animate cancel button in
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, {useLayoutEffect} from 'react'
|
import React, {useEffect, useLayoutEffect} from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Image,
|
Image,
|
||||||
@@ -16,6 +16,9 @@ import Animated, {
|
|||||||
FadeOut,
|
FadeOut,
|
||||||
LayoutAnimationConfig,
|
LayoutAnimationConfig,
|
||||||
LinearTransition,
|
LinearTransition,
|
||||||
|
useAnimatedStyle,
|
||||||
|
useSharedValue,
|
||||||
|
withTiming,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api'
|
import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api'
|
||||||
import {
|
import {
|
||||||
@@ -833,6 +836,26 @@ export function SearchScreen(
|
|||||||
}
|
}
|
||||||
}, [setShowAutocomplete])
|
}, [setShowAutocomplete])
|
||||||
|
|
||||||
|
const cancelWidth = useSharedValue(70)
|
||||||
|
const showCancelBtnAnimation = useSharedValue(0)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (showAutocomplete) {
|
||||||
|
showCancelBtnAnimation.set(withTiming(1))
|
||||||
|
} else {
|
||||||
|
showCancelBtnAnimation.set(withTiming(0))
|
||||||
|
}
|
||||||
|
}, [showAutocomplete, showCancelBtnAnimation])
|
||||||
|
|
||||||
|
const animatedInputContainerStyle = useAnimatedStyle(() => ({
|
||||||
|
marginRight: showCancelBtnAnimation.get() * cancelWidth.get(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const animatedCancelBtnStyle = useAnimatedStyle(() => ({
|
||||||
|
opacity: showCancelBtnAnimation.get(),
|
||||||
|
right: cancelWidth.get() * -1,
|
||||||
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="searchScreen">
|
<Layout.Screen testID="searchScreen">
|
||||||
<View
|
<View
|
||||||
@@ -852,8 +875,8 @@ export function SearchScreen(
|
|||||||
<LayoutAnimationConfig skipEntering skipExiting>
|
<LayoutAnimationConfig skipEntering skipExiting>
|
||||||
{!gtMobile && !showAutocomplete && (
|
{!gtMobile && !showAutocomplete && (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
entering={FadeIn.delay(100).duration(200)}
|
entering={native(FadeIn.delay(100).duration(200))}
|
||||||
exiting={FadeOut.duration(200)}
|
exiting={native(FadeOut.duration(200))}
|
||||||
// HACK: shift up search input. we can't remove the top padding
|
// HACK: shift up search input. we can't remove the top padding
|
||||||
// on the search input because it messes up the layout animation
|
// on the search input because it messes up the layout animation
|
||||||
// if we add it only when the header is hidden
|
// if we add it only when the header is hidden
|
||||||
@@ -881,10 +904,11 @@ export function SearchScreen(
|
|||||||
)}
|
)}
|
||||||
</LayoutAnimationConfig>
|
</LayoutAnimationConfig>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={[a.px_md, a.pt_sm, a.pb_sm, a.gap_sm]}
|
style={[a.px_md, a.pt_sm, a.pb_sm, a.overflow_hidden]}
|
||||||
layout={native(LinearTransition)}>
|
layout={native(LinearTransition)}>
|
||||||
<View style={[a.flex_row, a.gap_xs]}>
|
<Animated.View
|
||||||
<View style={[a.flex_1]}>
|
style={[a.gap_sm, a.relative, animatedInputContainerStyle]}>
|
||||||
|
<View style={[a.w_full]}>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
ref={textInput}
|
ref={textInput}
|
||||||
value={searchText}
|
value={searchText}
|
||||||
@@ -896,40 +920,47 @@ export function SearchScreen(
|
|||||||
hitSlop={{...HITSLOP_20, top: 0}}
|
hitSlop={{...HITSLOP_20, top: 0}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{showAutocomplete && (
|
<Animated.View
|
||||||
<Animated.View entering={FadeIn} exiting={FadeOut}>
|
|
||||||
<Button
|
|
||||||
label={_(msg`Cancel search`)}
|
|
||||||
size="large"
|
|
||||||
variant="ghost"
|
|
||||||
color="secondary"
|
|
||||||
style={[a.px_sm]}
|
|
||||||
onPress={onPressCancelSearch}
|
|
||||||
hitSlop={HITSLOP_10}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Cancel</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
</Animated.View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{showFilters && gtMobile && (
|
|
||||||
<View
|
|
||||||
style={[
|
style={[
|
||||||
a.flex_row,
|
a.absolute,
|
||||||
a.align_center,
|
{top: 0, bottom: 0},
|
||||||
a.justify_between,
|
a.pl_xs,
|
||||||
a.gap_sm,
|
animatedCancelBtnStyle,
|
||||||
]}>
|
!showAutocomplete && a.pointer_events_none,
|
||||||
<View style={[{width: 140}]}>
|
]}
|
||||||
<SearchLanguageDropdown
|
onLayout={evt => cancelWidth.set(evt.nativeEvent.layout.width)}
|
||||||
value={params.lang}
|
aria-hidden={!showAutocomplete}>
|
||||||
onChange={params.setLang}
|
<Button
|
||||||
/>
|
label={_(msg`Cancel search`)}
|
||||||
|
size="large"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
style={[a.px_sm]}
|
||||||
|
onPress={onPressCancelSearch}
|
||||||
|
hitSlop={HITSLOP_10}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Cancel</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</Animated.View>
|
||||||
|
|
||||||
|
{showFilters && gtMobile && (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.flex_row,
|
||||||
|
a.align_center,
|
||||||
|
a.justify_between,
|
||||||
|
a.gap_sm,
|
||||||
|
]}>
|
||||||
|
<View style={[{width: 140}]}>
|
||||||
|
<SearchLanguageDropdown
|
||||||
|
value={params.lang}
|
||||||
|
onChange={params.setLang}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
)}
|
||||||
)}
|
</Animated.View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Layout.Center>
|
</Layout.Center>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
Reference in New Issue
Block a user