FrontPastel/node_modules/@mui/base/legacy/useList/listReducer.js

355 lines
13 KiB
JavaScript
Raw Normal View History

2024-04-17 13:55:11 +00:00
import _extends from "@babel/runtime/helpers/esm/extends";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import { ListActionTypes } from './listActions.types';
/**
* Looks up the next valid item to highlight within the list.
*
* @param currentIndex The index of the start of the search.
* @param lookupDirection Whether to look for the next or previous item.
* @param items The array of items to search.
* @param includeDisabledItems Whether to include disabled items in the search.
* @param isItemDisabled A function that determines whether an item is disabled.
* @param wrapAround Whether to wrap around the list when searching.
* @returns The index of the next valid item to highlight or -1 if no valid item is found.
*/
function findValidItemToHighlight(currentIndex, lookupDirection, items, includeDisabledItems, isItemDisabled, wrapAround) {
if (items.length === 0 || !includeDisabledItems && items.every(function (item, itemIndex) {
return isItemDisabled(item, itemIndex);
})) {
return -1;
}
var nextFocus = currentIndex;
for (;;) {
// No valid items found
if (!wrapAround && lookupDirection === 'next' && nextFocus === items.length || !wrapAround && lookupDirection === 'previous' && nextFocus === -1) {
return -1;
}
var nextFocusDisabled = includeDisabledItems ? false : isItemDisabled(items[nextFocus], nextFocus);
if (nextFocusDisabled) {
nextFocus += lookupDirection === 'next' ? 1 : -1;
if (wrapAround) {
nextFocus = (nextFocus + items.length) % items.length;
}
} else {
return nextFocus;
}
}
}
/**
* Gets the next item to highlight based on the current highlighted item and the search direction.
*
* @param previouslyHighlightedValue The item from which to start the search for the next candidate.
* @param offset The offset from the previously highlighted item to search for the next candidate or a special named value ('reset', 'start', 'end').
* @param context The list action context.
*
* @returns The next item to highlight or null if no item is valid.
*/
export function moveHighlight(previouslyHighlightedValue, offset, context) {
var _items$nextIndex;
var items = context.items,
isItemDisabled = context.isItemDisabled,
disableListWrap = context.disableListWrap,
disabledItemsFocusable = context.disabledItemsFocusable,
itemComparer = context.itemComparer,
focusManagement = context.focusManagement; // TODO: make this configurable
// The always should be an item highlighted when focus is managed by the DOM
// so that it's accessible by the `tab` key.
var defaultHighlightedIndex = focusManagement === 'DOM' ? 0 : -1;
var maxIndex = items.length - 1;
var previouslyHighlightedIndex = previouslyHighlightedValue == null ? -1 : items.findIndex(function (item) {
return itemComparer(item, previouslyHighlightedValue);
});
var nextIndexCandidate;
var lookupDirection;
var wrapAround = !disableListWrap;
switch (offset) {
case 'reset':
if (defaultHighlightedIndex === -1) {
return null;
}
nextIndexCandidate = 0;
lookupDirection = 'next';
wrapAround = false;
break;
case 'start':
nextIndexCandidate = 0;
lookupDirection = 'next';
wrapAround = false;
break;
case 'end':
nextIndexCandidate = maxIndex;
lookupDirection = 'previous';
wrapAround = false;
break;
default:
{
var newIndex = previouslyHighlightedIndex + offset;
if (newIndex < 0) {
if (!wrapAround && previouslyHighlightedIndex !== -1 || Math.abs(offset) > 1) {
nextIndexCandidate = 0;
lookupDirection = 'next';
} else {
nextIndexCandidate = maxIndex;
lookupDirection = 'previous';
}
} else if (newIndex > maxIndex) {
if (!wrapAround || Math.abs(offset) > 1) {
nextIndexCandidate = maxIndex;
lookupDirection = 'previous';
} else {
nextIndexCandidate = 0;
lookupDirection = 'next';
}
} else {
nextIndexCandidate = newIndex;
lookupDirection = offset >= 0 ? 'next' : 'previous';
}
}
}
var nextIndex = findValidItemToHighlight(nextIndexCandidate, lookupDirection, items, disabledItemsFocusable, isItemDisabled, wrapAround);
// If there are no valid items to highlight, return the previously highlighted item (if it's still valid).
if (nextIndex === -1 && previouslyHighlightedValue !== null && !isItemDisabled(previouslyHighlightedValue, previouslyHighlightedIndex)) {
return previouslyHighlightedValue;
}
return (_items$nextIndex = items[nextIndex]) != null ? _items$nextIndex : null;
}
/**
* Toggles the selection of an item.
*
* @param item Item to toggle.
* @param selectedValues Already selected items.
* @param selectionMode The number of items that can be simultanously selected.
* @param itemComparer A custom item comparer function.
*
* @returns The new array of selected items.
*/
export function toggleSelection(item, selectedValues, selectionMode, itemComparer) {
if (selectionMode === 'none') {
return [];
}
if (selectionMode === 'single') {
// if the item to select has already been selected, return the original array
if (itemComparer(selectedValues[0], item)) {
return selectedValues;
}
return [item];
}
// The toggled item is selected; remove it from the selection.
if (selectedValues.some(function (sv) {
return itemComparer(sv, item);
})) {
return selectedValues.filter(function (sv) {
return !itemComparer(sv, item);
});
}
// The toggled item is not selected - add it to the selection.
return [].concat(_toConsumableArray(selectedValues), [item]);
}
/**
* Handles item selection in a list.
*
* @param item - The item to be selected.
* @param state - The current state of the list.
* @param context - The context of the list action.
* @returns The new state of the list after the item has been selected, or the original state if the item is disabled.
*/
export function handleItemSelection(item, state, context) {
var itemComparer = context.itemComparer,
isItemDisabled = context.isItemDisabled,
selectionMode = context.selectionMode,
items = context.items;
var selectedValues = state.selectedValues;
var itemIndex = items.findIndex(function (i) {
return itemComparer(item, i);
});
if (isItemDisabled(item, itemIndex)) {
return state;
}
// if the item is already selected, remove it from the selection, otherwise add it
var newSelectedValues = toggleSelection(item, selectedValues, selectionMode, itemComparer);
return _extends({}, state, {
selectedValues: newSelectedValues,
highlightedValue: item
});
}
function handleKeyDown(key, state, context) {
var previouslySelectedValue = state.highlightedValue;
var orientation = context.orientation,
pageSize = context.pageSize;
switch (key) {
case 'Home':
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, 'start', context)
});
case 'End':
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, 'end', context)
});
case 'PageUp':
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, -pageSize, context)
});
case 'PageDown':
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, pageSize, context)
});
case 'ArrowUp':
if (orientation !== 'vertical') {
break;
}
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, -1, context)
});
case 'ArrowDown':
if (orientation !== 'vertical') {
break;
}
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, 1, context)
});
case 'ArrowLeft':
{
if (orientation === 'vertical') {
break;
}
var offset = orientation === 'horizontal-ltr' ? -1 : 1;
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, offset, context)
});
}
case 'ArrowRight':
{
if (orientation === 'vertical') {
break;
}
var _offset = orientation === 'horizontal-ltr' ? 1 : -1;
return _extends({}, state, {
highlightedValue: moveHighlight(previouslySelectedValue, _offset, context)
});
}
case 'Enter':
case ' ':
if (state.highlightedValue === null) {
return state;
}
return handleItemSelection(state.highlightedValue, state, context);
default:
break;
}
return state;
}
function handleBlur(state, context) {
if (context.focusManagement === 'DOM') {
return state;
}
return _extends({}, state, {
highlightedValue: null
});
}
function textCriteriaMatches(nextFocus, searchString, stringifyItem) {
var _stringifyItem;
var text = (_stringifyItem = stringifyItem(nextFocus)) == null ? void 0 : _stringifyItem.trim().toLowerCase();
if (!text || text.length === 0) {
// Make item not navigable if stringification fails or results in empty string.
return false;
}
return text.indexOf(searchString) === 0;
}
function handleTextNavigation(state, searchString, context) {
var items = context.items,
isItemDisabled = context.isItemDisabled,
disabledItemsFocusable = context.disabledItemsFocusable,
getItemAsString = context.getItemAsString;
var startWithCurrentItem = searchString.length > 1;
var nextItem = startWithCurrentItem ? state.highlightedValue : moveHighlight(state.highlightedValue, 1, context);
for (var _index = 0; _index < items.length; _index += 1) {
// Return un-mutated state if looped back to the currently highlighted value
if (!nextItem || !startWithCurrentItem && state.highlightedValue === nextItem) {
return state;
}
if (textCriteriaMatches(nextItem, searchString, getItemAsString) && (!isItemDisabled(nextItem, items.indexOf(nextItem)) || disabledItemsFocusable)) {
// The nextItem is the element to be highlighted
return _extends({}, state, {
highlightedValue: nextItem
});
}
// Move to the next element.
nextItem = moveHighlight(nextItem, 1, context);
}
// No item matches the text search criteria
return state;
}
function handleItemsChange(items, previousItems, state, context) {
var _state$selectedValues;
var itemComparer = context.itemComparer,
focusManagement = context.focusManagement;
var newHighlightedValue = null;
if (state.highlightedValue != null) {
var _items$find;
newHighlightedValue = (_items$find = items.find(function (item) {
return itemComparer(item, state.highlightedValue);
})) != null ? _items$find : null;
} else if (focusManagement === 'DOM' && previousItems.length === 0) {
newHighlightedValue = moveHighlight(null, 'reset', context);
}
// exclude selected values that are no longer in the items list
var selectedValues = (_state$selectedValues = state.selectedValues) != null ? _state$selectedValues : [];
var newSelectedValues = selectedValues.filter(function (selectedValue) {
return items.some(function (item) {
return itemComparer(item, selectedValue);
});
});
return _extends({}, state, {
highlightedValue: newHighlightedValue,
selectedValues: newSelectedValues
});
}
function handleResetHighlight(state, context) {
return _extends({}, state, {
highlightedValue: moveHighlight(null, 'reset', context)
});
}
function handleHighlightLast(state, context) {
return _extends({}, state, {
highlightedValue: moveHighlight(null, 'end', context)
});
}
function handleClearSelection(state, context) {
return _extends({}, state, {
selectedValues: [],
highlightedValue: moveHighlight(null, 'reset', context)
});
}
export function listReducer(state, action) {
var type = action.type,
context = action.context;
switch (type) {
case ListActionTypes.keyDown:
return handleKeyDown(action.key, state, context);
case ListActionTypes.itemClick:
return handleItemSelection(action.item, state, context);
case ListActionTypes.blur:
return handleBlur(state, context);
case ListActionTypes.textNavigation:
return handleTextNavigation(state, action.searchString, context);
case ListActionTypes.itemsChange:
return handleItemsChange(action.items, action.previousItems, state, context);
case ListActionTypes.resetHighlight:
return handleResetHighlight(state, context);
case ListActionTypes.highlightLast:
return handleHighlightLast(state, context);
case ListActionTypes.clearSelection:
return handleClearSelection(state, context);
default:
return state;
}
}