mirror of
https://github.com/grafana/grafana.git
synced 2024-12-27 09:21:35 -06:00
Combobox: Use ScrollContainer
to show scroll indicators (#95962)
Add CustomScrollbar
This commit is contained in:
parent
06bdfe8e96
commit
a279220d74
@ -42,6 +42,9 @@ const meta: Meta<PropsAndCustomArgs> = {
|
||||
{ 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',
|
||||
},
|
||||
|
@ -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 = <T extends string | number>({
|
||||
|
||||
const virtualizerOptions = {
|
||||
count: items.length,
|
||||
getScrollElement: () => floatingRef.current,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
estimateSize: () => OPTION_HEIGHT,
|
||||
overscan: 4,
|
||||
};
|
||||
@ -239,7 +240,7 @@ export const Combobox = <T extends string | number>({
|
||||
},
|
||||
});
|
||||
|
||||
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 = <T extends string | number>({
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
})}
|
||||
>
|
||||
{isOpen && !asyncError && (
|
||||
<ul style={{ height: rowVirtualizer.getTotalSize() }} className={styles.menuUlContainer}>
|
||||
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
||||
return (
|
||||
<li
|
||||
key={`${items[virtualRow.index].value}-${virtualRow.index}`}
|
||||
data-index={virtualRow.index}
|
||||
className={cx(
|
||||
styles.option,
|
||||
selectedItem && items[virtualRow.index].value === selectedItem.value && styles.optionSelected,
|
||||
highlightedIndex === virtualRow.index && styles.optionFocused
|
||||
)}
|
||||
style={{
|
||||
height: virtualRow.size,
|
||||
transform: `translateY(${virtualRow.start}px)`,
|
||||
}}
|
||||
{...getItemProps({
|
||||
item: items[virtualRow.index],
|
||||
index: virtualRow.index,
|
||||
})}
|
||||
>
|
||||
<div className={styles.optionBody}>
|
||||
<span className={styles.optionLabel}>
|
||||
{items[virtualRow.index].label ?? items[virtualRow.index].value}
|
||||
</span>
|
||||
{items[virtualRow.index].description && (
|
||||
<span className={styles.optionDescription}>{items[virtualRow.index].description}</span>
|
||||
<ScrollContainer showScrollIndicators maxHeight="inherit" ref={scrollRef}>
|
||||
{isOpen && !asyncError && (
|
||||
<ul style={{ height: rowVirtualizer.getTotalSize() }} className={styles.menuUlContainer}>
|
||||
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
||||
return (
|
||||
<li
|
||||
key={`${items[virtualRow.index].value}-${virtualRow.index}`}
|
||||
data-index={virtualRow.index}
|
||||
className={cx(
|
||||
styles.option,
|
||||
selectedItem && items[virtualRow.index].value === selectedItem.value && styles.optionSelected,
|
||||
highlightedIndex === virtualRow.index && styles.optionFocused
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
{asyncError && (
|
||||
<Stack justifyContent="center" alignItems="center" height={8}>
|
||||
<Icon name="exclamation-triangle" size="md" className={styles.warningIcon} />
|
||||
<Text color="secondary">{t('combobox.async.error', 'An error occurred while loading options.')}</Text>
|
||||
</Stack>
|
||||
)}
|
||||
style={{
|
||||
height: virtualRow.size,
|
||||
transform: `translateY(${virtualRow.start}px)`,
|
||||
}}
|
||||
{...getItemProps({
|
||||
item: items[virtualRow.index],
|
||||
index: virtualRow.index,
|
||||
})}
|
||||
>
|
||||
<div className={styles.optionBody}>
|
||||
<span className={styles.optionLabel}>
|
||||
{items[virtualRow.index].label ?? items[virtualRow.index].value}
|
||||
</span>
|
||||
{items[virtualRow.index].description && (
|
||||
<span className={styles.optionDescription}>{items[virtualRow.index].description}</span>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
{asyncError && (
|
||||
<Stack justifyContent="center" alignItems="center" height={8}>
|
||||
<Icon name="exclamation-triangle" size="md" className={styles.warningIcon} />
|
||||
<Text color="secondary">{t('combobox.async.error', 'An error occurred while loading options.')}</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</ScrollContainer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -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({
|
||||
|
@ -23,6 +23,7 @@ export const useComboboxFloat = (
|
||||
) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const floatingRef = useRef<HTMLDivElement>(null);
|
||||
const scrollRef = useRef<HTMLDivElement>(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
|
||||
|
Loading…
Reference in New Issue
Block a user