From df84d8509dee6183567d18ffb7d9c781c8840b3f Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Thu, 4 Jul 2024 10:30:35 +0100 Subject: [PATCH] Select: Properly show group separator for virtualized selects (#90005) * add group separator for virtualized selects * simplify --- .../src/components/Select/Select.story.tsx | 2 ++ .../src/components/Select/SelectMenu.tsx | 24 +++++++++++++++---- .../src/components/Select/getSelectStyles.ts | 3 +++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/grafana-ui/src/components/Select/Select.story.tsx b/packages/grafana-ui/src/components/Select/Select.story.tsx index c56102ca64e..ac0a7277c40 100644 --- a/packages/grafana-ui/src/components/Select/Select.story.tsx +++ b/packages/grafana-ui/src/components/Select/Select.story.tsx @@ -31,6 +31,7 @@ const manyGroupedOptions = [ return { label: person, value: person }; }), }, + { label: 'Bar', value: '3' }, ]; const meta: Meta = { @@ -250,6 +251,7 @@ export const MultiSelectWithOptionGroups: StoryFn = (args) => { { label: 'Eagle', value: '13' }, ], }, + { label: 'Bar', value: '3' }, ]} value={value} onChange={(v) => { diff --git a/packages/grafana-ui/src/components/Select/SelectMenu.tsx b/packages/grafana-ui/src/components/Select/SelectMenu.tsx index c8a6aff1712..4513229a4b9 100644 --- a/packages/grafana-ui/src/components/Select/SelectMenu.tsx +++ b/packages/grafana-ui/src/components/Select/SelectMenu.tsx @@ -3,7 +3,7 @@ import { max } from 'lodash'; import { RefCallback, useEffect, useMemo, useRef } from 'react'; import * as React from 'react'; import { MenuListProps } from 'react-select'; -import { FixedSizeList as List } from 'react-window'; +import { VariableSizeList as List } from 'react-window'; import { SelectableValue, toIconName } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; @@ -36,8 +36,10 @@ export const SelectMenu = ({ children, maxHeight, innerRef, innerProps }: React. SelectMenu.displayName = 'SelectMenu'; const VIRTUAL_LIST_ITEM_HEIGHT = 37; +const VIRTUAL_DIVIDER_HEIGHT = 1; const VIRTUAL_LIST_WIDTH_ESTIMATE_MULTIPLIER = 8; const VIRTUAL_LIST_PADDING = 8; +const DIVIDER_KEY = 'divider'; // Some list items have icons or checkboxes so we need some extra width const VIRTUAL_LIST_WIDTH_EXTRA = 36; @@ -81,13 +83,17 @@ export const VirtualizedSelectMenu = ({ // flatten the children to account for any categories // these will have array children that are the individual options - const flattenedChildren = children.flatMap((child) => { + const flattenedChildren = children.flatMap((child, index) => { if (hasArrayChildren(child)) { // need to remove the children from the category else they end up in the DOM twice const childWithoutChildren = React.cloneElement(child, { children: null, }); - return [childWithoutChildren, ...child.props.children]; + return [ + childWithoutChildren, + ...child.props.children, +
, + ]; } return [child]; }); @@ -97,6 +103,15 @@ export const VirtualizedSelectMenu = ({ longestOption * VIRTUAL_LIST_WIDTH_ESTIMATE_MULTIPLIER + VIRTUAL_LIST_PADDING * 2 + VIRTUAL_LIST_WIDTH_EXTRA; const heightEstimate = Math.min(flattenedChildren.length * VIRTUAL_LIST_ITEM_HEIGHT, maxHeight); + const getRowHeight = (rowIndex: number) => { + const row = flattenedChildren[rowIndex]; + if (row.key.includes(DIVIDER_KEY)) { + return VIRTUAL_DIVIDER_HEIGHT; + } + + return VIRTUAL_LIST_ITEM_HEIGHT; + }; + return ( {({ index, style }) =>
{flattenedChildren[index]}
}
diff --git a/packages/grafana-ui/src/components/Select/getSelectStyles.ts b/packages/grafana-ui/src/components/Select/getSelectStyles.ts index a75b79417a3..7ba10c5ea45 100644 --- a/packages/grafana-ui/src/components/Select/getSelectStyles.ts +++ b/packages/grafana-ui/src/components/Select/getSelectStyles.ts @@ -163,5 +163,8 @@ export const getSelectStyles = stylesFactory((theme: GrafanaTheme2) => { borderBottom: `1px solid ${theme.colors.border.weak}`, }, }), + virtualizedSeparator: css({ + borderTop: `1px solid ${theme.colors.border.weak}`, + }), }; });