diff --git a/change/@fluentui-react-card-2e76b5b0-5eb0-4302-8ff2-19391b355451.json b/change/@fluentui-react-card-2e76b5b0-5eb0-4302-8ff2-19391b355451.json new file mode 100644 index 00000000000000..2c711765821852 --- /dev/null +++ b/change/@fluentui-react-card-2e76b5b0-5eb0-4302-8ff2-19391b355451.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: sync controllable state for selectable cards", + "packageName": "@fluentui/react-card", + "email": "marcosvmmoura@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-card/src/components/Card/useCardSelectable.ts b/packages/react-components/react-card/src/components/Card/useCardSelectable.ts index 1bbef24cc70609..023b592302e8ec 100644 --- a/packages/react-components/react-card/src/components/Card/useCardSelectable.ts +++ b/packages/react-components/react-card/src/components/Card/useCardSelectable.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { mergeCallbacks, slot } from '@fluentui/react-utilities'; +import { mergeCallbacks, slot, useControllableState } from '@fluentui/react-utilities'; import { Enter } from '@fluentui/keyboard-keys'; import { useFocusFinders } from '@fluentui/react-tabster'; @@ -22,16 +22,21 @@ export const useCardSelectable = ( { referenceLabel, referenceId }: Pick, cardRef: React.RefObject, ) => { - const { checkbox = {}, selected, defaultSelected, onSelectionChange, floatingAction, onClick, onKeyDown } = props; + const { checkbox = {}, onSelectionChange, floatingAction, onClick, onKeyDown } = props; const { findAllFocusable } = useFocusFinders(); - const checkboxRef = React.useRef(null); - const isSelectable = [selected, defaultSelected, onSelectionChange].some(prop => typeof prop !== 'undefined'); + const [selected, setSelected] = useControllableState({ + state: props.selected, + defaultState: props.defaultSelected, + initialState: false, + }); + const selectable = [props.selected, props.defaultSelected, onSelectionChange].some( + prop => typeof prop !== 'undefined', + ); - const [isCardSelected, setIsCardSelected] = React.useState(false); - const [isSelectFocused, setIsSelectFocused] = React.useState(false); + const [selectFocused, setSelectFocused] = React.useState(false); const shouldRestrictTriggerAction = React.useCallback( (event: CardOnSelectionChangeEvent) => { @@ -55,15 +60,15 @@ export const useCardSelectable = ( return; } - const newCheckedValue = !isCardSelected; + const newCheckedValue = !selected; - setIsCardSelected(newCheckedValue); + setSelected(newCheckedValue); if (onSelectionChange) { onSelectionChange(event, { selected: newCheckedValue }); } }, - [onSelectionChange, isCardSelected, shouldRestrictTriggerAction], + [onSelectionChange, selected, setSelected, shouldRestrictTriggerAction], ); const onKeyDownHandler = React.useCallback( @@ -77,7 +82,7 @@ export const useCardSelectable = ( ); const checkboxSlot = React.useMemo(() => { - if (!isSelectable || floatingAction) { + if (!selectable || floatingAction) { return; } @@ -93,15 +98,15 @@ export const useCardSelectable = ( defaultProps: { ref: checkboxRef, type: 'checkbox', - checked: isCardSelected, + checked: selected, onChange: (event: React.ChangeEvent) => onChangeHandler(event), - onFocus: () => setIsSelectFocused(true), - onBlur: () => setIsSelectFocused(false), + onFocus: () => setSelectFocused(true), + onBlur: () => setSelectFocused(false), ...selectableCheckboxProps, }, elementType: 'input', }); - }, [checkbox, floatingAction, isCardSelected, isSelectable, onChangeHandler, referenceId, referenceLabel]); + }, [checkbox, floatingAction, selected, selectable, onChangeHandler, referenceId, referenceLabel]); const floatingActionSlot = React.useMemo(() => { if (!floatingAction) { @@ -117,7 +122,7 @@ export const useCardSelectable = ( }, [floatingAction]); const selectableCardProps = React.useMemo(() => { - if (!isSelectable) { + if (!selectable) { return null; } @@ -125,17 +130,12 @@ export const useCardSelectable = ( onClick: mergeCallbacks(onClick, onChangeHandler), onKeyDown: mergeCallbacks(onKeyDown, onKeyDownHandler), }; - }, [isSelectable, onChangeHandler, onClick, onKeyDown, onKeyDownHandler]); - - React.useEffect( - () => setIsCardSelected(Boolean(defaultSelected ?? selected)), - [defaultSelected, selected, setIsCardSelected], - ); + }, [selectable, onChangeHandler, onClick, onKeyDown, onKeyDownHandler]); return { - selected: isCardSelected, - selectable: isSelectable, - selectFocused: isSelectFocused, + selected, + selectable, + selectFocused, selectableCardProps, checkboxSlot, floatingActionSlot,