diff --git a/components/Dropdown.tsx b/components/Dropdown.tsx index a3bcc7f..7ef8199 100644 --- a/components/Dropdown.tsx +++ b/components/Dropdown.tsx @@ -1,6 +1,7 @@ 'use client'; import { useRef, useEffect, useState } from 'react'; +import { createPortal } from 'react-dom'; type DropdownProps = { options: Array<{ id: number; name: string }>; @@ -20,12 +21,19 @@ export default function Dropdown({ onToggle, }: DropdownProps) { const dropdownRef = useRef(null); + const buttonRef = useRef(null); const [isOpen, setIsOpen] = useState(controlledIsOpen ?? false); + const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0 }); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { - if (!dropdownRef.current || !(event.target instanceof Node)) return; - if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + if (!dropdownRef.current || !buttonRef.current || !(event.target instanceof Node)) return; + if (!dropdownRef.current.contains(event.target) && !buttonRef.current.contains(event.target)) { if (onToggle) onToggle(false); else setIsOpen(false); } @@ -40,6 +48,17 @@ export default function Dropdown({ }; }, [controlledIsOpen, isOpen, onToggle]); + useEffect(() => { + if ((controlledIsOpen ?? isOpen) && buttonRef.current && mounted) { + const rect = buttonRef.current.getBoundingClientRect(); + setDropdownPosition({ + top: rect.bottom + window.scrollY + 4, + left: rect.left + window.scrollX, + width: rect.width + }); + } + }, [controlledIsOpen, isOpen, mounted]); + const activeOption = options.find((option) => option.id === activeId) || null; const handleSelect = (option: { id: number }) => { @@ -53,48 +72,65 @@ export default function Dropdown({ else setIsOpen((prev) => !prev); }; - return ( -
- - - {(controlledIsOpen ?? isOpen) && ( -
- {options.length === 0 ? ( -
- No teams available -
- ) : ( - options.map((option) => ( -
handleSelect(option)} - className={`dropdown-item ${activeOption?.id === option.id ? 'active' : ''}`} - > - {option.name} -
- )) - )} + const dropdownMenu = (controlledIsOpen ?? isOpen) && mounted ? ( +
+ {options.length === 0 ? ( +
+ No teams available
+ ) : ( + options.map((option) => ( +
handleSelect(option)} + className={`dropdown-item ${activeOption?.id === option.id ? 'active' : ''}`} + > + {option.name} +
+ )) )}
+ ) : null; + + return ( + <> +
+ +
+ + {mounted && typeof document !== 'undefined' && dropdownMenu ? + createPortal(dropdownMenu, document.body) : null + } + ); } \ No newline at end of file