UNPKG

@momentum-ui/react-collaboration

Version:

Cisco Momentum UI Framework for React Collaboration Applications

127 lines 5.82 kB
import { useMemo, useState } from 'react'; import { usePrevious } from './usePrevious'; var getSelection = function (mode, selectedByDefault) { if (selectedByDefault === void 0) { selectedByDefault = []; } if (mode === 'none') { if (selectedByDefault && selectedByDefault.length > 0) { console.warn('"None" selection mode does not support any selection, selected items will be ignored'); } return []; } if (mode === 'single' && selectedByDefault.length > 1) { console.warn('"Single" selection mode does not support multiple items, only the first item will be selected'); return [selectedByDefault[0]]; } return selectedByDefault; }; /** * Hook to manage selected items * * This hook support controlled and uncontrolled selection, and it works the same way as input components in React. * * Uncontrolled is the default state, when `selectedItems` is `undefined`. * In this case, the hook will manage the selection state internally. * * @example * ```tsx * const {selectedItems, isSelected, toggle, update, clear } = useItemSelected({ * selectionMode: 'multiple' * }) * ``` * * Controlled selection is when `selectedItems` is provided, and it isn't `undefined`. * This way the consumer of the hook can change the selection from outside. * Order to update this outside state, the `onSelectionChange` callback should be passed as well * * @example * ```tsx * const [selection, setSelection] = useState<Array<string>>([]); * * const {isSelected, toggle, update, clear } = useItemSelected({ * selectionMode: 'multiple', * selectedItems: selection, * onSelectionChange: setSelection, * isRequired: true, * }) * ``` * * @param param Hook options */ export var useItemSelected = function (_a) { var selectionMode = _a.selectionMode, selectedByDefault = _a.selectedByDefault, onSelectionChange = _a.onSelectionChange, _b = _a.selectedItems, selectedItemsFromProps = _b === void 0 ? undefined : _b, _c = _a.isRequired, isRequired = _c === void 0 ? false : _c; var isControlled = selectedItemsFromProps !== undefined; var prevIsControlled = usePrevious(isControlled); // Check if the selection mode is changed from controlled to uncontrolled // see "Controlling an input with a state variable" in rect docs // https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable if (prevIsControlled === true && prevIsControlled !== isControlled) { console.warn('A component is changing an uncontrolled input to be controlled.' + 'selectedItems should not alter between array and undefined value.'); } var _d = useState(new Set(getSelection(selectionMode, selectedByDefault))), internalSelectedItems = _d[0], setInternalSelectedItems = _d[1]; var selectedItems = useMemo(function () { return isControlled ? new Set(getSelection(selectionMode, selectedItemsFromProps)) : internalSelectedItems; }, // eslint-disable-next-line react-hooks/exhaustive-deps [isControlled, selectedItemsFromProps, internalSelectedItems]); return useMemo(function () { return ({ selectionMode: selectionMode, selectedItems: Array.from(selectedItems), isSelected: function (itemId) { return selectedItems.has(itemId); }, toggle: function (itemId, value) { if (selectionMode === 'none') return; var toggleInternal = function (prev) { var isSelected = prev.has(itemId); var select = value !== undefined ? value : !isSelected; var needToRemove = !select && isSelected && (!isRequired || prev.size > 1 || !isSelected); var needToAdd = select && !isSelected; var result = prev; if (selectionMode === 'single' && needToAdd) { result = new Set([itemId]); } else if (selectionMode === 'multiple' && needToAdd) { result = new Set(prev); result.add(itemId); } else if (needToRemove) { result = new Set(Array.from(prev).filter(function (i) { return i !== itemId; })); } if (result !== prev) { onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(Array.from(result)); } return result; }; if (!isControlled) { setInternalSelectedItems(toggleInternal); } else { toggleInternal(selectedItems); } }, update: function (allSelectedItems) { if (selectionMode !== 'none' && (allSelectedItems.length !== selectedItems.size || !allSelectedItems.every(function (i) { return selectedItems.has(i); }))) { var newSelection = getSelection(selectionMode, allSelectedItems); onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(newSelection); if (!isControlled) { setInternalSelectedItems(new Set(newSelection)); } } }, clear: function () { if (selectionMode !== 'none' && selectedItems.size > 0) { onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange([]); if (!isControlled) { setInternalSelectedItems(new Set()); } } }, }); }, // eslint-disable-next-line react-hooks/exhaustive-deps [selectedItems]); }; //# sourceMappingURL=useItemSelected.js.map