{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "springs", "type": "registry:lib", "title": "Spring Animations", "description": "Spring animation token presets for Framer Motion (fast, moderate, slow).", "files": [ { "path": "packages/ui/src/system/springs.ts", "content": "// Motion tokens. Each tier's value is the ENTER transition — a critically\n// damped spring, except the largest tier which keeps a little bounce. Its\n// `.exit` is the matching EXIT transition — a plain tween, no bounce, one tier\n// quicker — so a dismissal reads as crisp and final rather than replaying the\n// entrance in reverse.\n//\n// transition={spring.fast} // enter\n// exit={{ opacity: 0, transition: spring.fast.exit }} // leave\n//\n// The bigger the thing that moves, the slower the spring. Never hand-write a\n// duration — always reach for a tier.\nexport const spring = {\n fast: {\n type: \"spring\" as const,\n duration: 0.08,\n bounce: 0,\n exit: { duration: 0.06 },\n },\n // Critically damped: same perceived speed as a bouncier tier, but lands\n // exactly with no overshoot — for short travel and panels/sheets that must\n // settle precisely (dropdowns, tabs, drawers, merged selection backgrounds).\n moderate: {\n type: \"spring\" as const,\n duration: 0.16,\n bounce: 0,\n exit: { duration: 0.12 },\n },\n slow: {\n type: \"spring\" as const,\n duration: 0.24,\n bounce: 0.12,\n exit: { duration: 0.16 },\n },\n} as const;\n// Fallback delay (ms) for deferred-unmount timers that guard an exit tween:\n// popups keep their portal mounted until onAnimationComplete fires, but a\n// throttled/background tab can stall the animation, so a timer force-unmounts\n// after the tier's exit duration plus a safety buffer. Deriving it here keeps\n// the timers in step with the tokens above.\nexport const exitFallbackMs = (tier: {\n exit: {\n duration: number;\n };\n}) => Math.round(tier.exit.duration * 1000) + 100;\n", "type": "registry:lib", "target": "lib/springs.ts" } ] }