(react) add ref to Select

We encountered a use-case where we needed to blur the select programatically
but the component wasn't offering any way to do that.
This commit is contained in:
Nathan Vasse
2023-10-03 17:02:23 +02:00
committed by NathanVss
parent d647a77c58
commit 1c7a114b6e
12 changed files with 869 additions and 474 deletions

View File

@@ -1,58 +1,63 @@
import React, { useEffect } from "react";
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, SelectProps } from ":/components/Forms/Select/mono";
import { SelectHandle } from ":/components/Forms/Select/index";
export type SelectMultiProps = Omit<SelectProps, "onChange"> & {
onChange?: (event: { target: { value: string[] } }) => void;
};
export const SelectMulti = (props: SelectMultiProps) => {
const getSelectedItemsFromProps = () => {
const valueToUse = props.defaultValue ?? props.value ?? [];
return props.options.filter((option) =>
(valueToUse as string[]).includes(optionToValue(option)),
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(),
);
};
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 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)]);
// 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);
// props.onSelectedItemsChange?.(newSelectedItems);
};
const onSelectedItemsChange: SubProps["onSelectedItemsChange"] = (
newSelectedItems,
) => {
setSelectedItems(newSelectedItems);
// props.onSelectedItemsChange?.(newSelectedItems);
};
return props.searchable ? (
<SelectMultiSearchable
{...props}
selectedItems={selectedItems}
onSelectedItemsChange={onSelectedItemsChange}
/>
) : (
<SelectMultiSimple
{...props}
selectedItems={selectedItems}
onSelectedItemsChange={onSelectedItemsChange}
/>
);
};
return props.searchable ? (
<SelectMultiSearchable
{...props}
selectedItems={selectedItems}
onSelectedItemsChange={onSelectedItemsChange}
ref={ref}
/>
) : (
<SelectMultiSimple
{...props}
selectedItems={selectedItems}
onSelectedItemsChange={onSelectedItemsChange}
ref={ref}
/>
);
},
);