@hitachivantara/uikit-react-core
Version:
UI Kit Core React components.
203 lines (202 loc) • 7.17 kB
JavaScript
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 };