import type { PropsWithChildren } from 'react'; import { useCallback, useState, useRef, useId } from 'react'; import classNames from 'classnames'; import type { Placement, State as PopperState } from '@popperjs/core'; import Overlay from 'react-overlays/Overlay'; import ArrowDropDownIcon from '@/material-icons/400-24px/arrow_drop_down.svg?react'; import type { SelectItem } from 'mastodon/components/dropdown_selector'; import { DropdownSelector } from 'mastodon/components/dropdown_selector'; import { Icon } from 'mastodon/components/icon'; interface DropdownProps { value: string; options: SelectItem[]; disabled?: boolean; onChange: (value: string) => void; 'aria-labelledby': string; 'aria-describedby'?: string; placement?: Placement; } const Dropdown: React.FC = ({ value, options, disabled, onChange, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, placement: initialPlacement = 'bottom-end', }) => { const containerRef = useRef(null); const buttonRef = useRef(null); const [isOpen, setOpen] = useState(false); const [placement, setPlacement] = useState(initialPlacement); const uniqueId = useId(); const menuId = `${uniqueId}-menu`; const buttonLabelId = `${uniqueId}-button`; const handleClose = useCallback(() => { if (isOpen && buttonRef.current) { buttonRef.current.focus({ preventScroll: true }); } setOpen(false); }, [isOpen]); const handleToggle = useCallback(() => { if (isOpen) { handleClose(); } else { setOpen(true); } }, [isOpen, handleClose]); const handleOverlayEnter = useCallback( (state: Partial) => { if (state.placement) setPlacement(state.placement); }, [setPlacement], ); const valueOption = options.find((item) => item.value === value); return (
{({ props, placement }) => (
)}
); }; interface Props { value: string; options: SelectItem[]; label: string | React.ReactElement; hint: string | React.ReactElement; disabled?: boolean; onChange: (value: string) => void; } export const SelectWithLabel: React.FC> = ({ value, options, label, hint, disabled, onChange, }) => { const uniqueId = useId(); const labelId = `${uniqueId}-label`; const descId = `${uniqueId}-desc`; return ( // This label is only used for its click-forwarding behaviour, // accessible names are assigned manually // eslint-disable-next-line jsx-a11y/label-has-associated-control ); };