import { Close } from '@mui/icons-material' import { Box, Button, IconButton, Sheet, Typography } from '@mui/joy' import { ClickAwayListener, Popper } from '@mui/material' import { useEffect, useMemo, useRef, useState } from 'react' import { Z_INDEX } from '../../constants/zIndex' const BaseOptionPicker = ({ items = [], value = null, values = [], multiple = false, onChange, onValuesChange, emptyDisplay = 'icon', emptyLabel = 'Select', placement = 'top-start', menuMinWidth = 180, menuMaxHeight = 280, getItemValue = item => item.id, getItemLabel = item => item.label, renderItemStart, renderTriggerIcon, getItemColor, getTriggerText, onClear, }) => { const [isOpen, setIsOpen] = useState(false) const buttonRef = useRef(null) useEffect(() => { if (!isOpen) return const handleEscape = event => { if (event.key === 'Escape') { setIsOpen(false) } } document.addEventListener('keydown', handleEscape) return () => { document.removeEventListener('keydown', handleEscape) } }, [isOpen]) const selectedItems = useMemo(() => { if (multiple) { const selectedSet = new Set(values) return items.filter(item => selectedSet.has(getItemValue(item))) } if (value === null || value === undefined) return [] return items.filter(item => getItemValue(item) === value) }, [items, multiple, value, values, getItemValue]) const isEmpty = selectedItems.length === 0 const shouldShowLabel = !isEmpty || emptyDisplay === 'icon-text' const triggerText = getTriggerText ? getTriggerText({ selectedItems, isEmpty }) : isEmpty ? emptyLabel : getItemLabel(selectedItems[0]) const triggerColor = isEmpty ? undefined : getItemColor ? getItemColor(selectedItems[0]) : undefined const handleSelect = selectedValue => { if (multiple) { const selectedSet = new Set(values) if (selectedSet.has(selectedValue)) { selectedSet.delete(selectedValue) } else { selectedSet.add(selectedValue) } onValuesChange?.(Array.from(selectedSet)) return } onChange?.(selectedValue) setIsOpen(false) } const isSelected = item => { const optionValue = getItemValue(item) if (multiple) { return values.includes(optionValue) } return value === optionValue } const handleClear = e => { e.stopPropagation() onClear?.() } return ( <> {!isEmpty && onClear && ( )} {isOpen && ( setIsOpen(false)}> {items.map((item, index) => { const optionValue = getItemValue(item) const selected = isSelected(item) const itemColor = getItemColor ? getItemColor(item) : undefined return ( ) })} )} ) } export default BaseOptionPicker