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, useMultiList,
useSingleList, useSingleList,
useRemoteList, useRemoteList,
useOnFormReset,
createLoader, createLoader,
type ComboBoxProps type ComboBoxProps
} from './react-aria/hooks'; } from './react-aria/hooks';
@ -102,7 +103,7 @@ export function SingleComboBox({
const labelledby = useLabelledBy(props.id, ariaLabelledby); const labelledby = useLabelledBy(props.id, ariaLabelledby);
const { ref, dispatch } = useDispatchChangeEvent(); const { ref, dispatch } = useDispatchChangeEvent();
const { selectedItem, ...comboBoxProps } = useSingleList({ const { selectedItem, onReset, ...comboBoxProps } = useSingleList({
defaultItems, defaultItems,
defaultSelectedKey, defaultSelectedKey,
emptyFilterKey, emptyFilterKey,
@ -122,6 +123,7 @@ export function SingleComboBox({
field={formValue == 'text' ? 'label' : 'value'} field={formValue == 'text' ? 'label' : 'value'}
name={name} name={name}
form={form} form={form}
onReset={onReset}
data={data} data={data}
/> />
) : null} ) : null}
@ -150,8 +152,13 @@ export function MultiComboBox(maybeProps: MultiComboBoxProps) {
const { ref, dispatch } = useDispatchChangeEvent(); const { ref, dispatch } = useDispatchChangeEvent();
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const { selectedItems, hiddenInputValues, onRemove, ...comboBoxProps } = const {
useMultiList({ selectedItems,
hiddenInputValues,
onRemove,
onReset,
...comboBoxProps
} = useMultiList({
defaultItems, defaultItems,
defaultSelectedKeys, defaultSelectedKeys,
onChange: dispatch, onChange: dispatch,
@ -162,6 +169,7 @@ export function MultiComboBox(maybeProps: MultiComboBoxProps) {
inputRef.current?.focus(); inputRef.current?.focus();
} }
}); });
const formResetRef = useOnFormReset(onReset);
return ( return (
<div className="fr-ds-combobox__multiple"> <div className="fr-ds-combobox__multiple">
@ -193,12 +201,13 @@ export function MultiComboBox(maybeProps: MultiComboBoxProps) {
</ComboBox> </ComboBox>
{name ? ( {name ? (
<span ref={ref}> <span ref={ref}>
{hiddenInputValues.map((value) => ( {hiddenInputValues.map((value, i) => (
<input <input
type="hidden" type="hidden"
value={value} value={value}
name={name} name={name}
form={form} form={form}
ref={i == 0 ? formResetRef : undefined}
key={value} key={value}
/> />
))} ))}
@ -238,7 +247,7 @@ export function RemoteComboBox({
: loader, : loader,
[loader, minimumInputLength, limit] [loader, minimumInputLength, limit]
); );
const { selectedItem, ...comboBoxProps } = useRemoteList({ const { selectedItem, onReset, ...comboBoxProps } = useRemoteList({
allowsCustomValue, allowsCustomValue,
defaultItems, defaultItems,
defaultSelectedKey, defaultSelectedKey,
@ -270,6 +279,7 @@ export function RemoteComboBox({
} }
name={name} name={name}
form={form} form={form}
onReset={onReset}
data={data} data={data}
/> />
) : null} ) : null}
@ -285,11 +295,13 @@ export function ComboBoxValueSlot({
field, field,
name, name,
form, form,
onReset,
data data
}: { }: {
field: 'label' | 'value' | 'data'; field: 'label' | 'value' | 'data';
name: string; name: string;
form?: string; form?: string;
onReset?: () => void;
data?: Record<string, string>; data?: Record<string, string>;
}) { }) {
const selectedItem = useContext(SelectedItemContext); const selectedItem = useContext(SelectedItemContext);
@ -300,8 +312,16 @@ export function ComboBoxValueSlot({
value value
]) ])
); );
const ref = useOnFormReset(onReset);
return ( 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 // reset default selected key when props change
useEffect(() => { useEffect(() => {
@ -122,7 +126,8 @@ export function useSingleList({
onSelectionChange, onSelectionChange,
inputValue, inputValue,
onInputChange, onInputChange,
items: filteredItems items: filteredItems,
onReset
}; };
} }
@ -272,6 +277,11 @@ export function useMultiList({
} }
); );
const onReset = useEvent(() => {
setSelectedKeys(new Set());
setInputValue('');
});
return { return {
onRemove, onRemove,
onSelectionChange, onSelectionChange,
@ -279,7 +289,8 @@ export function useMultiList({
selectedItems, selectedItems,
items: filteredItems, items: filteredItems,
hiddenInputValues, 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 // add to items list current selected item if it's not in the list
const items = const items =
selectedItem && !list.getItem(selectedItem.value) selectedItem && !list.getItem(selectedItem.value)
@ -369,7 +385,8 @@ export function useRemoteList({
onSelectionChange, onSelectionChange,
inputValue, inputValue,
onInputChange, onInputChange,
items items,
onReset
}; };
} }
@ -436,3 +453,22 @@ function findLabelledbyId(id?: string) {
} }
return label.id; 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;
}