forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {forwardRef, useCallback, useEffect, useImperativeHandle} from 'react'
2import Animated, {
3 Easing,
4 useAnimatedProps,
5 useSharedValue,
6 withDelay,
7 withTiming,
8} from 'react-native-reanimated'
9import Svg, {Circle, Path} from 'react-native-svg'
10
11import {type Props, useCommonSVGProps} from '#/components/icons/common'
12
13const AnimatedPath = Animated.createAnimatedComponent(Path)
14const AnimatedCircle = Animated.createAnimatedComponent(Circle)
15
16const PATH = 'M14.1 27.2l7.1 7.2 16.7-16.8'
17
18export interface AnimatedCheckRef {
19 play(cb?: () => void): void
20}
21
22export interface AnimatedCheckProps extends Props {
23 playOnMount?: boolean
24}
25
26export const AnimatedCheck = forwardRef<AnimatedCheckRef, AnimatedCheckProps>(
27 function AnimatedCheck({playOnMount, ...props}, ref) {
28 const {fill, size, style, ...rest} = useCommonSVGProps(props)
29 const circleAnim = useSharedValue(0)
30 const checkAnim = useSharedValue(0)
31
32 const circleAnimatedProps = useAnimatedProps(() => ({
33 strokeDashoffset: 166 - circleAnim.get() * 166,
34 }))
35 const checkAnimatedProps = useAnimatedProps(() => ({
36 strokeDashoffset: 48 - 48 * checkAnim.get(),
37 }))
38
39 const play = useCallback(
40 (cb?: () => void) => {
41 circleAnim.set(0)
42 checkAnim.set(0)
43
44 circleAnim.set(() =>
45 withTiming(1, {duration: 500, easing: Easing.linear}),
46 )
47 checkAnim.set(() =>
48 withDelay(
49 500,
50 withTiming(1, {duration: 300, easing: Easing.linear}, cb),
51 ),
52 )
53 },
54 [circleAnim, checkAnim],
55 )
56
57 useImperativeHandle(ref, () => ({
58 play,
59 }))
60
61 useEffect(() => {
62 if (playOnMount) {
63 play()
64 }
65 }, [play, playOnMount])
66
67 return (
68 <Svg
69 fill="none"
70 {...rest}
71 viewBox="0 0 52 52"
72 width={size}
73 height={size}
74 style={style}>
75 <AnimatedCircle
76 animatedProps={circleAnimatedProps}
77 cx="26"
78 cy="26"
79 r="24"
80 fill="none"
81 stroke={fill}
82 strokeWidth={4}
83 strokeDasharray={166}
84 />
85 <AnimatedPath
86 animatedProps={checkAnimatedProps}
87 stroke={fill}
88 d={PATH}
89 strokeWidth={4}
90 strokeDasharray={48}
91 />
92 </Svg>
93 )
94 },
95)