diff --git a/.changeset/silver-falcons-shop.md b/.changeset/silver-falcons-shop.md new file mode 100644 index 0000000000..85dbb7b019 --- /dev/null +++ b/.changeset/silver-falcons-shop.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**Suggestion**: Always call `onSelectedChange`, and return `null` instead of `undefined` diff --git a/packages/react/src/components/suggestion/suggestion.stories.tsx b/packages/react/src/components/suggestion/suggestion.stories.tsx index 2ec5d5420b..3e8f5449ee 100644 --- a/packages/react/src/components/suggestion/suggestion.stories.tsx +++ b/packages/react/src/components/suggestion/suggestion.stories.tsx @@ -242,7 +242,7 @@ ControlledMultiple.play = async ({ canvasElement, step }) => { export const ControlledIndependentLabelValue: StoryFn = ( args, ) => { - const [item, setItem] = useState(DATA_PEOPLE[0]); + const [item, setItem] = useState(DATA_PEOPLE[0]); return ( <> diff --git a/packages/react/src/components/suggestion/suggestion.tsx b/packages/react/src/components/suggestion/suggestion.tsx index 375524d8db..e7bea2563a 100644 --- a/packages/react/src/components/suggestion/suggestion.tsx +++ b/packages/react/src/components/suggestion/suggestion.tsx @@ -109,7 +109,7 @@ type SuggestionValueProps = { * * Using this makes the component controlled and it must be used in combination with `onSelectedChange`. */ - selected?: SuggestionValue; + selected?: SuggestionValue | null; /** * Default selected item when uncontrolled */ @@ -120,7 +120,7 @@ type SuggestionValueProps = { onSelectedChange?: ( value: T['multiple'] extends true ? SuggestionItem[] - : SuggestionItem | undefined, + : SuggestionItem | null, ) => void; }; @@ -192,12 +192,17 @@ export const Suggestion = forwardRef( ); const selectedItems = selected ? sanitizeItems(selected) : defaultItems; const onSelectedChangeRef = useRef(onSelectedChange); + const selectedItemsRef = useRef(selectedItems); // Keep the ref updated with the latest callback useEffect(() => { onSelectedChangeRef.current = onSelectedChange; }, [onSelectedChange]); + useEffect(() => { + selectedItemsRef.current = selectedItems; + }, [selectedItems]); + /** * Listerners and handling of adding/removing */ @@ -207,19 +212,19 @@ export const Suggestion = forwardRef( event.preventDefault(); const multiple = combobox?.multiple; const data = event.detail; - const nextItem = nextItems(data, selectedItems, multiple); + const nextItem = nextItems(data, selectedItemsRef.current, multiple); + + onSelectedChangeRef.current?.( + (nextItem as SuggestionItem & SuggestionItem[]) || null, + ); - if (isControlled) - onSelectedChangeRef.current?.( - nextItem as SuggestionItem & SuggestionItem[], - ); - else setDefaultItems(sanitizeItems(nextItem)); + if (!isControlled) setDefaultItems(sanitizeItems(nextItem)); }; combobox?.addEventListener('comboboxbeforeselect', beforeChange); return () => combobox?.removeEventListener('comboboxbeforeselect', beforeChange); - }, [selectedItems, isControlled]); + }, [isControlled]); // Before match event listener useEffect(() => {