From 6d2b1d4dceba8cc40f06ab3736e3cfaab9b25ce3 Mon Sep 17 00:00:00 2001 From: Joyce Zhu Date: Thu, 2 May 2024 15:26:54 -0700 Subject: [PATCH 1/6] Add `openOnFocus` prop to `AutocompleteInput` Towards github/accessibility-audits#7437 --- .../src/Autocomplete/Autocomplete.docs.json | 6 ++++ .../src/Autocomplete/Autocomplete.stories.tsx | 28 +++++++++++++++++-- .../src/Autocomplete/AutocompleteInput.tsx | 24 +++++++++++++--- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/packages/react/src/Autocomplete/Autocomplete.docs.json b/packages/react/src/Autocomplete/Autocomplete.docs.json index 39b19c9ce45..2ddbe7990db 100644 --- a/packages/react/src/Autocomplete/Autocomplete.docs.json +++ b/packages/react/src/Autocomplete/Autocomplete.docs.json @@ -19,6 +19,12 @@ "name": "as", "type": "React.ElementType", "defaultValue": "TextInput" + }, + { + "name": "openOnFocus", + "type": "boolean", + "defaultValue": true, + "description": "Whether the associated autocomplete menu should open on an input focus event" } ], "passthrough": { diff --git a/packages/react/src/Autocomplete/Autocomplete.stories.tsx b/packages/react/src/Autocomplete/Autocomplete.stories.tsx index 52553e6bae9..bb8189b7f58 100644 --- a/packages/react/src/Autocomplete/Autocomplete.stories.tsx +++ b/packages/react/src/Autocomplete/Autocomplete.stories.tsx @@ -29,6 +29,9 @@ const getArgsByChildComponent = ({ menuLoading, selectionVariant, + // Autocomplete.Input + openOnFocus, + // Autocomplete.Overlay anchorSide, height, @@ -65,6 +68,7 @@ any) => { } return { menuArgs: {emptyStateText, loading: menuLoading, selectionVariant}, + inputArgs: {openOnFocus}, overlayArgs: {anchorSide, height, maxHeight: overlayMaxHeight, width}, textInputArgs, textInputWithTokensArgs: { @@ -131,6 +135,7 @@ const autocompleteStoryMeta: Meta = { emptyStateText: 'No selectable options', menuLoading: false, selectionVariant: 'single', + openOnFocus: true, anchorSide: undefined, height: 'auto', overlayMaxHeight: undefined, @@ -161,6 +166,16 @@ const autocompleteStoryMeta: Meta = { }, }, + // Autocomplete.Input + openOnFocus: { + control: { + type: 'boolean', + }, + table: { + category: 'Autocomplete.Input', + }, + }, + // Autocomplete.Overlay anchorSide: { control: { @@ -217,7 +232,7 @@ const autocompleteStoryMeta: Meta = { export const Default = (args: FormControlArgs) => { const {parentArgs, labelArgs, captionArgs, validationArgs} = getFormControlArgsByChildComponent(args) - const {menuArgs, overlayArgs, textInputArgs} = getArgsByChildComponent(args) + const {menuArgs, inputArgs, overlayArgs, textInputArgs} = getArgsByChildComponent(args) const isMultiselect = menuArgs.selectionVariant === 'multiple' const [selectedItemIds, setSelectedItemIds] = useState>([]) const onSelectedChange = (newlySelectedItems: Datum | Datum[]) => { @@ -228,12 +243,19 @@ export const Default = (args: FormControlArgs) => { setSelectedItemIds(newlySelectedItems.map(item => item.id)) } + const autocompleteInput = {...inputArgs, ...textInputArgs} + const formValidationId = 'validation-field' return ( - + ) => { {captionArgs.children && } {validationArgs.children && validationArgs.variant && ( - + )} diff --git a/packages/react/src/Autocomplete/AutocompleteInput.tsx b/packages/react/src/Autocomplete/AutocompleteInput.tsx index 7cdb0469491..000070615a5 100644 --- a/packages/react/src/Autocomplete/AutocompleteInput.tsx +++ b/packages/react/src/Autocomplete/AutocompleteInput.tsx @@ -10,11 +10,25 @@ import useSafeTimeout from '../hooks/useSafeTimeout' type InternalAutocompleteInputProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any as?: React.ComponentType> + // When false, the autocomplete menu will not render either on mouse click or + // keyboard focus. + openOnFocus?: boolean } const AutocompleteInput = React.forwardRef( ( - {as: Component = TextInput, onFocus, onBlur, onChange, onKeyDown, onKeyUp, onKeyPress, value, ...props}, + { + as: Component = TextInput, + onFocus, + onBlur, + onChange, + onKeyDown, + onKeyUp, + onKeyPress, + value, + openOnFocus = true, + ...props + }, forwardedRef, ) => { const autocompleteContext = useContext(AutocompleteContext) @@ -38,10 +52,12 @@ const AutocompleteInput = React.forwardRef( const handleInputFocus: FocusEventHandler = useCallback( event => { - onFocus && onFocus(event) - setShowMenu(true) + if (openOnFocus) { + onFocus?.(event) + setShowMenu(true) + } }, - [onFocus, setShowMenu], + [onFocus, setShowMenu, openOnFocus], ) const handleInputBlur: FocusEventHandler = useCallback( From cfd340b8cc9de4f15ab5e58c4df9afbb1d80c7f6 Mon Sep 17 00:00:00 2001 From: Joyce Zhu Date: Thu, 2 May 2024 16:57:27 -0700 Subject: [PATCH 2/6] Add changeset --- .changeset/few-weeks-serve.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/few-weeks-serve.md diff --git a/.changeset/few-weeks-serve.md b/.changeset/few-weeks-serve.md new file mode 100644 index 00000000000..c910b97efa6 --- /dev/null +++ b/.changeset/few-weeks-serve.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Add `openInFocus` prop (default: true) to `AutocompleteInput` From 7f0d519a6ca873c928ff6326b7d7abb65cf1cde1 Mon Sep 17 00:00:00 2001 From: Joyce Zhu Date: Thu, 9 May 2024 23:27:36 -0400 Subject: [PATCH 3/6] Fix JSON formatting --- packages/react/src/Autocomplete/Autocomplete.docs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/Autocomplete/Autocomplete.docs.json b/packages/react/src/Autocomplete/Autocomplete.docs.json index 2ddbe7990db..80da9258ba4 100644 --- a/packages/react/src/Autocomplete/Autocomplete.docs.json +++ b/packages/react/src/Autocomplete/Autocomplete.docs.json @@ -23,7 +23,7 @@ { "name": "openOnFocus", "type": "boolean", - "defaultValue": true, + "defaultValue": "true", "description": "Whether the associated autocomplete menu should open on an input focus event" } ], From b1edc9803ac5dbea903212028277111dae5c78df Mon Sep 17 00:00:00 2001 From: Joyce Zhu Date: Sat, 11 May 2024 02:35:10 -0400 Subject: [PATCH 4/6] Allow up and down to open menu if not already open --- packages/react/src/Autocomplete/AutocompleteInput.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/react/src/Autocomplete/AutocompleteInput.tsx b/packages/react/src/Autocomplete/AutocompleteInput.tsx index 000070615a5..70e6fe17e3a 100644 --- a/packages/react/src/Autocomplete/AutocompleteInput.tsx +++ b/packages/react/src/Autocomplete/AutocompleteInput.tsx @@ -15,6 +15,8 @@ type InternalAutocompleteInputProps = { openOnFocus?: boolean } +const ARROW_KEYS_NAV = new Set(['ArrowUp', 'ArrowDown']) + const AutocompleteInput = React.forwardRef( ( { @@ -99,6 +101,9 @@ const AutocompleteInput = React.forwardRef( setInputValue('') inputRef.current.value = '' } + if (!showMenu && ARROW_KEYS_NAV.has(event.key) && !event.altKey) { + setShowMenu(true) + } }, [inputRef, setInputValue, setHighlightRemainingText, onKeyDown], ) From 98b809da4c29ffdae96c1cccf2fadb78bbbe8ec9 Mon Sep 17 00:00:00 2001 From: Joyce Zhu Date: Sat, 11 May 2024 02:49:56 -0400 Subject: [PATCH 5/6] update hook --- packages/react/src/Autocomplete/AutocompleteInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/Autocomplete/AutocompleteInput.tsx b/packages/react/src/Autocomplete/AutocompleteInput.tsx index 70e6fe17e3a..73305148544 100644 --- a/packages/react/src/Autocomplete/AutocompleteInput.tsx +++ b/packages/react/src/Autocomplete/AutocompleteInput.tsx @@ -105,7 +105,7 @@ const AutocompleteInput = React.forwardRef( setShowMenu(true) } }, - [inputRef, setInputValue, setHighlightRemainingText, onKeyDown], + [inputRef, setInputValue, setHighlightRemainingText, onKeyDown, showMenu], ) const handleInputKeyUp: KeyboardEventHandler = useCallback( From dd7cf2944b2215955b8e9296f1aa8e4dba31ef2d Mon Sep 17 00:00:00 2001 From: Joyce Zhu Date: Mon, 13 May 2024 13:57:56 -0400 Subject: [PATCH 6/6] Update packages/react/src/Autocomplete/AutocompleteInput.tsx Co-authored-by: Kendall Gassner --- packages/react/src/Autocomplete/AutocompleteInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/Autocomplete/AutocompleteInput.tsx b/packages/react/src/Autocomplete/AutocompleteInput.tsx index 73305148544..f114d881aee 100644 --- a/packages/react/src/Autocomplete/AutocompleteInput.tsx +++ b/packages/react/src/Autocomplete/AutocompleteInput.tsx @@ -105,7 +105,7 @@ const AutocompleteInput = React.forwardRef( setShowMenu(true) } }, - [inputRef, setInputValue, setHighlightRemainingText, onKeyDown, showMenu], + [inputRef, setInputValue, setHighlightRemainingText, onKeyDown, showMenu, setShowMenu], ) const handleInputKeyUp: KeyboardEventHandler = useCallback(