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) <noreply@anthropic.com>
This commit is contained in:
@@ -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<TextInput>
|
||||
onChangeText: (text: string) => void
|
||||
onClose: () => void
|
||||
onEscape: () => void
|
||||
autocomplete: GifAutocompleteState
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
native(a.pt_4xl),
|
||||
a.relative,
|
||||
a.mb_lg,
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
!gtMobile && web(a.gap_md),
|
||||
a.pb_sm,
|
||||
t.atoms.bg,
|
||||
]}>
|
||||
{!gtMobile && IS_WEB && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="ghost"
|
||||
color="secondary"
|
||||
shape="round"
|
||||
onPress={onClose}
|
||||
label={_(msg`Close GIF dialog`)}>
|
||||
<ButtonIcon icon={Arrow} size="md" />
|
||||
</Button>
|
||||
)}
|
||||
<View style={[native(a.pt_4xl), a.relative, a.mb_lg, a.pb_sm, t.atoms.bg]}>
|
||||
<View style={[a.flex_row, a.align_center, !gtMobile && web(a.gap_md)]}>
|
||||
{!gtMobile && IS_WEB && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="ghost"
|
||||
color="secondary"
|
||||
shape="round"
|
||||
onPress={onClose}
|
||||
label={_(msg`Close GIF dialog`)}>
|
||||
<ButtonIcon icon={Arrow} size="md" />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<TextField.Root style={[!gtMobile && IS_WEB && a.flex_1]}>
|
||||
<TextField.Icon icon={Search} />
|
||||
<TextField.Input
|
||||
label={_(msg`Search GIFs`)}
|
||||
placeholder={_(msg`Search GIFs`)}
|
||||
onChangeText={onChangeText}
|
||||
returnKeyType="search"
|
||||
clearButtonMode="while-editing"
|
||||
inputRef={inputRef}
|
||||
maxLength={50}
|
||||
onKeyPress={({nativeEvent}) => {
|
||||
if (nativeEvent.key === 'Escape') {
|
||||
onEscape()
|
||||
<TextField.Root style={[!gtMobile && IS_WEB && a.flex_1]}>
|
||||
<TextField.Icon icon={Search} />
|
||||
<TextField.Input
|
||||
label={_(msg`Search GIFs`)}
|
||||
placeholder={_(msg`Search GIFs`)}
|
||||
onChangeText={onChangeText}
|
||||
returnKeyType="search"
|
||||
clearButtonMode="while-editing"
|
||||
inputRef={inputRef}
|
||||
maxLength={50}
|
||||
onKeyPress={({nativeEvent}) => {
|
||||
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
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</TextField.Root>
|
||||
aria-expanded={autocomplete.isVisible}
|
||||
aria-autocomplete={autocomplete.isVisible ? 'list' : undefined}
|
||||
aria-activedescendant={
|
||||
autocomplete.isVisible && autocomplete.activeIndex >= 0
|
||||
? suggestionItemId(autocomplete.activeIndex)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</TextField.Root>
|
||||
</View>
|
||||
|
||||
{/* future: tabs (Trending / Recents / Categories) render here */}
|
||||
{autocomplete.isVisible && (
|
||||
<GifAutocompleteSuggestions
|
||||
suggestions={autocomplete.suggestions}
|
||||
activeIndex={autocomplete.activeIndex}
|
||||
onSelect={autocomplete.selectSuggestion}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user