Files
WhiteNightsAdminPanel/src/shared/ui/MultiSelect/index.tsx
2026-03-18 20:11:07 +03:00

96 lines
2.6 KiB
TypeScript

import {
Autocomplete,
Checkbox,
CircularProgress,
TextField,
} from "@mui/material";
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
import CheckBoxIcon from "@mui/icons-material/CheckBox";
export interface MultiSelectOption<TValue = number | string> {
readonly value: TValue;
readonly label: string;
}
interface MultiSelectProps<TValue = number | string> {
readonly options: MultiSelectOption<TValue>[];
readonly value: TValue[];
readonly onChange: (values: TValue[]) => void;
readonly label?: string;
readonly placeholder?: string;
readonly loading?: boolean;
readonly disabled?: boolean;
readonly error?: boolean;
readonly helperText?: string;
readonly size?: "small" | "medium";
readonly fullWidth?: boolean;
}
export function MultiSelect<TValue = number | string>({
options,
value,
onChange,
label,
placeholder,
loading = false,
disabled = false,
error = false,
helperText,
size = "small",
fullWidth = true,
}: MultiSelectProps<TValue>) {
const selectedOptions = options.filter((opt) => value.includes(opt.value));
return (
<Autocomplete
multiple
disableCloseOnSelect
fullWidth={fullWidth}
size={size}
disabled={disabled}
loading={loading}
options={options}
value={selectedOptions}
getOptionLabel={(option) => option.label}
isOptionEqualToValue={(option, selected) => option.value === selected.value}
onChange={(_, newSelected) => {
onChange(newSelected.map((opt) => opt.value));
}}
renderOption={(props, option, { selected }) => {
const { key, ...rest } = props as React.HTMLAttributes<HTMLLIElement> & { key: React.Key };
return (
<li key={key} {...rest}>
<Checkbox
icon={<CheckBoxOutlineBlankIcon fontSize="small" />}
checkedIcon={<CheckBoxIcon fontSize="small" />}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.label}
</li>
);
}}
renderInput={(params) => (
<TextField
{...params}
label={label}
placeholder={selectedOptions.length === 0 ? placeholder : undefined}
error={error}
helperText={helperText}
slotProps={{
input: {
...params.InputProps,
endAdornment: (
<>
{loading && <CircularProgress color="inherit" size={16} />}
{params.InputProps.endAdornment}
</>
),
},
}}
/>
)}
/>
);
}