mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-07-10 14:52:49 +02:00
Better Dropdown size calculation for scrolling when not enough room
This commit is contained in:
@@ -229,17 +229,8 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
defaultSelectedIndex ?? null,
|
defaultSelectedIndex ?? null,
|
||||||
[defaultSelectedIndex],
|
[defaultSelectedIndex],
|
||||||
);
|
);
|
||||||
const [menuStyles, setMenuStyles] = useState<CSSProperties>({});
|
|
||||||
const [filter, setFilter] = useState<string>('');
|
const [filter, setFilter] = useState<string>('');
|
||||||
|
|
||||||
// Calculate the max height so we can scroll
|
|
||||||
const initMenu = useCallback((el: HTMLDivElement | null) => {
|
|
||||||
if (el === null) return {};
|
|
||||||
const windowBox = document.documentElement.getBoundingClientRect();
|
|
||||||
const menuBox = el.getBoundingClientRect();
|
|
||||||
setMenuStyles({ maxHeight: windowBox.height - menuBox.top - 5 });
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
onClose();
|
onClose();
|
||||||
setSelectedIndex(null);
|
setSelectedIndex(null);
|
||||||
@@ -355,11 +346,12 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
[handleClose, handleNext, handlePrev, handleSelect, items, selectedIndex],
|
[handleClose, handleNext, handlePrev, handleSelect, items, selectedIndex],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { containerStyles, triangleStyles } = useMemo<{
|
const styles = useMemo<{
|
||||||
containerStyles: CSSProperties;
|
container: CSSProperties;
|
||||||
triangleStyles: CSSProperties | null;
|
menu: CSSProperties;
|
||||||
|
triangle: CSSProperties;
|
||||||
}>(() => {
|
}>(() => {
|
||||||
if (triggerShape == null) return { containerStyles: {}, triangleStyles: null };
|
if (triggerShape == null) return { container: {}, triangle: {}, menu: {} };
|
||||||
|
|
||||||
const menuMarginY = 5;
|
const menuMarginY = 5;
|
||||||
const docRect = document.documentElement.getBoundingClientRect();
|
const docRect = document.documentElement.getBoundingClientRect();
|
||||||
@@ -371,7 +363,8 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
const onRight = horizontalSpaceRemaining < 200;
|
const onRight = horizontalSpaceRemaining < 200;
|
||||||
const upsideDown = heightBelow < heightAbove && heightBelow < items.length * 25 + 20 + 200;
|
const upsideDown = heightBelow < heightAbove && heightBelow < items.length * 25 + 20 + 200;
|
||||||
const triggerWidth = triggerShape.right - triggerShape.left;
|
const triggerWidth = triggerShape.right - triggerShape.left;
|
||||||
const containerStyles = {
|
return {
|
||||||
|
container: {
|
||||||
top: !upsideDown ? top + menuMarginY : undefined,
|
top: !upsideDown ? top + menuMarginY : undefined,
|
||||||
bottom: upsideDown
|
bottom: upsideDown
|
||||||
? docRect.height - top - (triggerShape.top - triggerShape.bottom) + menuMarginY
|
? docRect.height - top - (triggerShape.top - triggerShape.bottom) + menuMarginY
|
||||||
@@ -380,8 +373,8 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
left: !onRight ? triggerShape.left : undefined,
|
left: !onRight ? triggerShape.left : undefined,
|
||||||
minWidth: fullWidth ? triggerWidth : undefined,
|
minWidth: fullWidth ? triggerWidth : undefined,
|
||||||
maxWidth: '40rem',
|
maxWidth: '40rem',
|
||||||
};
|
},
|
||||||
const triangleStyles: CSSProperties = {
|
triangle: {
|
||||||
width: '0.4rem',
|
width: '0.4rem',
|
||||||
height: '0.4rem',
|
height: '0.4rem',
|
||||||
...(onRight
|
...(onRight
|
||||||
@@ -390,8 +383,11 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
...(upsideDown
|
...(upsideDown
|
||||||
? { bottom: '-0.2rem', rotate: '225deg' }
|
? { bottom: '-0.2rem', rotate: '225deg' }
|
||||||
: { top: '-0.2rem', rotate: '45deg' }),
|
: { top: '-0.2rem', rotate: '45deg' }),
|
||||||
|
},
|
||||||
|
menu: {
|
||||||
|
maxHeight: `${(upsideDown ? heightAbove : heightBelow) - 15}px`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return { containerStyles, triangleStyles };
|
|
||||||
}, [fullWidth, items.length, triggerShape]);
|
}, [fullWidth, items.length, triggerShape]);
|
||||||
|
|
||||||
const filteredItems = useMemo(
|
const filteredItems = useMemo(
|
||||||
@@ -435,20 +431,18 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
role="menu"
|
role="menu"
|
||||||
aria-orientation="vertical"
|
aria-orientation="vertical"
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
style={containerStyles}
|
style={styles.container}
|
||||||
className={classNames(className, 'outline-none my-1 pointer-events-auto fixed z-50')}
|
className={classNames(className, 'outline-none my-1 pointer-events-auto fixed z-50')}
|
||||||
>
|
>
|
||||||
{triangleStyles && showTriangle && (
|
{showTriangle && (
|
||||||
<span
|
<span
|
||||||
aria-hidden
|
aria-hidden
|
||||||
style={triangleStyles}
|
style={styles.triangle}
|
||||||
className="bg-surface absolute border-border-subtle border-t border-l"
|
className="bg-surface absolute border-border-subtle border-t border-l"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{containerStyles && (
|
|
||||||
<VStack
|
<VStack
|
||||||
ref={initMenu}
|
style={styles.menu}
|
||||||
style={menuStyles}
|
|
||||||
className={classNames(
|
className={classNames(
|
||||||
className,
|
className,
|
||||||
'h-auto bg-surface rounded-md shadow-lg py-1.5 border',
|
'h-auto bg-surface rounded-md shadow-lg py-1.5 border',
|
||||||
@@ -489,7 +483,6 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</VStack>
|
</VStack>
|
||||||
)}
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|||||||
Reference in New Issue
Block a user