smooth-motion
Version:
React smooth scroll and animation component powered by Framer Motion. Lightweight, fluid, customizable, TypeScript-ready, and perfect for modern web apps and UI design.
1 lines • 4.62 kB
Source Map (JSON)
{"version":3,"sources":["../src/SmoothScroll.tsx","../src/UseSmoothScroll.tsx"],"sourcesContent":["import React, { useRef, useEffect, useState, ReactNode } from \"react\";\r\nimport { motion, useScroll, useSpring, useTransform } from \"framer-motion\";\r\n\r\nexport type SmoothScrollProps = {\r\n children: ReactNode;\r\n stiffness?: number;\r\n damping?: number;\r\n mass?: number;\r\n};\r\n\r\nconst SmoothScroll: React.FC<SmoothScrollProps> = ({\r\n children,\r\n stiffness = 100,\r\n damping = 30,\r\n mass = 1,\r\n}) => {\r\n const scrollRef = useRef<HTMLDivElement | null>(null);\r\n const { scrollY } = useScroll();\r\n const [pageHeight, setPageHeight] = useState(0);\r\n\r\n const smoothY = useSpring(scrollY, { stiffness, damping, mass });\r\n const y = useTransform(smoothY, (val) => -val);\r\n\r\n useEffect(() => {\r\n if (!scrollRef.current) return;\r\n const node = scrollRef.current;\r\n\r\n const setHeight = () => setPageHeight(node.scrollHeight);\r\n setHeight();\r\n\r\n const resizeObserver = new ResizeObserver(setHeight);\r\n resizeObserver.observe(node);\r\n window.addEventListener(\"resize\", setHeight);\r\n\r\n return () => {\r\n resizeObserver.disconnect();\r\n window.removeEventListener(\"resize\", setHeight);\r\n };\r\n }, []);\r\n\r\n return (\r\n <>\r\n <div style={{ height: pageHeight }} />\r\n <motion.div\r\n ref={scrollRef}\r\n style={{ y }}\r\n className=\"fixed top-0 left-0 w-full will-change-transform\"\r\n >\r\n {children}\r\n </motion.div>\r\n </>\r\n );\r\n};\r\n\r\nexport default SmoothScroll;\r\n","import { useEffect } from \"react\";\r\nimport Lenis, { LenisOptions } from \"lenis\";\r\n\r\nexport type UseSmoothScrollProps = {\r\n speed?: number; // user controls scroll speed\r\n};\r\n\r\nconst UseSmoothScroll: React.FC<UseSmoothScrollProps> = ({ speed = 1 }) => {\r\n useEffect(() => {\r\n // Map speed to duration (inverse: higher speed → smaller duration)\r\n const duration = Math.max(0.5, 2 / speed);\r\n\r\n const options: LenisOptions = {\r\n duration,\r\n easing: (t: number) => 1 - Math.pow(1 - t, 3),\r\n // ✅ valid options in latest Lenis:\r\n // duration?: number\r\n // easing?: (t: number) => number\r\n // lerp?: number\r\n // direction?: \"vertical\" | \"horizontal\"\r\n // gestureDirection?: \"vertical\" | \"horizontal\"\r\n // wheelMultiplier?: number\r\n // touchMultiplier?: number\r\n // infinite?: boolean\r\n };\r\n\r\n const lenis = new Lenis(options);\r\n\r\n const animate = (time: number) => {\r\n lenis.raf(time);\r\n requestAnimationFrame(animate);\r\n };\r\n\r\n requestAnimationFrame(animate);\r\n\r\n return () => {\r\n lenis.destroy();\r\n };\r\n }, [speed]);\r\n\r\n return null;\r\n};\r\n\r\nexport default UseSmoothScroll;\r\n"],"mappings":";AAAA,SAAgB,QAAQ,WAAW,gBAA2B;AAC9D,SAAS,QAAQ,WAAW,WAAW,oBAAoB;AAwCnD,mBACI,KADJ;AA/BR,IAAM,eAA4C,CAAC;AAAA,EAC/C;AAAA,EACA,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,OAAO;AACX,MAAM;AACF,QAAM,YAAY,OAA8B,IAAI;AACpD,QAAM,EAAE,QAAQ,IAAI,UAAU;AAC9B,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,CAAC;AAE9C,QAAM,UAAU,UAAU,SAAS,EAAE,WAAW,SAAS,KAAK,CAAC;AAC/D,QAAM,IAAI,aAAa,SAAS,CAAC,QAAQ,CAAC,GAAG;AAE7C,YAAU,MAAM;AACZ,QAAI,CAAC,UAAU,QAAS;AACxB,UAAM,OAAO,UAAU;AAEvB,UAAM,YAAY,MAAM,cAAc,KAAK,YAAY;AACvD,cAAU;AAEV,UAAM,iBAAiB,IAAI,eAAe,SAAS;AACnD,mBAAe,QAAQ,IAAI;AAC3B,WAAO,iBAAiB,UAAU,SAAS;AAE3C,WAAO,MAAM;AACT,qBAAe,WAAW;AAC1B,aAAO,oBAAoB,UAAU,SAAS;AAAA,IAClD;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,SACI,iCACI;AAAA,wBAAC,SAAI,OAAO,EAAE,QAAQ,WAAW,GAAG;AAAA,IACpC;AAAA,MAAC,OAAO;AAAA,MAAP;AAAA,QACG,KAAK;AAAA,QACL,OAAO,EAAE,EAAE;AAAA,QACX,WAAU;AAAA,QAET;AAAA;AAAA,IACL;AAAA,KACJ;AAER;AAEA,IAAO,uBAAQ;;;ACtDf,SAAS,aAAAA,kBAAiB;AAC1B,OAAO,WAA6B;AAMpC,IAAM,kBAAkD,CAAC,EAAE,QAAQ,EAAE,MAAM;AACvE,EAAAA,WAAU,MAAM;AAEZ,UAAM,WAAW,KAAK,IAAI,KAAK,IAAI,KAAK;AAExC,UAAM,UAAwB;AAAA,MAC1B;AAAA,MACA,QAAQ,CAAC,MAAc,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUhD;AAEA,UAAM,QAAQ,IAAI,MAAM,OAAO;AAE/B,UAAM,UAAU,CAAC,SAAiB;AAC9B,YAAM,IAAI,IAAI;AACd,4BAAsB,OAAO;AAAA,IACjC;AAEA,0BAAsB,OAAO;AAE7B,WAAO,MAAM;AACT,YAAM,QAAQ;AAAA,IAClB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AACX;AAEA,IAAO,0BAAQ;","names":["useEffect"]}