96 lines
2.3 KiB
TypeScript
96 lines
2.3 KiB
TypeScript
import {forwardRef, useCallback, useEffect, useImperativeHandle} from 'react'
|
|
import Animated, {
|
|
Easing,
|
|
useAnimatedProps,
|
|
useSharedValue,
|
|
withDelay,
|
|
withTiming,
|
|
} from 'react-native-reanimated'
|
|
import Svg, {Circle, Path} from 'react-native-svg'
|
|
|
|
import {type Props, useCommonSVGProps} from '#/components/icons/common'
|
|
|
|
const AnimatedPath = Animated.createAnimatedComponent(Path)
|
|
const AnimatedCircle = Animated.createAnimatedComponent(Circle)
|
|
|
|
const PATH = 'M14.1 27.2l7.1 7.2 16.7-16.8'
|
|
|
|
export interface AnimatedCheckRef {
|
|
play(cb?: () => void): void
|
|
}
|
|
|
|
export interface AnimatedCheckProps extends Props {
|
|
playOnMount?: boolean
|
|
}
|
|
|
|
export const AnimatedCheck = forwardRef<AnimatedCheckRef, AnimatedCheckProps>(
|
|
function AnimatedCheck({playOnMount, ...props}, ref) {
|
|
const {fill, size, style, ...rest} = useCommonSVGProps(props)
|
|
const circleAnim = useSharedValue(0)
|
|
const checkAnim = useSharedValue(0)
|
|
|
|
const circleAnimatedProps = useAnimatedProps(() => ({
|
|
strokeDashoffset: 166 - circleAnim.get() * 166,
|
|
}))
|
|
const checkAnimatedProps = useAnimatedProps(() => ({
|
|
strokeDashoffset: 48 - 48 * checkAnim.get(),
|
|
}))
|
|
|
|
const play = useCallback(
|
|
(cb?: () => void) => {
|
|
circleAnim.set(0)
|
|
checkAnim.set(0)
|
|
|
|
circleAnim.set(() =>
|
|
withTiming(1, {duration: 500, easing: Easing.linear}),
|
|
)
|
|
checkAnim.set(() =>
|
|
withDelay(
|
|
500,
|
|
withTiming(1, {duration: 300, easing: Easing.linear}, cb),
|
|
),
|
|
)
|
|
},
|
|
[circleAnim, checkAnim],
|
|
)
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
play,
|
|
}))
|
|
|
|
useEffect(() => {
|
|
if (playOnMount) {
|
|
play()
|
|
}
|
|
}, [play, playOnMount])
|
|
|
|
return (
|
|
<Svg
|
|
fill="none"
|
|
{...rest}
|
|
viewBox="0 0 52 52"
|
|
width={size}
|
|
height={size}
|
|
style={style}>
|
|
<AnimatedCircle
|
|
animatedProps={circleAnimatedProps}
|
|
cx="26"
|
|
cy="26"
|
|
r="24"
|
|
fill="none"
|
|
stroke={fill}
|
|
strokeWidth={4}
|
|
strokeDasharray={166}
|
|
/>
|
|
<AnimatedPath
|
|
animatedProps={checkAnimatedProps}
|
|
stroke={fill}
|
|
d={PATH}
|
|
strokeWidth={4}
|
|
strokeDasharray={48}
|
|
/>
|
|
</Svg>
|
|
)
|
|
},
|
|
)
|