diff options
Diffstat (limited to 'src/view/com/util/anim/TriggerableAnimated.tsx')
-rw-r--r-- | src/view/com/util/anim/TriggerableAnimated.tsx | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/src/view/com/util/anim/TriggerableAnimated.tsx b/src/view/com/util/anim/TriggerableAnimated.tsx new file mode 100644 index 000000000..2a3cbb957 --- /dev/null +++ b/src/view/com/util/anim/TriggerableAnimated.tsx @@ -0,0 +1,73 @@ +import React from 'react' +import {Animated, StyleProp, View, ViewStyle} from 'react-native' +import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' + +type CreateAnimFn = (interp: Animated.Value) => Animated.CompositeAnimation +type FinishCb = () => void + +interface TriggeredAnimation { + start: CreateAnimFn + style: ( + interp: Animated.Value, + ) => Animated.WithAnimatedValue<StyleProp<ViewStyle>> +} + +export interface TriggerableAnimatedRef { + trigger: (anim: TriggeredAnimation, onFinish?: FinishCb) => void +} + +type TriggerableAnimatedProps = React.PropsWithChildren<{}> + +type PropsInner = TriggerableAnimatedProps & { + anim: TriggeredAnimation + onFinish: () => void +} + +export const TriggerableAnimated = React.forwardRef< + TriggerableAnimatedRef, + TriggerableAnimatedProps +>(({children, ...props}, ref) => { + const [anim, setAnim] = React.useState<TriggeredAnimation | undefined>( + undefined, + ) + const [finishCb, setFinishCb] = React.useState<FinishCb | undefined>( + undefined, + ) + React.useImperativeHandle(ref, () => ({ + trigger(v: TriggeredAnimation, cb?: FinishCb) { + setFinishCb(() => cb) // note- wrap in function due to react behaviors around setstate + setAnim(v) + }, + })) + const onFinish = () => { + finishCb?.() + setAnim(undefined) + setFinishCb(undefined) + } + return ( + <View key="triggerable"> + {anim ? ( + <AnimatingView anim={anim} onFinish={onFinish} {...props}> + {children} + </AnimatingView> + ) : ( + children + )} + </View> + ) +}) + +function AnimatingView({ + anim, + onFinish, + children, +}: React.PropsWithChildren<PropsInner>) { + const interp = useAnimatedValue(0) + React.useEffect(() => { + anim?.start(interp).start(() => { + onFinish() + }) + }) + const animStyle = anim?.style(interp) + return <Animated.View style={animStyle}>{children}</Animated.View> +} |