import React, { useState, useRef, useEffect } from 'react'; import { createPortal } from 'react-dom'; import { ChevronDownIcon } from '@heroicons/react/24/outline'; interface NumberSelectDropdownProps { value: number; onChange: (value: number) => void; min?: number; max?: number; placeholder?: string; disabled?: boolean; className?: string; } const NumberSelectDropdown: React.FC = ({ value, onChange, min = 1, max = 99, placeholder = 'Select number', disabled = false, className = '', }) => { const [isOpen, setIsOpen] = useState(false); const [position, setPosition] = useState({ top: 0, left: 0, width: 0, openUpward: false, }); const dropdownRef = useRef(null); const menuRef = useRef(null); // Generate options from min to max const options = Array.from({ length: max - min + 1 }, (_, i) => { const num = min + i; return { value: num, label: num.toString() }; }); const handleToggle = () => { if (disabled) return; if (!isOpen && dropdownRef.current) { const rect = dropdownRef.current.getBoundingClientRect(); const spaceBelow = window.innerHeight - rect.bottom; const spaceAbove = rect.top; const menuHeight = Math.min(options.length * 40 + 16, 200); // Max height with scroll const openUpward = spaceAbove > spaceBelow && spaceBelow < menuHeight; setPosition({ top: openUpward ? rect.top - menuHeight - 8 : rect.bottom + 8, left: rect.left, width: rect.width, openUpward, }); } setIsOpen(!isOpen); }; const handleClickOutside = (event: MouseEvent) => { if ( dropdownRef.current && !dropdownRef.current.contains(event.target as Node) && menuRef.current && !menuRef.current.contains(event.target as Node) ) { setIsOpen(false); } }; const handleSelect = (selectedValue: number) => { try { onChange(selectedValue); setIsOpen(false); } catch (error) { console.error('Error in number dropdown selection:', error); setIsOpen(false); } }; useEffect(() => { if (isOpen) { document.addEventListener('mousedown', handleClickOutside); } else { document.removeEventListener('mousedown', handleClickOutside); } return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [isOpen]); const selectedOption = options.find((option) => option.value === value); return (
{isOpen && createPortal(
e.stopPropagation()} > {options.map((option) => ( ))}
, document.body )}
); }; export default NumberSelectDropdown;