import React, { type ReactNode, useRef } from 'react'; import { useSelect } from 'downshift'; import { classNames } from '../../utils'; import { DropdownItem } from '../DropdownItem'; import { Icon } from '../Icon'; import { DropdownMenuContent } from '../DropdownMenuContent'; import styles from './SelectAddon.module.css'; const { stateChangeTypes } = useSelect; export type SelectAddonOptionGroup = { key: string; label: string; options: T[]; }; export type SelectAddonOption = { key: string; label: string }; export type Props = { className?: string; options: (T | SelectAddonOptionGroup)[]; value: T | undefined; isDisabled?: boolean; position?: 'left' | 'right'; onSelect(value: T): void; optionToString?(option: SelectAddonOption | null): string; renderOption?(option: T, state?: { isSelected: boolean }): ReactNode; // should always return a DropdownItem component renderOptionGroup?(optionGroup: SelectAddonOptionGroup): ReactNode; renderSelectedItem(value: T): React.ReactNode; } & Omit, 'type' | 'value' | 'onSelect'>; export const SelectAddon = ({ className, options, value, isDisabled = false, position = 'right', onSelect, optionToString = (option) => option?.label ?? '', renderOption, renderOptionGroup, renderSelectedItem, ...rest }: Props) => { const inputRef = useRef(null); const { isOpen, getToggleButtonProps, getMenuProps, getItemProps } = useSelect({ items: options.flatMap((option) => 'options' in option ? option.options : option, ), itemToString: optionToString, selectedItem: value ?? null, onSelectedItemChange: ({ selectedItem: newSelectedItem }) => { if (newSelectedItem) { onSelect(newSelectedItem); } }, onStateChange: ({ type }) => { switch (type) { case stateChangeTypes.ItemClick: case stateChangeTypes.ToggleButtonKeyDownEnter: if (inputRef.current) { inputRef.current.blur(); } break; default: } }, }); return ( <>
{ const isSelected = value?.key === option.key; if (renderOption) { return renderOption(option, { isSelected }); } return ( ); }} renderOptionGroup={renderOptionGroup} /> ); };