UNPKG

@grafana/ui

Version:
139 lines (136 loc) 5.74 kB
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