Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 95 lines 2.4 kB view raw
1import {useEffect, useRef, useState} from 'react' 2import {View} from 'react-native' 3import {useReducedMotion} from 'react-native-reanimated' 4 5import {decideShouldRoll} from '#/lib/custom-animations/util' 6 7const animationConfig = { 8 duration: 400, 9 easing: 'cubic-bezier(0.4, 0, 0.2, 1)', 10 fill: 'forwards' as FillMode, 11} 12 13const enteringUpKeyframe = [ 14 {opacity: 0, transform: 'translateY(18px)'}, 15 {opacity: 1, transform: 'translateY(0)'}, 16] 17 18const enteringDownKeyframe = [ 19 {opacity: 0, transform: 'translateY(-18px)'}, 20 {opacity: 1, transform: 'translateY(0)'}, 21] 22 23const exitingUpKeyframe = [ 24 {opacity: 1, transform: 'translateY(0)'}, 25 {opacity: 0, transform: 'translateY(-18px)'}, 26] 27 28const exitingDownKeyframe = [ 29 {opacity: 1, transform: 'translateY(0)'}, 30 {opacity: 0, transform: 'translateY(18px)'}, 31] 32 33export function CountWheel({ 34 count, 35 isToggled, 36 hasBeenToggled, 37 renderCount, 38}: { 39 count: number 40 isToggled: boolean 41 hasBeenToggled: boolean 42 renderCount: (props: {count: number}) => React.ReactNode 43}) { 44 const shouldAnimate = !useReducedMotion() && hasBeenToggled 45 const shouldRoll = decideShouldRoll(isToggled, count) 46 47 const countView = useRef<HTMLDivElement>(null) 48 const prevCountView = useRef<HTMLDivElement>(null) 49 50 const [prevCount, setPrevCount] = useState(count) 51 const prevIsToggled = useRef(isToggled) 52 53 useEffect(() => { 54 if (isToggled === prevIsToggled.current) { 55 return 56 } 57 58 const newPrevCount = isToggled ? count - 1 : count + 1 59 if (shouldAnimate && shouldRoll) { 60 countView.current?.animate?.( 61 isToggled ? enteringUpKeyframe : enteringDownKeyframe, 62 animationConfig, 63 ) 64 prevCountView.current?.animate?.( 65 isToggled ? exitingUpKeyframe : exitingDownKeyframe, 66 animationConfig, 67 ) 68 setPrevCount(newPrevCount) 69 } 70 prevIsToggled.current = isToggled 71 }, [isToggled, count, shouldAnimate, shouldRoll]) 72 73 if (count < 1) { 74 return null 75 } 76 77 return ( 78 <View> 79 <View 80 // @ts-expect-error is div 81 ref={countView}> 82 {renderCount({count})} 83 </View> 84 {shouldAnimate && (count > 1 || !isToggled) ? ( 85 <View 86 style={{position: 'absolute', opacity: 0}} 87 aria-disabled={true} 88 // @ts-expect-error is div 89 ref={prevCountView}> 90 {renderCount({count: prevCount})} 91 </View> 92 ) : null} 93 </View> 94 ) 95}