UNPKG

@grafana/ui

Version:
154 lines (151 loc) • 6.54 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 { Icon } from '../Icon/Icon.mjs'; import { Stack } from '../Layout/Stack/Stack.mjs'; import { ScrollContainer } from '../ScrollContainer/ScrollContainer.mjs'; import { AsyncError, NotFoundError, LoadingOptions } 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'; "use strict"; const VIRTUAL_OVERSCAN_ITEMS = 4; const ComboboxList = ({ options, highlightedIndex, selectedItems = [], scrollRef, getItemProps, enableAllOption, isMultiSelect = false, error = false, loading = false, noOptionsMessage }) => { 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, getItemKey: (index) => { var _a, _b; return (_b = (_a = options[index]) == null ? void 0 : _a.value) != null ? _b : index; }, overscan: VIRTUAL_OVERSCAN_ITEMS }); const isOptionSelected = useCallback( (item) => selectedItems.some((opt) => opt.value === item.value), [selectedItems] ); const allItemsSelected = enableAllOption && options.length > 1 && 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 && !item.infoOption && styles.optionFocused, item.infoOption && styles.optionInfo ), ...getItemProps({ item, index: virtualRow.index, id: itemId, "aria-describedby": groupHeaderId }), children: [ isMultiSelect && /* @__PURE__ */ jsx("div", { className: styles.optionAccessory, children: !item.infoOption && /* @__PURE__ */ jsx( Checkbox, { value: allItemsSelected || isOptionSelected(item), indeterminate: item.value === ALL_OPTION_VALUE && selectedItems.length > 0 && !allItemsSelected, "aria-labelledby": itemId, onClick: (e) => { e.stopPropagation(); }, "data-testid": `${itemId}-checkbox` }, itemId ) }), /* @__PURE__ */ jsxs("div", { className: styles.optionBody, children: [ /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", children: [ item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon }), /* @__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, {}), !loading && options.length === 0 && !error && /* @__PURE__ */ jsx(NotFoundError, { message: noOptionsMessage }), loading && options.length === 0 && /* @__PURE__ */ jsx(LoadingOptions, {}) ] }) ] }); }; export { ComboboxList }; //# sourceMappingURL=ComboboxList.mjs.map