import { ReactNode, useId } from 'react'; import { Checkbox, CheckboxProps, Chip, ChipProps, FormControl, FormControlProps, FormHelperText, InputLabel, InputLabelProps, MenuItem, MenuItemProps, PaperProps, Select as MuiSelect, SelectChangeEvent, SelectProps as MuiSelectProps } from '@mui/material'; import { FormHelperTextProps } from '@mui/material'; import { Box } from '@mui/material'; import { isFunction } from 'lodash'; import { useDefaultProps } from '../../hooks'; export interface MultiSelectOption { value: Value; label: ReactNode; menuItemProps?: Omit; } type ExtractOptionValue[]> = TOptions[number] extends MultiSelectOption ? V : never; type MultiSelectValue[]> = ExtractOptionValue[]; export type MultiSelectProps[] = []> = Omit< MuiSelectProps>, 'value' | 'onChange' | 'multiple' > & { value: MultiSelectValue; onChange?: ( value: MultiSelectValue, event: SelectChangeEvent>, child: React.ReactNode ) => void; /** * @default false */ checkbox?: boolean; /** * @default false */ chip?: boolean; placeholder?: ReactNode; helperText?: ReactNode; options: TOptions; slotProps?: { formControl?: Omit; helperText?: FormHelperTextProps; inputLabel?: InputLabelProps; menuItemProps?: Omit; checkbox?: Omit; chip?: Omit; }; }; function MultiSelect[] = []>(inProps: MultiSelectProps) { const { value, disabled, error, required, slotProps, helperText, label, children, options, variant, placeholder, fullWidth = true, checkbox = false, chip = false, onChange, MenuProps, displayEmpty, renderValue, size, color, ...other } = useDefaultProps({ name: 'ReevolveMultiSelect', props: inProps }); const selectLabelId = useId(); const onChangeHandler: MuiSelectProps>['onChange'] = (event, child) => { const value = event.target.value as MultiSelectValue; onChange?.(value, event, child); }; const _value = value ?? []; return ( {label && ( {label} )} { if (renderValue) { return renderValue(selected); } const selectedItems = options.filter((item) => selected.includes(item.value)); if (!selectedItems.length && placeholder) { return {placeholder}; } if (chip) { return ( {selectedItems.map((item) => ( ))} ); } return selectedItems.map((item) => item.label).join(', '); }} multiple labelId={selectLabelId} value={_value} onChange={onChangeHandler} label={label} slotProps={{ input: slotProps?.input, root: slotProps?.root }} displayEmpty={!!placeholder || displayEmpty} MenuProps={{ ...MenuProps, slotProps: { ...MenuProps?.slotProps, paper: { ...MenuProps?.slotProps?.paper, sx: (theme) => ({ maxHeight: 220, ...(isFunction((MenuProps?.slotProps?.paper as PaperProps)?.sx) ? ((MenuProps!.slotProps!.paper as PaperProps).sx as Function)(theme) : (MenuProps?.slotProps?.paper as PaperProps)?.sx) }) } } }} > {children} {placeholder && ( {placeholder} )} {options.map((option) => ( {checkbox && ( )} {option.label} ))} {helperText && {helperText}} ); } declare module '@mui/material' { interface Components { ReevolveMultiSelect?: { defaultProps?: Partial; }; } } export default MultiSelect;