UNPKG

@hitachivantara/uikit-react-core

Version:
203 lines (202 loc) 7.17 kB
import { HvTypography } from "../Typography/Typography.js"; import { HvListContainer } from "../ListContainer/ListContainer.js"; import { HvListItem } from "../ListContainer/ListItem/ListItem.js"; import { HvIcon } from "../icons.js"; import { HvCheckBox } from "../CheckBox/CheckBox.js"; import { HvOverflowTooltip } from "../OverflowTooltip/OverflowTooltip.js"; import { HvRadio } from "../Radio/Radio.js"; import { CounterLabel } from "../utils/CounterLabel.js"; import { useClasses } from "./List.styles.js"; import { useSelectableList } from "./useSelectableList.js"; import { parseList } from "./utils.js"; import { useDefaultProps } from "@hitachivantara/uikit-react-utils"; import { forwardRef, isValidElement, useEffect, useMemo, useRef } from "react"; import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime"; import { FixedSizeList } from "react-window"; //#region src/List/List.tsx var DEFAULT_LABELS = { /** The label used in the middle of the multi-selection count. */ selectionConjunction: "/" }; /** * Component used to show a set of related data to the user. * @deprecated use `HvListContainer` + `HvListItem` instead */ var HvList = (props) => { const { id, classes: classesProp, className, multiSelect = false, showSelectAll = false, labels = DEFAULT_LABELS, useSelector = false, selectable = true, singleSelectionToggle = true, condensed = false, onChange, onClick, values: valuesProp = [], height, virtualized = false, ...others } = useDefaultProps("HvList", props); const { classes, cx } = useClasses(classesProp); const [list, setList, selection] = useSelectableList(valuesProp); const listRef = useRef(null); useEffect(() => { setList(parseList(void 0, { multiSelect, selectable, singleSelectionToggle }, void 0, valuesProp)); }, [ valuesProp, multiSelect, selectable, singleSelectionToggle, setList ]); const [role, itemRole] = useMemo(() => { if (selectable && useSelector) return ["list", "listitem"]; if (selectable) return ["listbox", "option"]; return ["menu", "menuitem"]; }, [selectable, useSelector]); const handleSelect = (evt, item) => { if (!item.path) evt.preventDefault(); if (item.disabled) return; const parsedList = parseList(item, { multiSelect, selectable, singleSelectionToggle }, void 0, list); setList(parsedList); onClick?.(evt, item); onChange?.(parsedList); }; const handleSelectAll = () => { const parsedList = parseList(void 0, { multiSelect, selectable, singleSelectionToggle }, !list.some((elem) => elem.selected || elem.disabled), list); setList(parsedList); onChange?.(parsedList); }; const renderLeftIcon = (item) => { return isValidElement(item.icon) ? item.icon : typeof item.icon === "function" ? item.icon?.({ isSelected: item.selected, isDisabled: item.disabled }) : null; }; const renderSelectAll = () => { const anySelected = !!selection?.length; const allSelected = selection.length === list.length; return /* @__PURE__ */ jsx(HvCheckBox, { label: /* @__PURE__ */ jsx(CounterLabel, { selected: selection.length, total: list.length, conjunctionLabel: labels.selectionConjunction }), onChange: handleSelectAll, className: classes.selectAllSelector, indeterminate: anySelected && !allSelected, checked: allSelected }); }; const renderItemText = (item) => { return !multiSelect && item.path ? /* @__PURE__ */ jsx(HvTypography, { link: true, component: "a", href: item.path, className: classes.link, children: /* @__PURE__ */ jsx(HvOverflowTooltip, { data: item.label }) }) : /* @__PURE__ */ jsx(HvOverflowTooltip, { data: item.label }); }; const renderSelectItem = (item) => { if (!useSelector) return renderItemText(item); return /* @__PURE__ */ jsx(multiSelect ? HvCheckBox : HvRadio, { label: /* @__PURE__ */ jsx(HvOverflowTooltip, { data: item.label }), checked: item.selected || false, disabled: item.disabled, onChange: multiSelect ? (evt) => handleSelect(evt, item) : void 0, classes: { root: classes.selectorRoot, container: classes.selectorContainer, label: classes.truncate } }); }; const renderListItem = (item, i, otherProps = {}) => { const selected = item.selected || false; const startAdornment = !useSelector && item.icon ? renderLeftIcon(item) : null; return /* @__PURE__ */ jsx(HvListItem, { role: itemRole, disabled: item.disabled || void 0, className: classes.item, classes: { selected: cx({ [classes.itemSelector]: useSelector || multiSelect }) }, selected: multiSelect || selected ? selected : void 0, onClick: (evt) => handleSelect(evt, item), startAdornment, endAdornment: item.showNavIcon && /* @__PURE__ */ jsx(HvIcon, { name: "CaretRight", className: classes.box, size: "xs" }), separator: item.separator, ...otherProps, children: renderSelectItem(item) }, i); }; const filteredList = list.filter((it) => !it.isHidden); const anySelected = list.map((item) => item.selected && !item.disabled).reduce((result, selected) => result || selected, false); const selectedItemIndex = list.findIndex((item) => item.selected); useEffect(() => { if (selectedItemIndex >= 0 && listRef.current !== null) listRef.current.scrollToItem(selectedItemIndex); }, [listRef, selectedItemIndex]); const renderVirtualizedListItem = ({ index, style }) => { const item = filteredList[index]; const tabIndex = item.tabIndex || !anySelected && index === 0 || item.selected && !item.disabled ? 0 : -1; return renderListItem(item, index, { style: { ...style, top: `${Number.parseFloat(style.top) + 5}px`, left: `${Number.parseFloat(style.left) + 5}px`, width: `calc(${Number.parseFloat(style.width)}% - 10px)` }, tabIndex, interactive: true, condensed, disableGutters: useSelector }); }; const ariaMultiSelectable = role === "listbox" && multiSelect || void 0; const ListContainer = useMemo(() => { return forwardRef(({ ...rest }, ref) => /* @__PURE__ */ jsx(HvListContainer, { id, className: cx(classes.root, className), role, interactive: true, condensed, disableGutters: useSelector, "aria-multiselectable": ariaMultiSelectable, ref, ...rest })); }, [ cx, id, useSelector, className, classes.root, role, condensed, ariaMultiSelectable ]); if (filteredList.length === 0) return null; return /* @__PURE__ */ jsxs(Fragment$1, { children: [multiSelect && useSelector && showSelectAll && renderSelectAll(), !virtualized ? /* @__PURE__ */ jsx(HvListContainer, { id, className: cx(classes.root, className), role, interactive: true, condensed, disableGutters: useSelector, "aria-multiselectable": ariaMultiSelectable, ...others, children: filteredList.map((item, i) => renderListItem(item, i)) }) : /* @__PURE__ */ jsx(FixedSizeList, { ref: listRef, className: classes.virtualizedRoot, height: (height || 0) + 5, width: "100%", itemCount: filteredList.length, itemSize: condensed ? 32 : 40, innerElementType: ListContainer, ...others, children: renderVirtualizedListItem })] }); }; //#endregion export { HvList };