@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
JavaScript
// 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