Files
cunningham/packages/react/src/components/Forms/Select/multi.tsx
Nathan Vasse 94b32be5d3 (react) add monoline props to multi select
We want to enable a mode that prevent the pills the wrap on multiple
lines in order to control any height overflowing. In monoline mode the
selected items are displayed as text to allow text ellipsis, and the
menu renders the list items with checkboxes.
2023-11-24 11:01:41 +01:00

74 lines
2.3 KiB
TypeScript

import React, { forwardRef, useEffect } from "react";
import { optionToValue } from ":/components/Forms/Select/mono-common";
import { SelectMultiSearchable } from ":/components/Forms/Select/multi-searchable";
import { SelectMultiSimple } from ":/components/Forms/Select/multi-simple";
import { SubProps } from ":/components/Forms/Select/multi-common";
import {
Option,
SelectHandle,
SelectProps,
} from ":/components/Forms/Select/index";
export type SelectMultiProps = Omit<SelectProps, "onChange"> & {
onChange?: (event: { target: { value: string[] } }) => void;
};
export const SelectMulti = forwardRef<SelectHandle, SelectMultiProps>(
(props, ref) => {
const getSelectedItemsFromProps = () => {
const valueToUse = props.defaultValue ?? props.value ?? [];
return props.options.filter((option) =>
(valueToUse as string[]).includes(optionToValue(option)),
);
};
const [selectedItems, setSelectedItems] = React.useState<Option[]>(
getSelectedItemsFromProps(),
);
// If the component is used as a controlled component, we need to update the local value when the value prop changes.
useEffect(() => {
// Means it is not controlled.
if (props.defaultValue !== undefined) {
return;
}
setSelectedItems(getSelectedItemsFromProps());
}, [JSON.stringify(props.value)]);
// If the component is used as an uncontrolled component, we need to update the parent value when the local value changes.
useEffect(() => {
props.onChange?.({ target: { value: selectedItems.map(optionToValue) } });
}, [JSON.stringify(selectedItems)]);
const onSelectedItemsChange: SubProps["onSelectedItemsChange"] = (
newSelectedItems,
) => {
setSelectedItems(newSelectedItems);
};
const defaultProps: Partial<SelectMultiProps> = {
selectedItemsStyle: "pills",
menuOptionsStyle: "plain",
clearable: true,
};
return props.searchable ? (
<SelectMultiSearchable
{...defaultProps}
{...props}
selectedItems={selectedItems}
onSelectedItemsChange={onSelectedItemsChange}
ref={ref}
/>
) : (
<SelectMultiSimple
{...defaultProps}
{...props}
selectedItems={selectedItems}
onSelectedItemsChange={onSelectedItemsChange}
ref={ref}
/>
);
},
);