From 388c4f79cf47f6f1a7bf5fe5cc4336674930c24a Mon Sep 17 00:00:00 2001 From: Hailey Date: Sun, 28 Apr 2024 21:12:20 -0700 Subject: [PATCH] Increase search `TextInput` hit area and improve the related UI (#3748) * improve hit area of search text input use text cursor on web use a pressable instead use a vertical padding of 9 oops move vertical padding to `TextInput` to increase hit area * Hide it from a11y tree, change cursor * Hide clear on empty text * Render either Clear or Cancel * Remove Clear button * Animate it * Better animation --------- Co-authored-by: Dan Abramov --- src/view/screens/Search/Search.tsx | 104 +++++++++++++++++------------ 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx index 9c148af5..9355c2d6 100644 --- a/src/view/screens/Search/Search.tsx +++ b/src/view/screens/Search/Search.tsx @@ -7,6 +7,13 @@ import { TextInput, View, } from 'react-native' +import Animated, { + FadeIn, + FadeOut, + LinearTransition, + useAnimatedStyle, + withSpring, +} from 'react-native-reanimated' import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api' import { FontAwesomeIcon, @@ -56,6 +63,7 @@ import { } from '#/view/shell/desktop/Search' import {ProfileCardFeedLoadingPlaceholder} from 'view/com/util/LoadingPlaceholder' import {atoms as a} from '#/alf' +const AnimatedPressable = Animated.createAnimatedComponent(Pressable) function Loader() { const pal = usePalette('default') @@ -527,23 +535,10 @@ export function SearchScreen( const onPressCancelSearch = React.useCallback(() => { scrollToTopWeb() - - if (showAutocomplete) { - textInput.current?.blur() - setShowAutocomplete(false) - setSearchText(queryParam) - } else { - // If we just `setParams` and set `q` to an empty string, the URL still displays `q=`, which isn't pretty. - // However, `.replace()` on native has a "push" animation that we don't want. So we need to handle these - // differently. - if (isWeb) { - navigation.replace('Search', {}) - } else { - setSearchText('') - navigation.setParams({q: ''}) - } - } - }, [showAutocomplete, navigation, queryParam]) + textInput.current?.blur() + setShowAutocomplete(false) + setSearchText(queryParam) + }, [queryParam]) const onChangeText = React.useCallback(async (text: string) => { scrollToTopWeb() @@ -629,6 +624,14 @@ export function SearchScreen( ) } + const showClearButton = showAutocomplete && searchText.length > 0 + const clearButtonStyle = useAnimatedStyle(() => ({ + opacity: withSpring(showClearButton ? 1 : 0, { + overshootClamping: true, + duration: 50, + }), + })) + return ( )} - + isWeb && { + // @ts-ignore web only + cursor: 'default', + }, + ]} + onPress={() => { + textInput.current?.focus() + }}> - {showAutocomplete ? ( - - - - ) : undefined} - - - {(queryParam || showAutocomplete) && ( - - + + + + {showAutocomplete && ( + + - + Cancel - + )} @@ -880,6 +899,9 @@ const styles = StyleSheet.create({ }, headerCancelBtn: { paddingLeft: 10, + alignSelf: 'center', + zIndex: -1, + elevation: -1, // For Android }, tabBarContainer: { // @ts-ignore web only