From a279220d742416bf6617cb49162e36ae14d4f1bd Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:35:31 +0100 Subject: [PATCH] Combobox: Use `ScrollContainer` to show scroll indicators (#95962) Add CustomScrollbar --- .../components/Combobox/Combobox.story.tsx | 3 + .../src/components/Combobox/Combobox.tsx | 85 ++++++++++--------- .../components/Combobox/getComboboxStyles.ts | 1 - .../components/Combobox/useComboboxFloat.ts | 3 +- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx index 420a96c1ea9..1d73722378e 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx @@ -42,6 +42,9 @@ const meta: Meta = { { label: '1', value: 1 }, { label: '2', value: 2 }, { label: '3', value: 3 }, + { label: '4', value: 4 }, + { label: '5', value: 5 }, + { label: '6', value: 6 }, ], value: 'banana', }, diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.tsx index 933cee2d8c0..17e82c11e94 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.tsx @@ -10,6 +10,7 @@ import { Icon } from '../Icon/Icon'; import { AutoSizeInput } from '../Input/AutoSizeInput'; import { Input, Props as InputProps } from '../Input/Input'; import { Stack } from '../Layout/Stack/Stack'; +import { ScrollContainer } from '../ScrollContainer/ScrollContainer'; import { Text } from '../Text/Text'; import { getComboboxStyles } from './getComboboxStyles'; @@ -132,7 +133,7 @@ export const Combobox = ({ const virtualizerOptions = { count: items.length, - getScrollElement: () => floatingRef.current, + getScrollElement: () => scrollRef.current, estimateSize: () => OPTION_HEIGHT, overscan: 4, }; @@ -239,7 +240,7 @@ export const Combobox = ({ }, }); - const { inputRef, floatingRef, floatStyles } = useComboboxFloat(items, rowVirtualizer.range, isOpen); + const { inputRef, floatingRef, floatStyles, scrollRef } = useComboboxFloat(items, rowVirtualizer.range, isOpen); const onBlur = useCallback(() => { setInputValue(selectedItem?.label ?? value?.toString() ?? ''); @@ -311,46 +312,48 @@ export const Combobox = ({ 'aria-labelledby': ariaLabelledBy, })} > - {isOpen && !asyncError && ( -
    - {rowVirtualizer.getVirtualItems().map((virtualRow) => { - return ( -
  • -
    - - {items[virtualRow.index].label ?? items[virtualRow.index].value} - - {items[virtualRow.index].description && ( - {items[virtualRow.index].description} + + {isOpen && !asyncError && ( +
      + {rowVirtualizer.getVirtualItems().map((virtualRow) => { + return ( +
    • -
    • - ); - })} -
    - )} - {asyncError && ( - - - {t('combobox.async.error', 'An error occurred while loading options.')} - - )} + style={{ + height: virtualRow.size, + transform: `translateY(${virtualRow.start}px)`, + }} + {...getItemProps({ + item: items[virtualRow.index], + index: virtualRow.index, + })} + > +
    + + {items[virtualRow.index].label ?? items[virtualRow.index].value} + + {items[virtualRow.index].description && ( + {items[virtualRow.index].description} + )} +
    +
  • + ); + })} +
+ )} + {asyncError && ( + + + {t('combobox.async.error', 'An error occurred while loading options.')} + + )} + ); diff --git a/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts b/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts index 95ceef76a7e..a986fb67639 100644 --- a/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts +++ b/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts @@ -18,7 +18,6 @@ export const getComboboxStyles = (theme: GrafanaTheme2) => { background: theme.components.dropdown.background, boxShadow: theme.shadows.z3, zIndex: theme.zIndex.dropdown, - overflowY: 'auto', position: 'relative', }), menuUlContainer: css({ diff --git a/packages/grafana-ui/src/components/Combobox/useComboboxFloat.ts b/packages/grafana-ui/src/components/Combobox/useComboboxFloat.ts index 6b271d081ed..bedebb4b749 100644 --- a/packages/grafana-ui/src/components/Combobox/useComboboxFloat.ts +++ b/packages/grafana-ui/src/components/Combobox/useComboboxFloat.ts @@ -23,6 +23,7 @@ export const useComboboxFloat = ( ) => { const inputRef = useRef(null); const floatingRef = useRef(null); + const scrollRef = useRef(null); const [popoverMaxSize, setPopoverMaxSize] = useState<{ width: number; height: number } | undefined>(undefined); const scrollbarWidth = useMemo(() => getScrollbarWidth(), []); @@ -79,7 +80,7 @@ export const useComboboxFloat = ( maxHeight: popoverMaxSize?.height, }; - return { inputRef, floatingRef, floatStyles }; + return { inputRef, floatingRef, scrollRef, floatStyles }; }; // Creates a temporary div with a scrolling inner div to calculate the width of the scrollbar