From aa576a1b286ebe727325a941244e6e2f1f52161e Mon Sep 17 00:00:00 2001 From: vineyardbovines Date: Tue, 14 Apr 2026 14:19:23 -0400 Subject: [PATCH] Wire autocomplete into GifPickerHeader Adds `autocomplete` prop (GifAutocompleteState) to GifPickerHeader, restructures layout so suggestions render below the search bar, and wires up keyboard navigation + ARIA attributes for the combobox pattern. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../gifPicker/components/GifPickerHeader.tsx | 100 +++++++++++------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/src/features/gifPicker/components/GifPickerHeader.tsx b/src/features/gifPicker/components/GifPickerHeader.tsx index 19d56cbad0..3b979a15a7 100644 --- a/src/features/gifPicker/components/GifPickerHeader.tsx +++ b/src/features/gifPicker/components/GifPickerHeader.tsx @@ -9,65 +9,87 @@ import * as TextField from '#/components/forms/TextField' import {ArrowLeft_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow' import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass' import {IS_WEB} from '#/env' +import { + GIF_AUTOCOMPLETE_LISTBOX_ID, + GifAutocompleteSuggestions, + suggestionItemId, +} from '#/features/gifPicker/components/GifAutocompleteSuggestions' +import {type GifAutocompleteState} from '#/features/gifPicker/hooks/useGifAutocomplete' export function GifPickerHeader({ inputRef, onChangeText, onClose, onEscape, + autocomplete, }: { inputRef: Ref onChangeText: (text: string) => void onClose: () => void onEscape: () => void + autocomplete: GifAutocompleteState }) { const {_} = useLingui() const t = useTheme() const {gtMobile} = useBreakpoints() return ( - - {!gtMobile && IS_WEB && ( - - )} + + + {!gtMobile && IS_WEB && ( + + )} - - - { - if (nativeEvent.key === 'Escape') { - onEscape() + + + { + if (nativeEvent.key === 'Escape') { + if (!autocomplete.handleKeyDown('Escape')) { + onEscape() + } + } else { + autocomplete.handleKeyDown(nativeEvent.key) + } + }} + // @ts-ignore web-only ARIA props + role={autocomplete.isVisible ? 'combobox' : undefined} + aria-controls={ + autocomplete.isVisible ? GIF_AUTOCOMPLETE_LISTBOX_ID : undefined } - }} - /> - + aria-expanded={autocomplete.isVisible} + aria-autocomplete={autocomplete.isVisible ? 'list' : undefined} + aria-activedescendant={ + autocomplete.isVisible && autocomplete.activeIndex >= 0 + ? suggestionItemId(autocomplete.activeIndex) + : undefined + } + /> + + - {/* future: tabs (Trending / Recents / Categories) render here */} + {autocomplete.isVisible && ( + + )} ) }