@momentum-ui/react-collaboration
Version:
Cisco Momentum UI Framework for React Collaboration Applications
127 lines • 5.82 kB
JavaScript
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