diff --git a/.changeset/neat-donuts-enjoy.md b/.changeset/neat-donuts-enjoy.md new file mode 100644 index 0000000000..4d922e859d --- /dev/null +++ b/.changeset/neat-donuts-enjoy.md @@ -0,0 +1,6 @@ +--- +'@twilio-paste/combobox': patch +'@twilio-paste/core': patch +--- + +[Combobox] prevent selection of disabled items when using keyboard navigation and the enter key diff --git a/.changeset/thin-kids-beam.md b/.changeset/thin-kids-beam.md new file mode 100644 index 0000000000..085d0d8ae9 --- /dev/null +++ b/.changeset/thin-kids-beam.md @@ -0,0 +1,6 @@ +--- +'@twilio-paste/combobox-primitive': patch +'@twilio-paste/core': patch +--- + +[Combobox Primitive] export new type `UseComboboxPrimitiveStateChangeOptions` to help type stateReducers diff --git a/packages/paste-core/components/combobox/src/singleselect/Combobox.tsx b/packages/paste-core/components/combobox/src/singleselect/Combobox.tsx index cdc92a0e5e..9bed439c55 100644 --- a/packages/paste-core/components/combobox/src/singleselect/Combobox.tsx +++ b/packages/paste-core/components/combobox/src/singleselect/Combobox.tsx @@ -100,6 +100,7 @@ const Combobox = React.forwardRef( state, getA11yStatusMessage, getA11ySelectionMessage, + disabledItems, }); if ( diff --git a/packages/paste-core/components/combobox/src/singleselect/extractPropsFromState.tsx b/packages/paste-core/components/combobox/src/singleselect/extractPropsFromState.tsx index 1962f5099e..669a47f6c0 100644 --- a/packages/paste-core/components/combobox/src/singleselect/extractPropsFromState.tsx +++ b/packages/paste-core/components/combobox/src/singleselect/extractPropsFromState.tsx @@ -1,6 +1,11 @@ import * as React from 'react'; import {useComboboxPrimitive} from '@twilio-paste/combobox-primitive'; -import type {UseComboboxPrimitiveStateChange, UseComboboxPrimitiveReturnValue} from '@twilio-paste/combobox-primitive'; +import type { + UseComboboxPrimitiveState, + UseComboboxPrimitiveStateChange, + UseComboboxPrimitiveStateChangeOptions, + UseComboboxPrimitiveReturnValue, +} from '@twilio-paste/combobox-primitive'; import isEmpty from 'lodash/isEmpty'; import type {ComboboxProps} from '../types'; @@ -16,6 +21,7 @@ type DefaultStateProps = { selectedItem: ComboboxProps['selectedItem']; initialSelectedItem: ComboboxProps['initialSelectedItem']; items: ComboboxProps['items']; + disabledItems: ComboboxProps['disabledItems']; getA11yStatusMessage: ComboboxProps['getA11yStatusMessage']; getA11ySelectionMessage: ComboboxProps['getA11ySelectionMessage']; }; @@ -33,10 +39,24 @@ const getDefaultState = ({ items, getA11yStatusMessage, getA11ySelectionMessage, + disabledItems, }: DefaultStateProps): Partial> => { + const stateReducer = ( + state: UseComboboxPrimitiveState, + actionAndChanges: UseComboboxPrimitiveStateChangeOptions + ): Partial> => { + // If the item to be selected is disabled, return the current state without changes + if (disabledItems?.includes(actionAndChanges.changes.selectedItem)) { + return state; + } + + return actionAndChanges.changes; + }; + return useComboboxPrimitive({ initialSelectedItem, items, + stateReducer, onHighlightedIndexChange: React.useCallback( (changes: UseComboboxPrimitiveStateChange) => { if (onHighlightedIndexChange) { diff --git a/packages/paste-core/components/combobox/stories/Combobox.stories.tsx b/packages/paste-core/components/combobox/stories/Combobox.stories.tsx index c5fe7a6a1d..0024e41531 100644 --- a/packages/paste-core/components/combobox/stories/Combobox.stories.tsx +++ b/packages/paste-core/components/combobox/stories/Combobox.stories.tsx @@ -484,6 +484,7 @@ export const ComboboxObject: StoryFn = () => { } }} itemToString={(item: ObjectItem) => (item ? item.label : '')} + disabledItems={objectItems.slice(2, 5)} /> ); }; diff --git a/packages/paste-core/primitives/combobox/src/index.tsx b/packages/paste-core/primitives/combobox/src/index.tsx index a41e6d9d94..9da36c54b6 100644 --- a/packages/paste-core/primitives/combobox/src/index.tsx +++ b/packages/paste-core/primitives/combobox/src/index.tsx @@ -13,6 +13,7 @@ export type { UseComboboxState as UseComboboxPrimitiveState, UseComboboxReturnValue as UseComboboxPrimitiveReturnValue, UseComboboxStateChange as UseComboboxPrimitiveStateChange, + UseComboboxStateChangeOptions as UseComboboxPrimitiveStateChangeOptions, UseComboboxGetItemPropsOptions as UseComboboxPrimitiveGetItemPropsOptions, UseComboboxGetMenuPropsOptions as UseComboboxPrimitiveGetMenuPropsOptions, GetPropsCommonOptions as GetComboboxPrimitivePropsCommonOptions,