diff --git a/web/src/hooks/useSpringNumber.ts b/web/src/hooks/useSpringNumber.ts new file mode 100644 index 0000000..0277d12 --- /dev/null +++ b/web/src/hooks/useSpringNumber.ts @@ -0,0 +1,25 @@ +import { useEffect, useState } from "react"; +import { useMotionValueEvent, useSpring } from "motion/react"; +import { useUI } from "../lib/ui"; + +/** + * A number that physically settles into place instead of snapping. + * Returns the live value to render; respects reduced motion. + */ +export function useSpringNumber(target: number, stiffness = 60, damping = 18): number { + const { reduced } = useUI(); + const spring = useSpring(target, { stiffness, damping }); + const [value, setValue] = useState(target); + + useEffect(() => { + if (reduced) { + spring.jump(target); + } else { + spring.set(target); + } + }, [target, reduced, spring]); + + useMotionValueEvent(spring, "change", (v) => setValue(v)); + + return reduced ? target : value; +}