@grafana/ui
Version:
Grafana Components Library
139 lines (136 loc) • 5.74 kB
JavaScript
import { jsxs, jsx } from 'react/jsx-runtime';
import { cx } from '@emotion/css';
import { useVirtualizer } from '@tanstack/react-virtual';
import { useCallback } from 'react';
import { useStyles2 } from '../../themes/ThemeContext.mjs';
import { Checkbox } from '../Forms/Checkbox.mjs';
import { ScrollContainer } from '../ScrollContainer/ScrollContainer.mjs';
import { AsyncError, NotFoundError } from './MessageRows.mjs';
import { getComboboxStyles, MENU_OPTION_HEIGHT, MENU_OPTION_HEIGHT_DESCRIPTION } from './getComboboxStyles.mjs';
import { ALL_OPTION_VALUE } from './types.mjs';
import { isNewGroup } from './utils.mjs';
const VIRTUAL_OVERSCAN_ITEMS = 4;
const ComboboxList = ({
options,
highlightedIndex,
selectedItems = [],
scrollRef,
getItemProps,
enableAllOption,
isMultiSelect = false,
error = false
}) => {
const styles = useStyles2(getComboboxStyles);
const estimateSize = useCallback(
(index) => {
const firstGroupItem = isNewGroup(options[index], index > 0 ? options[index - 1] : void 0);
const hasDescription = "description" in options[index];
const hasGroup = "group" in options[index];
let itemHeight = MENU_OPTION_HEIGHT;
if (hasDescription) {
itemHeight = MENU_OPTION_HEIGHT_DESCRIPTION;
}
if (firstGroupItem && hasGroup) {
itemHeight += MENU_OPTION_HEIGHT;
}
return itemHeight;
},
[options]
);
const rowVirtualizer = useVirtualizer({
count: options.length,
getScrollElement: () => scrollRef.current,
estimateSize,
overscan: VIRTUAL_OVERSCAN_ITEMS
});
const isOptionSelected = useCallback(
(item) => selectedItems.some((opt) => opt.value === item.value),
[selectedItems]
);
const allItemsSelected = enableAllOption && selectedItems.length === options.length - 1;
return /* @__PURE__ */ jsxs(ScrollContainer, { showScrollIndicators: true, maxHeight: "inherit", ref: scrollRef, padding: 0.5, children: [
/* @__PURE__ */ jsx("div", { style: { height: rowVirtualizer.getTotalSize() }, className: styles.menuUlContainer, children: rowVirtualizer.getVirtualItems().map((virtualRow, index, allVirtualRows) => {
var _a;
const item = options[virtualRow.index];
const startingNewGroup = isNewGroup(item, options[virtualRow.index - 1]);
const groupHeaderIndex = allVirtualRows.find((row) => {
const rowItem = options[row.index];
return rowItem.group === item.group;
});
const groupHeaderItem = groupHeaderIndex && options[groupHeaderIndex.index];
const itemId = `combobox-option-${item.value}`;
const groupHeaderId = groupHeaderItem ? `combobox-option-group-${groupHeaderItem.value}` : void 0;
return (
// Wrapping div should have no styling other than virtual list positioning.
// It's children (header and option) should appear as flat list items.
/* @__PURE__ */ jsxs(
"div",
{
className: styles.listItem,
style: {
height: virtualRow.size,
transform: `translateY(${virtualRow.start}px)`
},
children: [
startingNewGroup && /* @__PURE__ */ jsx(
"div",
{
role: "presentation",
"data-testid": "combobox-option-group",
id: groupHeaderId,
className: cx(
styles.optionGroupHeader,
item.group && styles.optionGroupLabel,
virtualRow.index === 0 && styles.optionFirstGroupHeader
),
children: item.group
}
),
/* @__PURE__ */ jsxs(
"div",
{
className: cx(
styles.option,
!isMultiSelect && isOptionSelected(item) && styles.optionSelected,
highlightedIndex === virtualRow.index && styles.optionFocused
),
...getItemProps({
item,
index: virtualRow.index,
id: itemId,
"aria-describedby": groupHeaderId
}),
children: [
isMultiSelect && /* @__PURE__ */ jsx("div", { className: styles.optionAccessory, children: /* @__PURE__ */ jsx(
Checkbox,
{
value: allItemsSelected || isOptionSelected(item),
indeterminate: item.value === ALL_OPTION_VALUE && selectedItems.length > 0 && !allItemsSelected,
"aria-labelledby": itemId,
onClick: (e) => {
e.stopPropagation();
}
},
itemId
) }),
/* @__PURE__ */ jsxs("div", { className: styles.optionBody, children: [
/* @__PURE__ */ jsx("div", { className: styles.optionLabel, children: (_a = item.label) != null ? _a : item.value }),
item.description && /* @__PURE__ */ jsx("div", { className: styles.optionDescription, children: item.description })
] })
]
}
)
]
},
item.value
)
);
}) }),
/* @__PURE__ */ jsxs("div", { "aria-live": "polite", children: [
error && /* @__PURE__ */ jsx(AsyncError, {}),
options.length === 0 && !error && /* @__PURE__ */ jsx(NotFoundError, {})
] })
] });
};
export { ComboboxList, VIRTUAL_OVERSCAN_ITEMS };
//# sourceMappingURL=ComboboxList.mjs.map