@carbon/react
Version:
React components for the Carbon Design System
114 lines (112 loc) • 4.08 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const require_runtime = require("../_virtual/_rolldown/runtime.js");
let react = require("react");
react = require_runtime.__toESM(react);
require("react/jsx-runtime");
let react_fast_compare = require("react-fast-compare");
react_fast_compare = require_runtime.__toESM(react_fast_compare);
//#region src/internal/Selection.tsx
/**
* Copyright IBM Corp. 2016, 2025
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const callOnChangeHandler = ({ isControlled, isMounted, onChangeHandlerControlled, onChangeHandlerUncontrolled, selectedItems }) => {
if (isControlled) {
if (isMounted && onChangeHandlerControlled) setTimeout(() => {
onChangeHandlerControlled({ selectedItems });
}, 0);
} else onChangeHandlerUncontrolled(selectedItems);
};
const useSelection = ({ disabled, onChange, initialSelectedItems = [], selectedItems: controlledItems, selectAll = false, filteredItems = [] }) => {
const isMounted = (0, react.useRef)(false);
const savedOnChange = (0, react.useRef)(onChange);
const [uncontrolledItems, setUncontrolledItems] = (0, react.useState)(initialSelectedItems);
const isControlled = !!controlledItems;
const selectedItems = isControlled ? controlledItems : uncontrolledItems;
const onItemChange = (0, react.useCallback)((item) => {
if (disabled) return;
const allSelectableItems = filteredItems.filter((item) => !item?.disabled && !item?.isSelectAll);
const disabledItemCount = filteredItems.filter((item) => item?.disabled).length;
let newSelectedItems;
if (item?.isSelectAll && selectedItems.length > 0) newSelectedItems = [];
else if (item?.isSelectAll && selectedItems.length === 0) newSelectedItems = allSelectableItems;
else {
const selectedIndex = selectedItems.findLastIndex((selectedItem) => (0, react_fast_compare.default)(selectedItem, item));
if (selectedIndex === -1) {
newSelectedItems = selectedItems.concat(item);
if (selectAll && filteredItems.length - 1 === newSelectedItems.length + disabledItemCount) newSelectedItems = allSelectableItems;
} else {
newSelectedItems = removeAtIndex(selectedItems, selectedIndex);
newSelectedItems = newSelectedItems.filter((item) => !item?.isSelectAll);
}
}
callOnChangeHandler({
isControlled,
isMounted: isMounted.current,
onChangeHandlerControlled: savedOnChange.current,
onChangeHandlerUncontrolled: setUncontrolledItems,
selectedItems: newSelectedItems
});
}, [
disabled,
selectedItems,
filteredItems,
selectAll,
isControlled
]);
const clearSelection = (0, react.useCallback)(() => {
if (disabled) return;
callOnChangeHandler({
isControlled,
isMounted: isMounted.current,
onChangeHandlerControlled: savedOnChange.current,
onChangeHandlerUncontrolled: setUncontrolledItems,
selectedItems: []
});
}, [disabled, isControlled]);
const toggleAll = (0, react.useCallback)((items) => {
callOnChangeHandler({
isControlled,
isMounted: isMounted.current,
onChangeHandlerControlled: savedOnChange.current,
onChangeHandlerUncontrolled: setUncontrolledItems,
selectedItems: items
});
}, [isControlled]);
(0, react.useEffect)(() => {
savedOnChange.current = onChange;
}, [onChange]);
(0, react.useEffect)(() => {
if (isMounted.current && savedOnChange.current && !isControlled) savedOnChange.current({ selectedItems });
}, [isControlled, selectedItems]);
(0, react.useEffect)(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return {
clearSelection,
onItemChange,
toggleAll,
selectedItems
};
};
/**
* Generic utility for safely removing an element at a given index from an
* array.
*/
const removeAtIndex = (array, index) => {
const result = array.slice();
result.splice(index, 1);
return result;
};
//#endregion
exports.useSelection = useSelection;