🎨 style: adjust the popover position based on the user screen
This commit is contained in:
parent
b7fe301c81
commit
c950bd8d93
@ -5,6 +5,8 @@ import React, {
|
||||
useMemo,
|
||||
useCallback,
|
||||
MouseEvent,
|
||||
useRef,
|
||||
useEffect,
|
||||
} from 'react';
|
||||
import { useMultipleSelection, useCombobox } from 'downshift';
|
||||
import { SelectTheme, selectTheme } from './Select.theme';
|
||||
@ -62,6 +64,34 @@ export const MultiSelect: React.FC<MultiSelectProps> = ({
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [selectedItem, setSelectedItem] = useState<DropdownItem | null>(null);
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
const [dropdownPosition, setDropdownPosition] = useState<'top' | 'bottom'>(
|
||||
'bottom',
|
||||
);
|
||||
const popoverRef = useRef(null); // Ref for the popover
|
||||
const inputWrapperRef = useRef(null); // Ref for the input wrapper
|
||||
|
||||
// Calculate and update popover position
|
||||
useEffect(() => {
|
||||
if (dropdownOpen && popoverRef.current && inputWrapperRef.current) {
|
||||
const popover = popoverRef.current;
|
||||
// @ts-expect-error – we know it's not null
|
||||
const input = inputWrapperRef.current.getBoundingClientRect();
|
||||
const spaceBelow = window.innerHeight - input.bottom;
|
||||
const spaceAbove = input.top;
|
||||
// @ts-expect-error – we know it's not null
|
||||
const popoverHeight = popover.offsetHeight;
|
||||
|
||||
// Determine if there's enough space below
|
||||
if (spaceBelow >= popoverHeight) {
|
||||
setDropdownPosition('bottom');
|
||||
} else if (spaceAbove >= popoverHeight) {
|
||||
setDropdownPosition('top');
|
||||
} else {
|
||||
// Default to bottom if neither has enough space, but you could also set logic to choose the side with more space
|
||||
setDropdownPosition('bottom');
|
||||
}
|
||||
}
|
||||
}, [dropdownOpen]); // Re-calculate whenever the dropdown is opened
|
||||
|
||||
const handleSelectedItemChange = (selectedItem: DropdownItem | null) => {
|
||||
setSelectedItem(selectedItem);
|
||||
@ -211,6 +241,7 @@ export const MultiSelect: React.FC<MultiSelectProps> = ({
|
||||
<div className={theme.container()}>
|
||||
{renderLabels}
|
||||
<div
|
||||
ref={inputWrapperRef}
|
||||
className={theme.inputWrapper({
|
||||
hasValue: multiple && selectedItems.length > 0,
|
||||
})}
|
||||
@ -250,7 +281,15 @@ export const MultiSelect: React.FC<MultiSelectProps> = ({
|
||||
{renderRightIcon}
|
||||
</div>
|
||||
{renderHelperText}
|
||||
<ul {...getMenuProps()} className={theme.popover({ isOpen })}>
|
||||
<ul
|
||||
{...getMenuProps()}
|
||||
id="popover"
|
||||
ref={popoverRef}
|
||||
className={cn(theme.popover({ isOpen }), {
|
||||
'top-1/4': dropdownPosition === 'bottom',
|
||||
'bottom-[95%]': dropdownPosition === 'top',
|
||||
})}
|
||||
>
|
||||
{isOpen && filteredItems.length !== 0 ? (
|
||||
filteredItems.map((item, index) => (
|
||||
<li
|
||||
|
Loading…
Reference in New Issue
Block a user