Skip to content

Commit

Permalink
move to utils
Browse files Browse the repository at this point in the history
  • Loading branch information
pablonyx committed Nov 27, 2024
1 parent b0102e5 commit a9fc89e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 33 deletions.
35 changes: 2 additions & 33 deletions web/src/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ChevronDownIcon } from "./icons/icons";
import { FiCheck, FiChevronDown } from "react-icons/fi";
import { Popover } from "./popover/Popover";
import { createPortal } from "react-dom";
import { useDropdownPosition } from "@/lib/dropdown";

export interface Option<T> {
name: string;
Expand Down Expand Up @@ -91,39 +92,7 @@ export function SearchMultiSelectDropdown({
};
}, []);

// Improved positioning logic
const updateMenuPosition = useCallback(() => {
if (isOpen && dropdownRef.current && dropdownMenuRef.current) {
const rect = dropdownRef.current.getBoundingClientRect();
const menuRect = dropdownMenuRef.current.getBoundingClientRect();
const viewportHeight = window.innerHeight;

let top = rect.bottom + window.scrollY;

// Check if the menu would go off the bottom of the viewport
if (top + menuRect.height > viewportHeight) {
// Position the menu above the input if it would go off the bottom
top = rect.top + window.scrollY - menuRect.height;
}

dropdownMenuRef.current.style.position = "absolute";
dropdownMenuRef.current.style.top = `${top}px`;
dropdownMenuRef.current.style.left = `${rect.left + window.scrollX}px`;
dropdownMenuRef.current.style.width = `${rect.width}px`;
dropdownMenuRef.current.style.zIndex = "10000";
}
}, [isOpen]);

useEffect(() => {
updateMenuPosition();
window.addEventListener("resize", updateMenuPosition);
window.addEventListener("scroll", updateMenuPosition);

return () => {
window.removeEventListener("resize", updateMenuPosition);
window.removeEventListener("scroll", updateMenuPosition);
};
}, [isOpen, updateMenuPosition]);
useDropdownPosition({ isOpen, dropdownRef, dropdownMenuRef });

return (
<div className="relative text-left w-full" ref={dropdownRef}>
Expand Down
49 changes: 49 additions & 0 deletions web/src/lib/dropdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { RefObject, useCallback, useEffect } from "react";

interface DropdownPositionProps {
isOpen: boolean;
dropdownRef: RefObject<HTMLElement>;
dropdownMenuRef: RefObject<HTMLElement>;
}

// This hook manages the positioning of a dropdown menu relative to its trigger element.
// It ensures the menu is positioned correctly, adjusting for viewport boundaries and scroll position.
// Also adds event listeners for window resize and scroll to update the position dynamically.
export const useDropdownPosition = ({
isOpen,
dropdownRef,
dropdownMenuRef,
}: DropdownPositionProps) => {
const updateMenuPosition = useCallback(() => {
if (isOpen && dropdownRef.current && dropdownMenuRef.current) {
const rect = dropdownRef.current.getBoundingClientRect();
const menuRect = dropdownMenuRef.current.getBoundingClientRect();
const viewportHeight = window.innerHeight;

let top = rect.bottom + window.scrollY;

if (top + menuRect.height > viewportHeight) {
top = rect.top + window.scrollY - menuRect.height;
}

dropdownMenuRef.current.style.position = "absolute";
dropdownMenuRef.current.style.top = `${top}px`;
dropdownMenuRef.current.style.left = `${rect.left + window.scrollX}px`;
dropdownMenuRef.current.style.width = `${rect.width}px`;
dropdownMenuRef.current.style.zIndex = "10000";
}
}, [isOpen, dropdownRef, dropdownMenuRef]);

useEffect(() => {
updateMenuPosition();
window.addEventListener("resize", updateMenuPosition);
window.addEventListener("scroll", updateMenuPosition);

return () => {
window.removeEventListener("resize", updateMenuPosition);
window.removeEventListener("scroll", updateMenuPosition);
};
}, [isOpen, updateMenuPosition]);

return updateMenuPosition;
};

0 comments on commit a9fc89e

Please sign in to comment.