import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'
import { useState } from 'react'
import styles from './AnimatedNumber.module.scss'
type AnimatedNumberProps = {
value: number
format?: (value: number) => string
align?: 'center' | 'start'
className?: string
}
const variants = {
initial: (direction: number) => ({ x: direction * 12, opacity: 0 }),
animate: { x: 0, opacity: 1 },
exit: (direction: number) => ({ x: direction * -12, opacity: 0 }),
}
// A quantity stepper's count slides leftward when incrementing (the new
// digit enters from the right, the old one exits to the left) and
// rightward when decrementing.
//
// `direction` is derived from a prop change during render (the React-docs
// "adjusting state when a prop changes" pattern) rather than mutating a ref
// in the render body — mutating a ref here would already reflect the new
// value by the time `exit`'s "custom" is resolved for the outgoing digit,
// so every transition — increment or decrement — read as "forward".
export const AnimatedNumber = ({
value,
format = String,
align = 'center',
className,
}: AnimatedNumberProps) => {
const reduceMotion = useReducedMotion()
const [previousValue, setPreviousValue] = useState(value)
const [direction, setDirection] = useState(1)
if (value !== previousValue) {
setDirection(value > previousValue ? 1 : -1)
setPreviousValue(value)
}
if (reduceMotion) {
return {format(value)}
}
return (
{format(value)}
)
}