UNPKG

@awsui/components-react

Version:

On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en

143 lines • 7.4 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { useState } from 'react'; import { fireNonCancelableEvent } from '../../internal/events'; import { useUniqueId } from '../../internal/hooks/use-unique-id'; import { joinStrings } from '../../internal/utils/strings'; import { getTrackableValue } from '../utils'; import { ItemSet } from './utils'; export function useSelection(options) { const singleSelectionProps = useSingleSelection(options); const multiSelectionProps = useMultiSelection(options); return options.selectionType === 'single' ? singleSelectionProps : multiSelectionProps; } function useSingleSelection({ ariaLabels, isItemDisabled = () => false, onSelectionChange, selectedItems = [], selectionType, trackBy, }) { // The name assigned to all controls to combine them in a single group. const selectionControlName = useUniqueId(); if (selectionType !== 'single') { return { isItemSelected: () => false }; } // Selection state for individual items. const selectedSet = new ItemSet(trackBy, selectedItems.slice(0, 1)); const isItemSelected = selectedSet.has.bind(selectedSet); const handleToggleItem = (item) => { if (!isItemDisabled(item) && !isItemSelected(item)) { fireNonCancelableEvent(onSelectionChange, { selectedItems: [item] }); } }; return { isItemSelected, getItemSelectionProps: (item) => { var _a; return ({ name: selectionControlName, selectionType: 'single', disabled: isItemDisabled(item), checked: isItemSelected(item), onChange: () => handleToggleItem(item), ariaLabel: joinStrings(ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.selectionGroupLabel, (_a = ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.itemSelectionLabel) === null || _a === void 0 ? void 0 : _a.call(ariaLabels, { selectedItems }, item)), }); }, }; } function useMultiSelection({ ariaLabels, isItemDisabled = () => false, items, loading, onSelectionChange, selectedItems = [], selectionType, trackBy, }) { // The name assigned to all controls to combine them in a single group. const selectionControlName = useUniqueId(); const [shiftPressed, setShiftPressed] = useState(false); const [lastClickedItem, setLastClickedItem] = useState(null); if (selectionType !== 'multi') { return { isItemSelected: () => false }; } // Selection state for individual items. const selectedSet = new ItemSet(trackBy, selectedItems); const isItemSelected = selectedSet.has.bind(selectedSet); // Derived selection state for all-items checkbox. let allItemsDisabled = true; let allEnabledItemsSelected = true; for (const item of items) { allItemsDisabled = allItemsDisabled && isItemDisabled(item); allEnabledItemsSelected = allEnabledItemsSelected && (isItemSelected(item) || isItemDisabled(item)); } const allItemsCheckboxSelected = selectedItems.length > 0 && allEnabledItemsSelected; const allItemsCheckboxIndeterminate = selectedItems.length > 0 && !allEnabledItemsSelected; // Shift-selection helpers. const itemIndexesMap = new Map(); items.forEach((item, i) => itemIndexesMap.set(getTrackableValue(trackBy, item), i)); const getShiftSelectedItems = (item) => { const lastClickedItemIndex = lastClickedItem ? itemIndexesMap.get(getTrackableValue(trackBy, lastClickedItem)) : undefined; // We use lastClickedItemIndex to determine if filtering/sorting/pagination // made previously selected item invisible, therefore we reset state for shift-select. if (lastClickedItemIndex !== undefined) { const currentItemIndex = itemIndexesMap.get(getTrackableValue(trackBy, item)); const start = Math.min(currentItemIndex, lastClickedItemIndex); const end = Math.max(currentItemIndex, lastClickedItemIndex); return items.slice(start, end + 1); } return [item]; }; // Select items that are not already selected or disabled. const selectItems = (requestedItems) => { const newSelectedItems = [...selectedItems]; requestedItems.forEach(newItem => { if (!isItemSelected(newItem) && !isItemDisabled(newItem)) { newSelectedItems.push(newItem); } }); return newSelectedItems; }; // Unselect items unless they are disabled. const deselectItems = (requestedItems) => { const requestedItemsSet = new ItemSet(trackBy, requestedItems); const newSelectedItems = []; selectedItems.forEach(selectedItem => { const shouldUnselect = requestedItemsSet.has(selectedItem); if (!shouldUnselect || isItemDisabled(selectedItem)) { newSelectedItems.push(selectedItem); } }); return newSelectedItems; }; const handleToggleAll = () => { const newSelectedItems = allEnabledItemsSelected ? deselectItems(items) : selectItems(items); fireNonCancelableEvent(onSelectionChange, { selectedItems: newSelectedItems }); }; const handleToggleItem = (item) => { if (!isItemDisabled(item)) { const requestedItems = shiftPressed ? getShiftSelectedItems(item) : [item]; const selectedItems = isItemSelected(item) ? deselectItems(requestedItems) : selectItems(requestedItems); fireNonCancelableEvent(onSelectionChange, { selectedItems }); setLastClickedItem(item); } }; return { isItemSelected, getSelectAllProps: () => { var _a; return ({ name: selectionControlName, selectionType: 'multi', disabled: allItemsDisabled || !!loading, checked: allItemsCheckboxSelected, indeterminate: allItemsCheckboxIndeterminate, onChange: handleToggleAll, ariaLabel: joinStrings(ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.selectionGroupLabel, (_a = ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.allItemsSelectionLabel) === null || _a === void 0 ? void 0 : _a.call(ariaLabels, { selectedItems })), selectionGroupLabel: ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.selectionGroupLabel, }); }, getItemSelectionProps: (item) => { var _a; return ({ name: selectionControlName, selectionType: 'multi', disabled: isItemDisabled(item), checked: isItemSelected(item), onChange: () => handleToggleItem(item), onShiftToggle: (value) => setShiftPressed(value), ariaLabel: joinStrings(ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.selectionGroupLabel, (_a = ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.itemSelectionLabel) === null || _a === void 0 ? void 0 : _a.call(ariaLabels, { selectedItems }, item)), }); }, }; } //# sourceMappingURL=use-selection.js.map