feat(combobox): reset value on form reset

This commit is contained in:
Paul Chavard 2024-07-02 22:18:32 +02:00
parent 89fb0abe6e
commit c6f1d16451
No known key found for this signature in database
2 changed files with 75 additions and 19 deletions

View file

@ -22,6 +22,7 @@ import {
useMultiList,
useSingleList,
useRemoteList,
useOnFormReset,
createLoader,
type ComboBoxProps
} from './react-aria/hooks';
@ -102,7 +103,7 @@ export function SingleComboBox({
const labelledby = useLabelledBy(props.id, ariaLabelledby);
const { ref, dispatch } = useDispatchChangeEvent();
const { selectedItem, ...comboBoxProps } = useSingleList({
const { selectedItem, onReset, ...comboBoxProps } = useSingleList({
defaultItems,
defaultSelectedKey,
emptyFilterKey,
@ -122,6 +123,7 @@ export function SingleComboBox({
field={formValue == 'text' ? 'label' : 'value'}
name={name}
form={form}
onReset={onReset}
data={data}
/>
) : null}
@ -150,18 +152,24 @@ export function MultiComboBox(maybeProps: MultiComboBoxProps) {
const { ref, dispatch } = useDispatchChangeEvent();
const inputRef = useRef<HTMLInputElement>(null);
const { selectedItems, hiddenInputValues, onRemove, ...comboBoxProps } =
useMultiList({
defaultItems,
defaultSelectedKeys,
onChange: dispatch,
formValue,
allowsCustomValue,
valueSeparator,
focusInput: () => {
inputRef.current?.focus();
}
});
const {
selectedItems,
hiddenInputValues,
onRemove,
onReset,
...comboBoxProps
} = useMultiList({
defaultItems,
defaultSelectedKeys,
onChange: dispatch,
formValue,
allowsCustomValue,
valueSeparator,
focusInput: () => {
inputRef.current?.focus();
}
});
const formResetRef = useOnFormReset(onReset);
return (
<div className="fr-ds-combobox__multiple">
@ -193,12 +201,13 @@ export function MultiComboBox(maybeProps: MultiComboBoxProps) {
</ComboBox>
{name ? (
<span ref={ref}>
{hiddenInputValues.map((value) => (
{hiddenInputValues.map((value, i) => (
<input
type="hidden"
value={value}
name={name}
form={form}
ref={i == 0 ? formResetRef : undefined}
key={value}
/>
))}
@ -238,7 +247,7 @@ export function RemoteComboBox({
: loader,
[loader, minimumInputLength, limit]
);
const { selectedItem, ...comboBoxProps } = useRemoteList({
const { selectedItem, onReset, ...comboBoxProps } = useRemoteList({
allowsCustomValue,
defaultItems,
defaultSelectedKey,
@ -270,6 +279,7 @@ export function RemoteComboBox({
}
name={name}
form={form}
onReset={onReset}
data={data}
/>
) : null}
@ -285,11 +295,13 @@ export function ComboBoxValueSlot({
field,
name,
form,
onReset,
data
}: {
field: 'label' | 'value' | 'data';
name: string;
form?: string;
onReset?: () => void;
data?: Record<string, string>;
}) {
const selectedItem = useContext(SelectedItemContext);
@ -300,8 +312,16 @@ export function ComboBoxValueSlot({
value
])
);
const ref = useOnFormReset(onReset);
return (
<input type="hidden" name={name} value={value} form={form} {...dataProps} />
<input
ref={onReset ? ref : undefined}
type="hidden"
name={name}
value={value}
form={form}
{...dataProps}
/>
);
}

View file

@ -107,6 +107,10 @@ export function useSingleList({
}
}
);
const onReset = useEvent(() => {
setSelectedKey(null);
setInputValue('');
});
// reset default selected key when props change
useEffect(() => {
@ -122,7 +126,8 @@ export function useSingleList({
onSelectionChange,
inputValue,
onInputChange,
items: filteredItems
items: filteredItems,
onReset
};
}
@ -272,6 +277,11 @@ export function useMultiList({
}
);
const onReset = useEvent(() => {
setSelectedKeys(new Set());
setInputValue('');
});
return {
onRemove,
onSelectionChange,
@ -279,7 +289,8 @@ export function useMultiList({
selectedItems,
items: filteredItems,
hiddenInputValues,
inputValue
inputValue,
onReset
};
}
@ -357,6 +368,11 @@ export function useRemoteList({
}
);
const onReset = useEvent(() => {
setSelectedItem(null);
setInputValue('');
});
// add to items list current selected item if it's not in the list
const items =
selectedItem && !list.getItem(selectedItem.value)
@ -369,7 +385,8 @@ export function useRemoteList({
onSelectionChange,
inputValue,
onInputChange,
items
items,
onReset
};
}
@ -436,3 +453,22 @@ function findLabelledbyId(id?: string) {
}
return label.id;
}
export function useOnFormReset(onReset?: () => void) {
const ref = useRef<HTMLInputElement>(null);
const onResetListener = useEvent<EventListener>((event) => {
if (event.target == ref.current?.form) {
onReset?.();
}
});
useEffect(() => {
if (onReset) {
addEventListener('reset', onResetListener);
return () => {
removeEventListener('reset', onResetListener);
};
}
}, [onReset, onResetListener]);
return ref;
}