use-scroll-animate 10.2.0 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/CHANGELOG.md +35 -0
- package/README.md +67 -0
- package/bin/motionary-mcp.mjs +265 -0
- package/dist/chunks/anim-image-DDdb9q3X.js +166 -0
- package/dist/chunks/anim-image-DDdb9q3X.js.map +1 -0
- package/dist/chunks/anim-image-blQgPFFS.cjs +174 -0
- package/dist/chunks/anim-image-blQgPFFS.cjs.map +1 -0
- package/dist/chunks/audio-BpU-A1m1.cjs.map +1 -1
- package/dist/chunks/{audio-D95jwlOh.js → audio-CWt1xdZB.js} +3 -3
- package/dist/chunks/{audio-D95jwlOh.js.map → audio-CWt1xdZB.js.map} +1 -1
- package/dist/chunks/{base-BnRyfuyM.js → base-BTev8qxg.js} +2 -2
- package/dist/chunks/{base-BnRyfuyM.js.map → base-BTev8qxg.js.map} +1 -1
- package/dist/chunks/base-DBheNxJu.cjs.map +1 -1
- package/dist/chunks/bind-B_CTL6Qn.js.map +1 -1
- package/dist/chunks/bind-Ui43-n2d.cjs.map +1 -1
- package/dist/chunks/builtins-CKKZNR95.cjs.map +1 -1
- package/dist/chunks/{builtins-CqIq1zBv.js → builtins-CPmS6aDB.js} +3 -3
- package/dist/chunks/{builtins-CqIq1zBv.js.map → builtins-CPmS6aDB.js.map} +1 -1
- package/dist/chunks/core-B5T0dhFH.cjs.map +1 -1
- package/dist/chunks/{core-DsGoL9EY.js → core-BviA7nFa.js} +2 -2
- package/dist/chunks/{core-DsGoL9EY.js.map → core-BviA7nFa.js.map} +1 -1
- package/dist/chunks/core-D74Fz-dL.cjs.map +1 -1
- package/dist/chunks/core-D7cVumUu.js.map +1 -1
- package/dist/chunks/{core-XA2yhn1b.js → core-KiM7MXjL.js} +2 -2
- package/dist/chunks/{core-XA2yhn1b.js.map → core-KiM7MXjL.js.map} +1 -1
- package/dist/chunks/core-MQlXZKUG.cjs.map +1 -1
- package/dist/chunks/ease-HwYZnZat.cjs +94 -0
- package/dist/chunks/ease-HwYZnZat.cjs.map +1 -0
- package/dist/chunks/ease-XN8_0sXu.js +89 -0
- package/dist/chunks/ease-XN8_0sXu.js.map +1 -0
- package/dist/chunks/fx-B_pbhpDp.cjs.map +1 -1
- package/dist/chunks/{fx-CtnrFEg9.js → fx-CgWKqVsn.js} +2 -2
- package/dist/chunks/{fx-CtnrFEg9.js.map → fx-CgWKqVsn.js.map} +1 -1
- package/dist/chunks/generative-2LhxG5BJ.js.map +1 -1
- package/dist/chunks/generative-BHIj-NU0.cjs.map +1 -1
- package/dist/chunks/{gpu-CDcXiNA8.js → gpu-BWfgYWMY.js} +2 -2
- package/dist/chunks/{gpu-CDcXiNA8.js.map → gpu-BWfgYWMY.js.map} +1 -1
- package/dist/chunks/gpu-cUixt7kT.cjs.map +1 -1
- package/dist/chunks/index-tags-B-JBecYg.js.map +1 -1
- package/dist/chunks/index-tags-hLIF2Clq.cjs.map +1 -1
- package/dist/chunks/{keyframes-W-474DMc.js → keyframes-B5PWe5bU.js} +3 -2
- package/dist/chunks/keyframes-B5PWe5bU.js.map +1 -0
- package/dist/chunks/{keyframes-ZheOkpt0.cjs → keyframes-tC3I7anQ.cjs} +4 -3
- package/dist/chunks/keyframes-tC3I7anQ.cjs.map +1 -0
- package/dist/chunks/{manifest-D58HXVY-.js → manifest-BHx5yPN6.js} +2 -2
- package/dist/chunks/{manifest-D58HXVY-.js.map → manifest-BHx5yPN6.js.map} +1 -1
- package/dist/chunks/manifest-PaF9B8Vt.cjs.map +1 -1
- package/dist/chunks/{player-48Zy_NBG.js → player-BfHMNtiM.js} +4 -4
- package/dist/chunks/{player-48Zy_NBG.js.map → player-BfHMNtiM.js.map} +1 -1
- package/dist/chunks/player-C4y4jXSv.cjs.map +1 -1
- package/dist/chunks/presets-BYBVJVeP.js.map +1 -1
- package/dist/chunks/presets-CUHys3sK.cjs.map +1 -1
- package/dist/chunks/{registry-gFJRpPES.js → registry-BKzyg1JV.js} +2 -2
- package/dist/chunks/{registry-gFJRpPES.js.map → registry-BKzyg1JV.js.map} +1 -1
- package/dist/chunks/{registry-BIEjKngP.js → registry-CT-TT_bx.js} +3 -3
- package/dist/chunks/{registry-BIEjKngP.js.map → registry-CT-TT_bx.js.map} +1 -1
- package/dist/chunks/{registry-eJgpFAzI.cjs → registry-tzwKkldE.cjs} +2 -2
- package/dist/chunks/{registry-eJgpFAzI.cjs.map → registry-tzwKkldE.cjs.map} +1 -1
- package/dist/chunks/registry-xQZnSqqV.cjs.map +1 -1
- package/dist/chunks/shared-CkKHWrtJ.js.map +1 -1
- package/dist/chunks/shared-jkgRH-Hx.cjs.map +1 -1
- package/dist/chunks/{spring-CZDNyqWp.js → spring-BHuP55DR.js} +2 -2
- package/dist/chunks/{spring-CZDNyqWp.js.map → spring-BHuP55DR.js.map} +1 -1
- package/dist/chunks/spring-BlTQD2AV.cjs.map +1 -1
- package/dist/chunks/stagger-CCFyhzSw.cjs.map +1 -1
- package/dist/chunks/stagger-DtMKo2SK.js.map +1 -1
- package/dist/chunks/{ticker-CM_56oVy.js → ticker-C8lSGml9.js} +2 -2
- package/dist/chunks/{ticker-CM_56oVy.js.map → ticker-C8lSGml9.js.map} +1 -1
- package/dist/chunks/{ticker-D4o6enH0.cjs → ticker-Un0bvTWR.cjs} +2 -2
- package/dist/chunks/{ticker-D4o6enH0.cjs.map → ticker-Un0bvTWR.cjs.map} +1 -1
- package/dist/chunks/{tween-CqX1JBuj.js → tween-BcejKpsx.js} +15 -91
- package/dist/chunks/tween-BcejKpsx.js.map +1 -0
- package/dist/chunks/{tween-CBuWYpI-.cjs → tween-CwLLC3Ko.cjs} +15 -95
- package/dist/chunks/tween-CwLLC3Ko.cjs.map +1 -0
- package/dist/chunks/variants-CrDDJoYK.cjs.map +1 -1
- package/dist/chunks/{variants-GU3yIL4F.js → variants-CsRGUIyA.js} +2 -2
- package/dist/chunks/{variants-GU3yIL4F.js.map → variants-CsRGUIyA.js.map} +1 -1
- package/dist/components/a11y.cjs.map +1 -1
- package/dist/components/a11y.js +2 -2
- package/dist/components/a11y.js.map +1 -1
- package/dist/components/angular.cjs.map +1 -1
- package/dist/components/angular.js +8 -8
- package/dist/components/angular.js.map +1 -1
- package/dist/components/background.cjs.map +1 -1
- package/dist/components/background.js +2 -2
- package/dist/components/background.js.map +1 -1
- package/dist/components/bridge.cjs.map +1 -1
- package/dist/components/bridge.js +1 -1
- package/dist/components/bridge.js.map +1 -1
- package/dist/components/cards.cjs.map +1 -1
- package/dist/components/cards.js +2 -2
- package/dist/components/cards.js.map +1 -1
- package/dist/components/click.cjs.map +1 -1
- package/dist/components/click.js +3 -3
- package/dist/components/click.js.map +1 -1
- package/dist/components/core.cjs.map +1 -1
- package/dist/components/core.js.map +1 -1
- package/dist/components/depth.cjs.map +1 -1
- package/dist/components/depth.js +3 -3
- package/dist/components/depth.js.map +1 -1
- package/dist/components/design.cjs.map +1 -1
- package/dist/components/design.js +3 -3
- package/dist/components/design.js.map +1 -1
- package/dist/components/dsl.cjs.map +1 -1
- package/dist/components/dsl.js +2 -2
- package/dist/components/dsl.js.map +1 -1
- package/dist/components/effects.cjs.map +1 -1
- package/dist/components/effects.js +9 -9
- package/dist/components/effects.js.map +1 -1
- package/dist/components/engine.cjs.map +1 -1
- package/dist/components/engine.js +2 -2
- package/dist/components/engine.js.map +1 -1
- package/dist/components/feedback.cjs.map +1 -1
- package/dist/components/feedback.js +1 -1
- package/dist/components/feedback.js.map +1 -1
- package/dist/components/fx-3d.cjs.map +1 -1
- package/dist/components/fx-3d.js +2 -2
- package/dist/components/fx-3d.js.map +1 -1
- package/dist/components/fx-ai.cjs.map +1 -1
- package/dist/components/fx-ai.js +2 -2
- package/dist/components/fx-ai.js.map +1 -1
- package/dist/components/fx-chart.cjs.map +1 -1
- package/dist/components/fx-chart.js +2 -2
- package/dist/components/fx-chart.js.map +1 -1
- package/dist/components/fx-cinema.cjs.map +1 -1
- package/dist/components/fx-cinema.js +2 -2
- package/dist/components/fx-cinema.js.map +1 -1
- package/dist/components/fx-cyber.cjs.map +1 -1
- package/dist/components/fx-cyber.js +2 -2
- package/dist/components/fx-cyber.js.map +1 -1
- package/dist/components/fx-festival.cjs.map +1 -1
- package/dist/components/fx-festival.js +2 -2
- package/dist/components/fx-festival.js.map +1 -1
- package/dist/components/fx-focus.cjs.map +1 -1
- package/dist/components/fx-focus.js +2 -2
- package/dist/components/fx-focus.js.map +1 -1
- package/dist/components/fx-form.cjs.map +1 -1
- package/dist/components/fx-form.js +2 -2
- package/dist/components/fx-form.js.map +1 -1
- package/dist/components/fx-game.cjs.map +1 -1
- package/dist/components/fx-game.js +2 -2
- package/dist/components/fx-game.js.map +1 -1
- package/dist/components/fx-genart.cjs.map +1 -1
- package/dist/components/fx-genart.js +2 -2
- package/dist/components/fx-genart.js.map +1 -1
- package/dist/components/fx-geo.cjs.map +1 -1
- package/dist/components/fx-geo.js +2 -2
- package/dist/components/fx-geo.js.map +1 -1
- package/dist/components/fx-gesture.cjs.map +1 -1
- package/dist/components/fx-gesture.js +2 -2
- package/dist/components/fx-gesture.js.map +1 -1
- package/dist/components/fx-gpu.js +3 -3
- package/dist/components/fx-light.cjs.map +1 -1
- package/dist/components/fx-light.js +2 -2
- package/dist/components/fx-light.js.map +1 -1
- package/dist/components/fx-lottie.cjs.map +1 -1
- package/dist/components/fx-lottie.js +2 -2
- package/dist/components/fx-lottie.js.map +1 -1
- package/dist/components/fx-morph.cjs.map +1 -1
- package/dist/components/fx-morph.js +2 -2
- package/dist/components/fx-morph.js.map +1 -1
- package/dist/components/fx-music.cjs.map +1 -1
- package/dist/components/fx-music.js +3 -3
- package/dist/components/fx-music.js.map +1 -1
- package/dist/components/fx-organic.cjs.map +1 -1
- package/dist/components/fx-organic.js +2 -2
- package/dist/components/fx-organic.js.map +1 -1
- package/dist/components/fx-paper.cjs.map +1 -1
- package/dist/components/fx-paper.js +2 -2
- package/dist/components/fx-paper.js.map +1 -1
- package/dist/components/fx-perf.cjs.map +1 -1
- package/dist/components/fx-perf.js +2 -2
- package/dist/components/fx-perf.js.map +1 -1
- package/dist/components/fx-physics.cjs.map +1 -1
- package/dist/components/fx-physics.js +2 -2
- package/dist/components/fx-physics.js.map +1 -1
- package/dist/components/fx-retro.cjs.map +1 -1
- package/dist/components/fx-retro.js +2 -2
- package/dist/components/fx-retro.js.map +1 -1
- package/dist/components/fx-safe.cjs.map +1 -1
- package/dist/components/fx-safe.js +2 -2
- package/dist/components/fx-safe.js.map +1 -1
- package/dist/components/fx-shop.cjs.map +1 -1
- package/dist/components/fx-shop.js +2 -2
- package/dist/components/fx-shop.js.map +1 -1
- package/dist/components/fx-social.cjs.map +1 -1
- package/dist/components/fx-social.js +2 -2
- package/dist/components/fx-social.js.map +1 -1
- package/dist/components/fx-spatial.cjs.map +1 -1
- package/dist/components/fx-spatial.js +2 -2
- package/dist/components/fx-spatial.js.map +1 -1
- package/dist/components/fx-surface.cjs.map +1 -1
- package/dist/components/fx-surface.js +2 -2
- package/dist/components/fx-surface.js.map +1 -1
- package/dist/components/fx-text.cjs.map +1 -1
- package/dist/components/fx-text.js +2 -2
- package/dist/components/fx-text.js.map +1 -1
- package/dist/components/fx-transitions.cjs.map +1 -1
- package/dist/components/fx-transitions.js +3 -3
- package/dist/components/fx-transitions.js.map +1 -1
- package/dist/components/fx-video.cjs.map +1 -1
- package/dist/components/fx-video.js +2 -2
- package/dist/components/fx-video.js.map +1 -1
- package/dist/components/fx-weather.cjs.map +1 -1
- package/dist/components/fx-weather.js +2 -2
- package/dist/components/fx-weather.js.map +1 -1
- package/dist/components/fx.cjs.map +1 -1
- package/dist/components/fx.js +6 -6
- package/dist/components/fx.js.map +1 -1
- package/dist/components/fx2.cjs.map +1 -1
- package/dist/components/fx2.js +6 -6
- package/dist/components/fx2.js.map +1 -1
- package/dist/components/gesture.cjs.map +1 -1
- package/dist/components/gesture.js +4 -4
- package/dist/components/gesture.js.map +1 -1
- package/dist/components/interaction.cjs.map +1 -1
- package/dist/components/interaction.js +1 -1
- package/dist/components/interaction.js.map +1 -1
- package/dist/components/layout.cjs.map +1 -1
- package/dist/components/layout.js +1 -1
- package/dist/components/layout.js.map +1 -1
- package/dist/components/lazy.cjs.map +1 -1
- package/dist/components/lazy.js.map +1 -1
- package/dist/components/lite.cjs.map +1 -1
- package/dist/components/lite.js.map +1 -1
- package/dist/components/marketplace.cjs.map +1 -1
- package/dist/components/marketplace.js +4 -4
- package/dist/components/marketplace.js.map +1 -1
- package/dist/components/native.cjs.map +1 -1
- package/dist/components/native.js +3 -3
- package/dist/components/native.js.map +1 -1
- package/dist/components/packs.cjs.map +1 -1
- package/dist/components/packs.js +1 -1
- package/dist/components/packs.js.map +1 -1
- package/dist/components/page.cjs.map +1 -1
- package/dist/components/page.js +3 -3
- package/dist/components/page.js.map +1 -1
- package/dist/components/perf.cjs.map +1 -1
- package/dist/components/perf.js +2 -2
- package/dist/components/perf.js.map +1 -1
- package/dist/components/physics.cjs.map +1 -1
- package/dist/components/physics.js +3 -3
- package/dist/components/physics.js.map +1 -1
- package/dist/components/plugins.cjs.map +1 -1
- package/dist/components/plugins.js +4 -4
- package/dist/components/plugins.js.map +1 -1
- package/dist/components/react.cjs.map +1 -1
- package/dist/components/react.js.map +1 -1
- package/dist/components/reveal.cjs.map +1 -1
- package/dist/components/reveal.js +1 -1
- package/dist/components/reveal.js.map +1 -1
- package/dist/components/solid.cjs.map +1 -1
- package/dist/components/solid.js +8 -8
- package/dist/components/solid.js.map +1 -1
- package/dist/components/svelte.cjs.map +1 -1
- package/dist/components/svelte.js +8 -8
- package/dist/components/svelte.js.map +1 -1
- package/dist/components/svg.cjs.map +1 -1
- package/dist/components/svg.js +1 -1
- package/dist/components/svg.js.map +1 -1
- package/dist/components/text.cjs.map +1 -1
- package/dist/components/text.js +2 -2
- package/dist/components/text.js.map +1 -1
- package/dist/components/timeline.cjs.map +1 -1
- package/dist/components/timeline.js +3 -3
- package/dist/components/timeline.js.map +1 -1
- package/dist/components/tokens.cjs.map +1 -1
- package/dist/components/tokens.js.map +1 -1
- package/dist/components/transitions.cjs.map +1 -1
- package/dist/components/transitions.js +1 -1
- package/dist/components/transitions.js.map +1 -1
- package/dist/components/ui.cjs.map +1 -1
- package/dist/components/ui.js +4 -4
- package/dist/components/ui.js.map +1 -1
- package/dist/components/vue.cjs.map +1 -1
- package/dist/components/vue.js +8 -8
- package/dist/components/vue.js.map +1 -1
- package/dist/components/webgl.cjs.map +1 -1
- package/dist/components/webgl.js +1 -1
- package/dist/components/webgl.js.map +1 -1
- package/dist/components/widgets.cjs +766 -212
- package/dist/components/widgets.cjs.map +1 -1
- package/dist/components/widgets.d.cts +207 -2
- package/dist/components/widgets.d.ts +207 -2
- package/dist/components/widgets.js +770 -221
- package/dist/components/widgets.js.map +1 -1
- package/dist/components.cjs.map +1 -1
- package/dist/components.js +10 -10
- package/dist/components.js.map +1 -1
- package/dist/element.cjs.map +1 -1
- package/dist/element.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +250 -1
- package/dist/llms.txt +13 -2
- package/dist/manifest.json +646 -1
- package/dist/presets/extended.cjs.map +1 -1
- package/dist/presets/extended.js.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.js.map +1 -1
- package/dist/runtime/format-apng.cjs +131 -0
- package/dist/runtime/format-apng.cjs.map +1 -0
- package/dist/runtime/format-apng.d.cts +250 -0
- package/dist/runtime/format-apng.d.ts +250 -0
- package/dist/runtime/format-apng.iife.js +2 -0
- package/dist/runtime/format-apng.iife.js.map +1 -0
- package/dist/runtime/format-apng.js +123 -0
- package/dist/runtime/format-apng.js.map +1 -0
- package/dist/runtime/format-css.cjs +5 -4
- package/dist/runtime/format-css.cjs.map +1 -1
- package/dist/runtime/format-css.js +5 -4
- package/dist/runtime/format-css.js.map +1 -1
- package/dist/runtime/format-gif.cjs +206 -0
- package/dist/runtime/format-gif.cjs.map +1 -0
- package/dist/runtime/format-gif.d.cts +223 -0
- package/dist/runtime/format-gif.d.ts +223 -0
- package/dist/runtime/format-gif.iife.js +2 -0
- package/dist/runtime/format-gif.iife.js.map +1 -0
- package/dist/runtime/format-gif.js +199 -0
- package/dist/runtime/format-gif.js.map +1 -0
- package/dist/runtime/format-motion.cjs +9 -8
- package/dist/runtime/format-motion.cjs.map +1 -1
- package/dist/runtime/format-motion.js +5 -4
- package/dist/runtime/format-motion.js.map +1 -1
- package/dist/runtime/format-sprite.cjs +226 -0
- package/dist/runtime/format-sprite.cjs.map +1 -0
- package/dist/runtime/format-sprite.d.cts +224 -0
- package/dist/runtime/format-sprite.d.ts +224 -0
- package/dist/runtime/format-sprite.iife.js +2 -0
- package/dist/runtime/format-sprite.iife.js.map +1 -0
- package/dist/runtime/format-sprite.js +216 -0
- package/dist/runtime/format-sprite.js.map +1 -0
- package/dist/runtime/format-svg.cjs +5 -4
- package/dist/runtime/format-svg.cjs.map +1 -1
- package/dist/runtime/format-svg.iife.js.map +1 -1
- package/dist/runtime/format-svg.js +4 -3
- package/dist/runtime/format-svg.js.map +1 -1
- package/dist/runtime/format-webp.cjs +123 -0
- package/dist/runtime/format-webp.cjs.map +1 -0
- package/dist/runtime/format-webp.d.cts +245 -0
- package/dist/runtime/format-webp.d.ts +245 -0
- package/dist/runtime/format-webp.iife.js +2 -0
- package/dist/runtime/format-webp.iife.js.map +1 -0
- package/dist/runtime/format-webp.js +115 -0
- package/dist/runtime/format-webp.js.map +1 -0
- package/dist/runtime/scroll.cjs +2 -2
- package/dist/runtime/scroll.cjs.map +1 -1
- package/dist/runtime/scroll.js +2 -2
- package/dist/runtime/scroll.js.map +1 -1
- package/dist/runtime/smooth.cjs +284 -0
- package/dist/runtime/smooth.cjs.map +1 -0
- package/dist/runtime/smooth.d.cts +137 -0
- package/dist/runtime/smooth.d.ts +137 -0
- package/dist/runtime/smooth.iife.js +2 -0
- package/dist/runtime/smooth.iife.js.map +1 -0
- package/dist/runtime/smooth.js +279 -0
- package/dist/runtime/smooth.js.map +1 -0
- package/dist/runtime/text.cjs +147 -0
- package/dist/runtime/text.cjs.map +1 -0
- package/dist/runtime/text.d.cts +65 -0
- package/dist/runtime/text.d.ts +65 -0
- package/dist/runtime/text.iife.js +2 -0
- package/dist/runtime/text.iife.js.map +1 -0
- package/dist/runtime/text.js +143 -0
- package/dist/runtime/text.js.map +1 -0
- package/dist/runtime.cjs +9 -8
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +9 -2
- package/dist/runtime.d.ts +9 -2
- package/dist/runtime.iife.js +1 -1
- package/dist/runtime.iife.js.map +1 -1
- package/dist/runtime.js +6 -5
- package/dist/runtime.js.map +1 -1
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.js.map +1 -1
- package/dist/svelte.cjs.map +1 -1
- package/dist/svelte.js.map +1 -1
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js.map +1 -1
- package/dist/widgets.umd.js +1 -1
- package/dist/widgets.umd.js.map +1 -1
- package/docs/ROADMAP.md +2 -2
- package/docs/components/README.md +12 -7
- package/docs/components/usa-parallax-layers.md +38 -0
- package/docs/components/usa-route-transition.md +38 -0
- package/docs/components/usa-scroll-ring.md +32 -0
- package/docs/components/usa-smooth-scroll.md +60 -0
- package/docs/components/usa-text-splitter.md +60 -0
- package/docs/components.md +94 -0
- package/docs/mcp.md +50 -0
- package/docs/runtime/format-apng.md +59 -0
- package/docs/runtime/format-gif.md +60 -0
- package/docs/runtime/format-sprite.md +60 -0
- package/docs/runtime/format-webp.md +58 -0
- package/docs/runtime/smooth.md +60 -0
- package/docs/runtime/text.md +59 -0
- package/package.json +64 -2
- package/dist/chunks/keyframes-W-474DMc.js.map +0 -1
- package/dist/chunks/keyframes-ZheOkpt0.cjs.map +0 -1
- package/dist/chunks/tween-CBuWYpI-.cjs.map +0 -1
- package/dist/chunks/tween-CqX1JBuj.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smooth.iife.js","sources":["../../src/runtime/smooth.ts","../../src/runtime/iife/smooth.ts"],"sourcesContent":["/**\n * `motionary/runtime/smooth` (10.4) — smooth (inertial) scrolling on the\n * runtime ticker, written for Motionary (own implementation and API).\n *\n * - Wheel / trackpad input is eased towards its target (`lerp` or a fixed\n * `duration` + `ease`) on the shared ticker; keyboard, scrollbar dragging,\n * find-in-page and screen-reader scrolling stay native (the target follows\n * them), touch stays native by default (`touch: true` to smooth it).\n * - Works on the window or inside any scrollable `wrapper`; vertical or\n * horizontal; nested scrollables and `[data-smooth-ignore]` are left alone.\n * - Anchor links (`#id`) glide to their target (with `offset`), focus moves\n * for keyboard users, and the URL hash is kept.\n * - **Off under `prefers-reduced-motion: reduce`** (and while the media query\n * matches; it re-enables when it stops matching) — wheel scrolling is then\n * fully native. `force: true` overrides this only for non-motion use cases.\n * - Real `scroll` events still fire, so `motionary/runtime/scroll` scenes,\n * IntersectionObservers and CSS scroll timelines all keep working.\n * SSR-safe: nothing touches `window` until `smoothScroll()` is called.\n */\nimport { RUNTIME_VERSION, requireModule, type RuntimeModule } from './registry';\nimport type { CoreApi } from './index';\nimport { parseEase, type Ease } from './ease';\n\nexport interface SmoothOptions {\n /** Scroll container (default: the window / document scroller). */\n wrapper?: HTMLElement | Window;\n /** Easing factor per 60 fps frame, 0–1 (default 0.1). Ignored when `duration` is set. */\n lerp?: number;\n /** Fixed glide time in ms (with `ease`) instead of `lerp`. */\n duration?: number;\n ease?: string | Ease;\n orientation?: 'vertical' | 'horizontal';\n /** Wheel delta multiplier (default 1). */\n wheelMultiplier?: number;\n /** Smooth touch scrolling too (default false: native momentum is better on touch devices). */\n touch?: boolean;\n touchMultiplier?: number;\n /** Glide to `#anchor` links (default true). */\n anchors?: boolean | { offset?: number };\n /** Ignore prefers-reduced-motion (default false — leave it off unless the motion is essential). */\n force?: boolean;\n onScroll?: (s: SmoothScroll) => void;\n}\n\nexport interface ScrollToOptions2 {\n offset?: number;\n /** Jump without animating. */\n immediate?: boolean;\n duration?: number;\n ease?: string | Ease;\n onComplete?: () => void;\n}\n\nconst clamp = (v: number, a: number, b: number) => Math.min(b, Math.max(a, v));\nconst instances = new Set<SmoothScroll>();\n\nexport class SmoothScroll {\n /** Current (animated) scroll position, px. */\n current = 0;\n /** Where the scroll is heading, px. */\n target = 0;\n /** px per frame of the last update. */\n velocity = 0;\n /** True while gliding. */\n isScrolling = false;\n private o: SmoothOptions;\n private el: HTMLElement;\n private win: boolean;\n private stopped = false;\n private reduced = false;\n private off: (() => void)[] = [];\n private tickOff: (() => void) | null = null;\n private written = NaN;\n private glide: { from: number; to: number; t: number; d: number; ease: Ease; done?: () => void } | null = null;\n private listeners = new Set<(s: SmoothScroll) => void>();\n private touchY = 0;\n\n constructor(o: SmoothOptions = {}) {\n if (typeof window === 'undefined') throw new Error('[motionary] smoothScroll() needs a browser (call it on the client)');\n this.o = o;\n const w = o.wrapper || window;\n this.win = w === window;\n this.el = this.win ? (document.scrollingElement as HTMLElement) || document.documentElement : (w as HTMLElement);\n if (o.onScroll) this.listeners.add(o.onScroll);\n this.current = this.target = this.native;\n const mq = typeof matchMedia === 'function' ? matchMedia('(prefers-reduced-motion: reduce)') : null;\n const syncMq = () => {\n this.reduced = !!mq?.matches && !o.force;\n this.el.classList.toggle('usa-smooth', !this.reduced && !this.stopped);\n };\n syncMq();\n if (mq) this.on(mq as any, 'change', syncMq);\n const evTarget: EventTarget = this.win ? window : this.el;\n this.on(evTarget, 'wheel', (e: WheelEvent) => this.wheel(e), { passive: false });\n if (o.touch) {\n this.on(evTarget, 'touchstart', (e: TouchEvent) => (this.touchY = this.axis(e.touches[0].clientX, e.touches[0].clientY)), { passive: true });\n this.on(evTarget, 'touchmove', (e: TouchEvent) => {\n if (!this.active || e.touches.length !== 1) return;\n const p = this.axis(e.touches[0].clientX, e.touches[0].clientY);\n e.preventDefault();\n this.push((this.touchY - p) * (o.touchMultiplier ?? 1.5));\n this.touchY = p;\n }, { passive: false });\n }\n // native scrolling (keyboard, scrollbar, find, focus, assistive tech): follow it\n this.on(evTarget, 'scroll', () => {\n if (Math.abs(this.native - this.written) <= 1) return; // our own write (browsers may coalesce several into one event)\n // someone else scrolled (keyboard, scrollbar drag, find, focus): adopt it and drop any glide\n this.halt();\n this.glide = null;\n this.current = this.target = this.native;\n }, { passive: true });\n if (o.anchors !== false) this.on(this.win ? document : this.el, 'click', (e: MouseEvent) => this.anchor(e));\n instances.add(this);\n }\n\n private on(t: EventTarget, type: string, fn: (e: any) => void, opt?: AddEventListenerOptions): void {\n t.addEventListener(type, fn, opt);\n this.off.push(() => t.removeEventListener(type, fn, opt));\n }\n private get horizontal(): boolean {\n return this.o.orientation === 'horizontal';\n }\n private axis(x: number, y: number): number {\n return this.horizontal ? x : y;\n }\n /** The scroll position the browser reports. */\n get native(): number {\n return this.horizontal ? this.el.scrollLeft : this.el.scrollTop;\n }\n /** Maximum scroll, px. */\n get limit(): number {\n return this.horizontal ? this.el.scrollWidth - this.el.clientWidth : this.el.scrollHeight - this.el.clientHeight;\n }\n /** 0–1 */\n get progress(): number {\n return this.limit ? this.current / this.limit : 0;\n }\n /** Smoothing is running (not stopped, not reduced motion). */\n get active(): boolean {\n return !this.stopped && !this.reduced;\n }\n\n private wheel(e: WheelEvent): void {\n if (!this.active || e.ctrlKey) return; // ctrl+wheel = zoom\n // leave nested scrollables / opted-out regions alone\n for (let n = e.target as HTMLElement | null; n && n !== this.el; n = n.parentElement) {\n if (n.hasAttribute?.('data-smooth-ignore')) return;\n if (n !== document.body && n.scrollHeight > n.clientHeight + 1 && /(auto|scroll)/.test(getComputedStyle(n).overflowY)) return;\n }\n const unit = e.deltaMode === 1 ? 40 : e.deltaMode === 2 ? (this.horizontal ? this.el.clientWidth : this.el.clientHeight) : 1;\n const d = (this.horizontal ? e.deltaX || e.deltaY : e.deltaY) * unit * (this.o.wheelMultiplier ?? 1);\n const next = clamp(this.target + d, 0, this.limit);\n if (next === this.target && (this.target <= 0 || this.target >= this.limit)) return; // at an edge: let the page / parent handle it\n e.preventDefault();\n this.push(d);\n }\n private push(d: number): void {\n this.glide = null;\n this.target = clamp(this.target + d, 0, this.limit);\n this.start();\n }\n private start(): void {\n if (this.tickOff) return;\n this.isScrolling = true;\n this.tickOff = requireModule<CoreApi>('core', 'motionary/runtime/smooth').getTicker().add((_, dt) => this.tick(dt));\n }\n private tick(dt: number): void {\n const prev = this.current;\n if (this.glide) {\n const g = this.glide;\n g.t = Math.min(g.d, g.t + dt);\n this.current = g.from + (g.to - g.from) * g.ease(g.d ? g.t / g.d : 1);\n if (g.t >= g.d) {\n this.current = this.target = g.to;\n this.glide = null;\n g.done?.();\n }\n } else if (this.o.duration) {\n this.glide = { from: this.current, to: this.target, t: 0, d: this.o.duration, ease: this.easeOf(this.o.ease) };\n return this.tick(dt);\n } else {\n // frame-rate independent lerp\n const k = 1 - Math.pow(1 - clamp(this.o.lerp ?? 0.1, 0.001, 1), dt / (1000 / 60));\n this.current += (this.target - this.current) * k;\n if (Math.abs(this.target - this.current) < 0.5) this.current = this.target;\n }\n this.velocity = this.current - prev;\n this.write(this.current);\n this.listeners.forEach((f) => f(this));\n if (this.current === this.target && !this.glide) this.halt();\n }\n private easeOf(e?: string | Ease): Ease {\n return typeof e === 'function' ? e : parseEase(e || 'expo-out');\n }\n private write(v: number): void {\n const r = Math.round(v * 100) / 100;\n if (Math.abs(this.native - r) < 0.5) return;\n if (this.horizontal) this.el.scrollLeft = r;\n else this.el.scrollTop = r;\n this.written = this.native; // what the browser actually stored (it may round to device pixels)\n }\n private halt(): void {\n this.tickOff?.();\n this.tickOff = null;\n this.isScrolling = false;\n this.velocity = 0;\n }\n private anchor(e: MouseEvent): void {\n if (e.defaultPrevented || e.button || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n const a = (e.target as Element).closest?.('a[href*=\"#\"]') as HTMLAnchorElement | null;\n if (!a || a.target === '_blank') return;\n const u = new URL(a.href, location.href);\n if (u.origin !== location.origin || u.pathname !== location.pathname || !u.hash) return;\n const id = decodeURIComponent(u.hash.slice(1));\n const t = id === 'top' ? null : document.getElementById(id);\n if (id !== 'top' && !t) return;\n if (!this.win && t && !this.el.contains(t)) return;\n e.preventDefault();\n const off = typeof this.o.anchors === 'object' ? this.o.anchors.offset || 0 : 0;\n this.scrollTo(t || 0, { offset: off, onComplete: () => {\n if (t) {\n if (!t.hasAttribute('tabindex') && !/^(a|button|input|select|textarea)$/i.test(t.tagName)) t.setAttribute('tabindex', '-1');\n t.focus({ preventScroll: true });\n }\n } });\n if (history.pushState) history.pushState(null, '', u.hash);\n }\n\n /** Scroll to a position (px), an element, or a selector. Animated unless reduced motion / `immediate`. */\n scrollTo(to: number | string | Element, o: ScrollToOptions2 = {}): void {\n let y: number;\n if (typeof to === 'number') y = to;\n else {\n const el = typeof to === 'string' ? document.querySelector(to) : to;\n if (!el) return;\n const r = el.getBoundingClientRect();\n const base = this.win ? 0 : this.axis(this.el.getBoundingClientRect().left, this.el.getBoundingClientRect().top);\n y = this.native + this.axis(r.left, r.top) - base;\n }\n y = clamp(y + (o.offset || 0), 0, this.limit);\n if (o.immediate || !this.active) {\n this.halt();\n this.glide = null;\n this.current = this.target = y;\n this.write(y);\n o.onComplete?.();\n return;\n }\n this.target = y;\n this.glide = { from: this.current, to: y, t: 0, d: o.duration ?? this.o.duration ?? Math.min(1200, 400 + Math.abs(y - this.current) * 0.4), ease: this.easeOf(o.ease ?? this.o.ease), done: o.onComplete };\n this.start();\n }\n /** Pause smoothing (native scrolling everywhere) — e.g. while a modal is open. */\n stop(): void {\n this.stopped = true;\n this.halt();\n this.el.classList.remove('usa-smooth');\n }\n /** Resume after `stop()`. */\n resume(): void {\n this.stopped = false;\n this.current = this.target = this.native;\n this.el.classList.toggle('usa-smooth', !this.reduced);\n }\n /** Listen to every smoothed frame; returns an unsubscribe function. */\n onScroll(fn: (s: SmoothScroll) => void): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n /** Remove all listeners and restore native scrolling. */\n destroy(): void {\n this.halt();\n this.off.forEach((f) => f());\n this.off = [];\n this.listeners.clear();\n this.el.classList.remove('usa-smooth');\n instances.delete(this);\n }\n}\n\n/** Start smooth scrolling (see module docs). Off under reduced motion. */\nexport function smoothScroll(o: SmoothOptions = {}): SmoothScroll {\n return new SmoothScroll(o);\n}\n\n/** Every live instance. */\nexport const allSmooth = (): SmoothScroll[] => Array.from(instances);\n\nexport interface SmoothApi {\n smoothScroll: typeof smoothScroll;\n allSmooth: typeof allSmooth;\n SmoothScroll: typeof SmoothScroll;\n}\n\n/** The module object for `use(smooth)`. */\nexport const smooth: RuntimeModule<SmoothApi> = { id: 'smooth', version: RUNTIME_VERSION, requires: ['core'], api: { smoothScroll, allSmooth, SmoothScroll } };\n","// CDN build: load runtime.iife.js first, then this file → registers motionary/runtime/smooth and adds its API to window.MotionaryRuntime.\nimport { register } from '../registry';\nimport { smooth } from '../smooth';\nexport * from '../smooth';\nregister(smooth);\n"],"names":["clamp","v","a","b","Math","min","max","instances","Set","SmoothScroll","constructor","o","this","current","target","velocity","isScrolling","stopped","reduced","off","tickOff","written","NaN","glide","listeners","touchY","window","Error","w","wrapper","win","el","document","scrollingElement","documentElement","onScroll","add","native","mq","matchMedia","syncMq","matches","force","classList","toggle","on","evTarget","e","wheel","passive","touch","axis","touches","clientX","clientY","active","length","p","preventDefault","push","touchMultiplier","abs","halt","anchors","anchor","t","type","fn","opt","addEventListener","removeEventListener","horizontal","orientation","x","y","scrollLeft","scrollTop","limit","scrollWidth","clientWidth","scrollHeight","clientHeight","progress","ctrlKey","n","parentElement","hasAttribute","body","test","getComputedStyle","overflowY","unit","deltaMode","d","deltaX","deltaY","wheelMultiplier","start","requireModule","getTicker","_","dt","tick","prev","g","from","to","ease","done","duration","easeOf","k","pow","lerp","write","forEach","f","parseEase","r","round","defaultPrevented","button","metaKey","shiftKey","altKey","closest","u","URL","href","location","origin","pathname","hash","id","decodeURIComponent","slice","getElementById","contains","offset","scrollTo","onComplete","tagName","setAttribute","focus","preventScroll","history","pushState","querySelector","getBoundingClientRect","base","left","top","immediate","stop","remove","resume","delete","destroy","clear","smoothScroll","allSmooth","Array","smooth","version","RUNTIME_VERSION","requires","api","register"],"mappings":"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"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { R as RUNTIME_VERSION, g as requireModule } from '../chunks/registry-CT-TT_bx.js';
|
|
2
|
+
import { p as parseEase } from '../chunks/ease-XN8_0sXu.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `motionary/runtime/smooth` (10.4) — smooth (inertial) scrolling on the
|
|
6
|
+
* runtime ticker, written for Motionary (own implementation and API).
|
|
7
|
+
*
|
|
8
|
+
* - Wheel / trackpad input is eased towards its target (`lerp` or a fixed
|
|
9
|
+
* `duration` + `ease`) on the shared ticker; keyboard, scrollbar dragging,
|
|
10
|
+
* find-in-page and screen-reader scrolling stay native (the target follows
|
|
11
|
+
* them), touch stays native by default (`touch: true` to smooth it).
|
|
12
|
+
* - Works on the window or inside any scrollable `wrapper`; vertical or
|
|
13
|
+
* horizontal; nested scrollables and `[data-smooth-ignore]` are left alone.
|
|
14
|
+
* - Anchor links (`#id`) glide to their target (with `offset`), focus moves
|
|
15
|
+
* for keyboard users, and the URL hash is kept.
|
|
16
|
+
* - **Off under `prefers-reduced-motion: reduce`** (and while the media query
|
|
17
|
+
* matches; it re-enables when it stops matching) — wheel scrolling is then
|
|
18
|
+
* fully native. `force: true` overrides this only for non-motion use cases.
|
|
19
|
+
* - Real `scroll` events still fire, so `motionary/runtime/scroll` scenes,
|
|
20
|
+
* IntersectionObservers and CSS scroll timelines all keep working.
|
|
21
|
+
* SSR-safe: nothing touches `window` until `smoothScroll()` is called.
|
|
22
|
+
*/
|
|
23
|
+
const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
|
|
24
|
+
const instances = new Set();
|
|
25
|
+
class SmoothScroll {
|
|
26
|
+
constructor(o = {}) {
|
|
27
|
+
/** Current (animated) scroll position, px. */
|
|
28
|
+
this.current = 0;
|
|
29
|
+
/** Where the scroll is heading, px. */
|
|
30
|
+
this.target = 0;
|
|
31
|
+
/** px per frame of the last update. */
|
|
32
|
+
this.velocity = 0;
|
|
33
|
+
/** True while gliding. */
|
|
34
|
+
this.isScrolling = false;
|
|
35
|
+
this.stopped = false;
|
|
36
|
+
this.reduced = false;
|
|
37
|
+
this.off = [];
|
|
38
|
+
this.tickOff = null;
|
|
39
|
+
this.written = NaN;
|
|
40
|
+
this.glide = null;
|
|
41
|
+
this.listeners = new Set();
|
|
42
|
+
this.touchY = 0;
|
|
43
|
+
if (typeof window === 'undefined')
|
|
44
|
+
throw new Error('[motionary] smoothScroll() needs a browser (call it on the client)');
|
|
45
|
+
this.o = o;
|
|
46
|
+
const w = o.wrapper || window;
|
|
47
|
+
this.win = w === window;
|
|
48
|
+
this.el = this.win ? document.scrollingElement || document.documentElement : w;
|
|
49
|
+
if (o.onScroll)
|
|
50
|
+
this.listeners.add(o.onScroll);
|
|
51
|
+
this.current = this.target = this.native;
|
|
52
|
+
const mq = typeof matchMedia === 'function' ? matchMedia('(prefers-reduced-motion: reduce)') : null;
|
|
53
|
+
const syncMq = () => {
|
|
54
|
+
this.reduced = !!mq?.matches && !o.force;
|
|
55
|
+
this.el.classList.toggle('usa-smooth', !this.reduced && !this.stopped);
|
|
56
|
+
};
|
|
57
|
+
syncMq();
|
|
58
|
+
if (mq)
|
|
59
|
+
this.on(mq, 'change', syncMq);
|
|
60
|
+
const evTarget = this.win ? window : this.el;
|
|
61
|
+
this.on(evTarget, 'wheel', (e) => this.wheel(e), { passive: false });
|
|
62
|
+
if (o.touch) {
|
|
63
|
+
this.on(evTarget, 'touchstart', (e) => (this.touchY = this.axis(e.touches[0].clientX, e.touches[0].clientY)), { passive: true });
|
|
64
|
+
this.on(evTarget, 'touchmove', (e) => {
|
|
65
|
+
if (!this.active || e.touches.length !== 1)
|
|
66
|
+
return;
|
|
67
|
+
const p = this.axis(e.touches[0].clientX, e.touches[0].clientY);
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
this.push((this.touchY - p) * (o.touchMultiplier ?? 1.5));
|
|
70
|
+
this.touchY = p;
|
|
71
|
+
}, { passive: false });
|
|
72
|
+
}
|
|
73
|
+
// native scrolling (keyboard, scrollbar, find, focus, assistive tech): follow it
|
|
74
|
+
this.on(evTarget, 'scroll', () => {
|
|
75
|
+
if (Math.abs(this.native - this.written) <= 1)
|
|
76
|
+
return; // our own write (browsers may coalesce several into one event)
|
|
77
|
+
// someone else scrolled (keyboard, scrollbar drag, find, focus): adopt it and drop any glide
|
|
78
|
+
this.halt();
|
|
79
|
+
this.glide = null;
|
|
80
|
+
this.current = this.target = this.native;
|
|
81
|
+
}, { passive: true });
|
|
82
|
+
if (o.anchors !== false)
|
|
83
|
+
this.on(this.win ? document : this.el, 'click', (e) => this.anchor(e));
|
|
84
|
+
instances.add(this);
|
|
85
|
+
}
|
|
86
|
+
on(t, type, fn, opt) {
|
|
87
|
+
t.addEventListener(type, fn, opt);
|
|
88
|
+
this.off.push(() => t.removeEventListener(type, fn, opt));
|
|
89
|
+
}
|
|
90
|
+
get horizontal() {
|
|
91
|
+
return this.o.orientation === 'horizontal';
|
|
92
|
+
}
|
|
93
|
+
axis(x, y) {
|
|
94
|
+
return this.horizontal ? x : y;
|
|
95
|
+
}
|
|
96
|
+
/** The scroll position the browser reports. */
|
|
97
|
+
get native() {
|
|
98
|
+
return this.horizontal ? this.el.scrollLeft : this.el.scrollTop;
|
|
99
|
+
}
|
|
100
|
+
/** Maximum scroll, px. */
|
|
101
|
+
get limit() {
|
|
102
|
+
return this.horizontal ? this.el.scrollWidth - this.el.clientWidth : this.el.scrollHeight - this.el.clientHeight;
|
|
103
|
+
}
|
|
104
|
+
/** 0–1 */
|
|
105
|
+
get progress() {
|
|
106
|
+
return this.limit ? this.current / this.limit : 0;
|
|
107
|
+
}
|
|
108
|
+
/** Smoothing is running (not stopped, not reduced motion). */
|
|
109
|
+
get active() {
|
|
110
|
+
return !this.stopped && !this.reduced;
|
|
111
|
+
}
|
|
112
|
+
wheel(e) {
|
|
113
|
+
if (!this.active || e.ctrlKey)
|
|
114
|
+
return; // ctrl+wheel = zoom
|
|
115
|
+
// leave nested scrollables / opted-out regions alone
|
|
116
|
+
for (let n = e.target; n && n !== this.el; n = n.parentElement) {
|
|
117
|
+
if (n.hasAttribute?.('data-smooth-ignore'))
|
|
118
|
+
return;
|
|
119
|
+
if (n !== document.body && n.scrollHeight > n.clientHeight + 1 && /(auto|scroll)/.test(getComputedStyle(n).overflowY))
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const unit = e.deltaMode === 1 ? 40 : e.deltaMode === 2 ? (this.horizontal ? this.el.clientWidth : this.el.clientHeight) : 1;
|
|
123
|
+
const d = (this.horizontal ? e.deltaX || e.deltaY : e.deltaY) * unit * (this.o.wheelMultiplier ?? 1);
|
|
124
|
+
const next = clamp(this.target + d, 0, this.limit);
|
|
125
|
+
if (next === this.target && (this.target <= 0 || this.target >= this.limit))
|
|
126
|
+
return; // at an edge: let the page / parent handle it
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
this.push(d);
|
|
129
|
+
}
|
|
130
|
+
push(d) {
|
|
131
|
+
this.glide = null;
|
|
132
|
+
this.target = clamp(this.target + d, 0, this.limit);
|
|
133
|
+
this.start();
|
|
134
|
+
}
|
|
135
|
+
start() {
|
|
136
|
+
if (this.tickOff)
|
|
137
|
+
return;
|
|
138
|
+
this.isScrolling = true;
|
|
139
|
+
this.tickOff = requireModule('core', 'motionary/runtime/smooth').getTicker().add((_, dt) => this.tick(dt));
|
|
140
|
+
}
|
|
141
|
+
tick(dt) {
|
|
142
|
+
const prev = this.current;
|
|
143
|
+
if (this.glide) {
|
|
144
|
+
const g = this.glide;
|
|
145
|
+
g.t = Math.min(g.d, g.t + dt);
|
|
146
|
+
this.current = g.from + (g.to - g.from) * g.ease(g.d ? g.t / g.d : 1);
|
|
147
|
+
if (g.t >= g.d) {
|
|
148
|
+
this.current = this.target = g.to;
|
|
149
|
+
this.glide = null;
|
|
150
|
+
g.done?.();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (this.o.duration) {
|
|
154
|
+
this.glide = { from: this.current, to: this.target, t: 0, d: this.o.duration, ease: this.easeOf(this.o.ease) };
|
|
155
|
+
return this.tick(dt);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// frame-rate independent lerp
|
|
159
|
+
const k = 1 - Math.pow(1 - clamp(this.o.lerp ?? 0.1, 0.001, 1), dt / (1000 / 60));
|
|
160
|
+
this.current += (this.target - this.current) * k;
|
|
161
|
+
if (Math.abs(this.target - this.current) < 0.5)
|
|
162
|
+
this.current = this.target;
|
|
163
|
+
}
|
|
164
|
+
this.velocity = this.current - prev;
|
|
165
|
+
this.write(this.current);
|
|
166
|
+
this.listeners.forEach((f) => f(this));
|
|
167
|
+
if (this.current === this.target && !this.glide)
|
|
168
|
+
this.halt();
|
|
169
|
+
}
|
|
170
|
+
easeOf(e) {
|
|
171
|
+
return typeof e === 'function' ? e : parseEase(e || 'expo-out');
|
|
172
|
+
}
|
|
173
|
+
write(v) {
|
|
174
|
+
const r = Math.round(v * 100) / 100;
|
|
175
|
+
if (Math.abs(this.native - r) < 0.5)
|
|
176
|
+
return;
|
|
177
|
+
if (this.horizontal)
|
|
178
|
+
this.el.scrollLeft = r;
|
|
179
|
+
else
|
|
180
|
+
this.el.scrollTop = r;
|
|
181
|
+
this.written = this.native; // what the browser actually stored (it may round to device pixels)
|
|
182
|
+
}
|
|
183
|
+
halt() {
|
|
184
|
+
this.tickOff?.();
|
|
185
|
+
this.tickOff = null;
|
|
186
|
+
this.isScrolling = false;
|
|
187
|
+
this.velocity = 0;
|
|
188
|
+
}
|
|
189
|
+
anchor(e) {
|
|
190
|
+
if (e.defaultPrevented || e.button || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
|
|
191
|
+
return;
|
|
192
|
+
const a = e.target.closest?.('a[href*="#"]');
|
|
193
|
+
if (!a || a.target === '_blank')
|
|
194
|
+
return;
|
|
195
|
+
const u = new URL(a.href, location.href);
|
|
196
|
+
if (u.origin !== location.origin || u.pathname !== location.pathname || !u.hash)
|
|
197
|
+
return;
|
|
198
|
+
const id = decodeURIComponent(u.hash.slice(1));
|
|
199
|
+
const t = id === 'top' ? null : document.getElementById(id);
|
|
200
|
+
if (id !== 'top' && !t)
|
|
201
|
+
return;
|
|
202
|
+
if (!this.win && t && !this.el.contains(t))
|
|
203
|
+
return;
|
|
204
|
+
e.preventDefault();
|
|
205
|
+
const off = typeof this.o.anchors === 'object' ? this.o.anchors.offset || 0 : 0;
|
|
206
|
+
this.scrollTo(t || 0, { offset: off, onComplete: () => {
|
|
207
|
+
if (t) {
|
|
208
|
+
if (!t.hasAttribute('tabindex') && !/^(a|button|input|select|textarea)$/i.test(t.tagName))
|
|
209
|
+
t.setAttribute('tabindex', '-1');
|
|
210
|
+
t.focus({ preventScroll: true });
|
|
211
|
+
}
|
|
212
|
+
} });
|
|
213
|
+
if (history.pushState)
|
|
214
|
+
history.pushState(null, '', u.hash);
|
|
215
|
+
}
|
|
216
|
+
/** Scroll to a position (px), an element, or a selector. Animated unless reduced motion / `immediate`. */
|
|
217
|
+
scrollTo(to, o = {}) {
|
|
218
|
+
let y;
|
|
219
|
+
if (typeof to === 'number')
|
|
220
|
+
y = to;
|
|
221
|
+
else {
|
|
222
|
+
const el = typeof to === 'string' ? document.querySelector(to) : to;
|
|
223
|
+
if (!el)
|
|
224
|
+
return;
|
|
225
|
+
const r = el.getBoundingClientRect();
|
|
226
|
+
const base = this.win ? 0 : this.axis(this.el.getBoundingClientRect().left, this.el.getBoundingClientRect().top);
|
|
227
|
+
y = this.native + this.axis(r.left, r.top) - base;
|
|
228
|
+
}
|
|
229
|
+
y = clamp(y + (o.offset || 0), 0, this.limit);
|
|
230
|
+
if (o.immediate || !this.active) {
|
|
231
|
+
this.halt();
|
|
232
|
+
this.glide = null;
|
|
233
|
+
this.current = this.target = y;
|
|
234
|
+
this.write(y);
|
|
235
|
+
o.onComplete?.();
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
this.target = y;
|
|
239
|
+
this.glide = { from: this.current, to: y, t: 0, d: o.duration ?? this.o.duration ?? Math.min(1200, 400 + Math.abs(y - this.current) * 0.4), ease: this.easeOf(o.ease ?? this.o.ease), done: o.onComplete };
|
|
240
|
+
this.start();
|
|
241
|
+
}
|
|
242
|
+
/** Pause smoothing (native scrolling everywhere) — e.g. while a modal is open. */
|
|
243
|
+
stop() {
|
|
244
|
+
this.stopped = true;
|
|
245
|
+
this.halt();
|
|
246
|
+
this.el.classList.remove('usa-smooth');
|
|
247
|
+
}
|
|
248
|
+
/** Resume after `stop()`. */
|
|
249
|
+
resume() {
|
|
250
|
+
this.stopped = false;
|
|
251
|
+
this.current = this.target = this.native;
|
|
252
|
+
this.el.classList.toggle('usa-smooth', !this.reduced);
|
|
253
|
+
}
|
|
254
|
+
/** Listen to every smoothed frame; returns an unsubscribe function. */
|
|
255
|
+
onScroll(fn) {
|
|
256
|
+
this.listeners.add(fn);
|
|
257
|
+
return () => this.listeners.delete(fn);
|
|
258
|
+
}
|
|
259
|
+
/** Remove all listeners and restore native scrolling. */
|
|
260
|
+
destroy() {
|
|
261
|
+
this.halt();
|
|
262
|
+
this.off.forEach((f) => f());
|
|
263
|
+
this.off = [];
|
|
264
|
+
this.listeners.clear();
|
|
265
|
+
this.el.classList.remove('usa-smooth');
|
|
266
|
+
instances.delete(this);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/** Start smooth scrolling (see module docs). Off under reduced motion. */
|
|
270
|
+
function smoothScroll(o = {}) {
|
|
271
|
+
return new SmoothScroll(o);
|
|
272
|
+
}
|
|
273
|
+
/** Every live instance. */
|
|
274
|
+
const allSmooth = () => Array.from(instances);
|
|
275
|
+
/** The module object for `use(smooth)`. */
|
|
276
|
+
const smooth = { id: 'smooth', version: RUNTIME_VERSION, requires: ['core'], api: { smoothScroll, allSmooth, SmoothScroll } };
|
|
277
|
+
|
|
278
|
+
export { SmoothScroll, allSmooth, smooth, smoothScroll };
|
|
279
|
+
//# sourceMappingURL=smooth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smooth.js","sources":["../../src/runtime/smooth.ts"],"sourcesContent":["/**\n * `motionary/runtime/smooth` (10.4) — smooth (inertial) scrolling on the\n * runtime ticker, written for Motionary (own implementation and API).\n *\n * - Wheel / trackpad input is eased towards its target (`lerp` or a fixed\n * `duration` + `ease`) on the shared ticker; keyboard, scrollbar dragging,\n * find-in-page and screen-reader scrolling stay native (the target follows\n * them), touch stays native by default (`touch: true` to smooth it).\n * - Works on the window or inside any scrollable `wrapper`; vertical or\n * horizontal; nested scrollables and `[data-smooth-ignore]` are left alone.\n * - Anchor links (`#id`) glide to their target (with `offset`), focus moves\n * for keyboard users, and the URL hash is kept.\n * - **Off under `prefers-reduced-motion: reduce`** (and while the media query\n * matches; it re-enables when it stops matching) — wheel scrolling is then\n * fully native. `force: true` overrides this only for non-motion use cases.\n * - Real `scroll` events still fire, so `motionary/runtime/scroll` scenes,\n * IntersectionObservers and CSS scroll timelines all keep working.\n * SSR-safe: nothing touches `window` until `smoothScroll()` is called.\n */\nimport { RUNTIME_VERSION, requireModule, type RuntimeModule } from './registry';\nimport type { CoreApi } from './index';\nimport { parseEase, type Ease } from './ease';\n\nexport interface SmoothOptions {\n /** Scroll container (default: the window / document scroller). */\n wrapper?: HTMLElement | Window;\n /** Easing factor per 60 fps frame, 0–1 (default 0.1). Ignored when `duration` is set. */\n lerp?: number;\n /** Fixed glide time in ms (with `ease`) instead of `lerp`. */\n duration?: number;\n ease?: string | Ease;\n orientation?: 'vertical' | 'horizontal';\n /** Wheel delta multiplier (default 1). */\n wheelMultiplier?: number;\n /** Smooth touch scrolling too (default false: native momentum is better on touch devices). */\n touch?: boolean;\n touchMultiplier?: number;\n /** Glide to `#anchor` links (default true). */\n anchors?: boolean | { offset?: number };\n /** Ignore prefers-reduced-motion (default false — leave it off unless the motion is essential). */\n force?: boolean;\n onScroll?: (s: SmoothScroll) => void;\n}\n\nexport interface ScrollToOptions2 {\n offset?: number;\n /** Jump without animating. */\n immediate?: boolean;\n duration?: number;\n ease?: string | Ease;\n onComplete?: () => void;\n}\n\nconst clamp = (v: number, a: number, b: number) => Math.min(b, Math.max(a, v));\nconst instances = new Set<SmoothScroll>();\n\nexport class SmoothScroll {\n /** Current (animated) scroll position, px. */\n current = 0;\n /** Where the scroll is heading, px. */\n target = 0;\n /** px per frame of the last update. */\n velocity = 0;\n /** True while gliding. */\n isScrolling = false;\n private o: SmoothOptions;\n private el: HTMLElement;\n private win: boolean;\n private stopped = false;\n private reduced = false;\n private off: (() => void)[] = [];\n private tickOff: (() => void) | null = null;\n private written = NaN;\n private glide: { from: number; to: number; t: number; d: number; ease: Ease; done?: () => void } | null = null;\n private listeners = new Set<(s: SmoothScroll) => void>();\n private touchY = 0;\n\n constructor(o: SmoothOptions = {}) {\n if (typeof window === 'undefined') throw new Error('[motionary] smoothScroll() needs a browser (call it on the client)');\n this.o = o;\n const w = o.wrapper || window;\n this.win = w === window;\n this.el = this.win ? (document.scrollingElement as HTMLElement) || document.documentElement : (w as HTMLElement);\n if (o.onScroll) this.listeners.add(o.onScroll);\n this.current = this.target = this.native;\n const mq = typeof matchMedia === 'function' ? matchMedia('(prefers-reduced-motion: reduce)') : null;\n const syncMq = () => {\n this.reduced = !!mq?.matches && !o.force;\n this.el.classList.toggle('usa-smooth', !this.reduced && !this.stopped);\n };\n syncMq();\n if (mq) this.on(mq as any, 'change', syncMq);\n const evTarget: EventTarget = this.win ? window : this.el;\n this.on(evTarget, 'wheel', (e: WheelEvent) => this.wheel(e), { passive: false });\n if (o.touch) {\n this.on(evTarget, 'touchstart', (e: TouchEvent) => (this.touchY = this.axis(e.touches[0].clientX, e.touches[0].clientY)), { passive: true });\n this.on(evTarget, 'touchmove', (e: TouchEvent) => {\n if (!this.active || e.touches.length !== 1) return;\n const p = this.axis(e.touches[0].clientX, e.touches[0].clientY);\n e.preventDefault();\n this.push((this.touchY - p) * (o.touchMultiplier ?? 1.5));\n this.touchY = p;\n }, { passive: false });\n }\n // native scrolling (keyboard, scrollbar, find, focus, assistive tech): follow it\n this.on(evTarget, 'scroll', () => {\n if (Math.abs(this.native - this.written) <= 1) return; // our own write (browsers may coalesce several into one event)\n // someone else scrolled (keyboard, scrollbar drag, find, focus): adopt it and drop any glide\n this.halt();\n this.glide = null;\n this.current = this.target = this.native;\n }, { passive: true });\n if (o.anchors !== false) this.on(this.win ? document : this.el, 'click', (e: MouseEvent) => this.anchor(e));\n instances.add(this);\n }\n\n private on(t: EventTarget, type: string, fn: (e: any) => void, opt?: AddEventListenerOptions): void {\n t.addEventListener(type, fn, opt);\n this.off.push(() => t.removeEventListener(type, fn, opt));\n }\n private get horizontal(): boolean {\n return this.o.orientation === 'horizontal';\n }\n private axis(x: number, y: number): number {\n return this.horizontal ? x : y;\n }\n /** The scroll position the browser reports. */\n get native(): number {\n return this.horizontal ? this.el.scrollLeft : this.el.scrollTop;\n }\n /** Maximum scroll, px. */\n get limit(): number {\n return this.horizontal ? this.el.scrollWidth - this.el.clientWidth : this.el.scrollHeight - this.el.clientHeight;\n }\n /** 0–1 */\n get progress(): number {\n return this.limit ? this.current / this.limit : 0;\n }\n /** Smoothing is running (not stopped, not reduced motion). */\n get active(): boolean {\n return !this.stopped && !this.reduced;\n }\n\n private wheel(e: WheelEvent): void {\n if (!this.active || e.ctrlKey) return; // ctrl+wheel = zoom\n // leave nested scrollables / opted-out regions alone\n for (let n = e.target as HTMLElement | null; n && n !== this.el; n = n.parentElement) {\n if (n.hasAttribute?.('data-smooth-ignore')) return;\n if (n !== document.body && n.scrollHeight > n.clientHeight + 1 && /(auto|scroll)/.test(getComputedStyle(n).overflowY)) return;\n }\n const unit = e.deltaMode === 1 ? 40 : e.deltaMode === 2 ? (this.horizontal ? this.el.clientWidth : this.el.clientHeight) : 1;\n const d = (this.horizontal ? e.deltaX || e.deltaY : e.deltaY) * unit * (this.o.wheelMultiplier ?? 1);\n const next = clamp(this.target + d, 0, this.limit);\n if (next === this.target && (this.target <= 0 || this.target >= this.limit)) return; // at an edge: let the page / parent handle it\n e.preventDefault();\n this.push(d);\n }\n private push(d: number): void {\n this.glide = null;\n this.target = clamp(this.target + d, 0, this.limit);\n this.start();\n }\n private start(): void {\n if (this.tickOff) return;\n this.isScrolling = true;\n this.tickOff = requireModule<CoreApi>('core', 'motionary/runtime/smooth').getTicker().add((_, dt) => this.tick(dt));\n }\n private tick(dt: number): void {\n const prev = this.current;\n if (this.glide) {\n const g = this.glide;\n g.t = Math.min(g.d, g.t + dt);\n this.current = g.from + (g.to - g.from) * g.ease(g.d ? g.t / g.d : 1);\n if (g.t >= g.d) {\n this.current = this.target = g.to;\n this.glide = null;\n g.done?.();\n }\n } else if (this.o.duration) {\n this.glide = { from: this.current, to: this.target, t: 0, d: this.o.duration, ease: this.easeOf(this.o.ease) };\n return this.tick(dt);\n } else {\n // frame-rate independent lerp\n const k = 1 - Math.pow(1 - clamp(this.o.lerp ?? 0.1, 0.001, 1), dt / (1000 / 60));\n this.current += (this.target - this.current) * k;\n if (Math.abs(this.target - this.current) < 0.5) this.current = this.target;\n }\n this.velocity = this.current - prev;\n this.write(this.current);\n this.listeners.forEach((f) => f(this));\n if (this.current === this.target && !this.glide) this.halt();\n }\n private easeOf(e?: string | Ease): Ease {\n return typeof e === 'function' ? e : parseEase(e || 'expo-out');\n }\n private write(v: number): void {\n const r = Math.round(v * 100) / 100;\n if (Math.abs(this.native - r) < 0.5) return;\n if (this.horizontal) this.el.scrollLeft = r;\n else this.el.scrollTop = r;\n this.written = this.native; // what the browser actually stored (it may round to device pixels)\n }\n private halt(): void {\n this.tickOff?.();\n this.tickOff = null;\n this.isScrolling = false;\n this.velocity = 0;\n }\n private anchor(e: MouseEvent): void {\n if (e.defaultPrevented || e.button || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n const a = (e.target as Element).closest?.('a[href*=\"#\"]') as HTMLAnchorElement | null;\n if (!a || a.target === '_blank') return;\n const u = new URL(a.href, location.href);\n if (u.origin !== location.origin || u.pathname !== location.pathname || !u.hash) return;\n const id = decodeURIComponent(u.hash.slice(1));\n const t = id === 'top' ? null : document.getElementById(id);\n if (id !== 'top' && !t) return;\n if (!this.win && t && !this.el.contains(t)) return;\n e.preventDefault();\n const off = typeof this.o.anchors === 'object' ? this.o.anchors.offset || 0 : 0;\n this.scrollTo(t || 0, { offset: off, onComplete: () => {\n if (t) {\n if (!t.hasAttribute('tabindex') && !/^(a|button|input|select|textarea)$/i.test(t.tagName)) t.setAttribute('tabindex', '-1');\n t.focus({ preventScroll: true });\n }\n } });\n if (history.pushState) history.pushState(null, '', u.hash);\n }\n\n /** Scroll to a position (px), an element, or a selector. Animated unless reduced motion / `immediate`. */\n scrollTo(to: number | string | Element, o: ScrollToOptions2 = {}): void {\n let y: number;\n if (typeof to === 'number') y = to;\n else {\n const el = typeof to === 'string' ? document.querySelector(to) : to;\n if (!el) return;\n const r = el.getBoundingClientRect();\n const base = this.win ? 0 : this.axis(this.el.getBoundingClientRect().left, this.el.getBoundingClientRect().top);\n y = this.native + this.axis(r.left, r.top) - base;\n }\n y = clamp(y + (o.offset || 0), 0, this.limit);\n if (o.immediate || !this.active) {\n this.halt();\n this.glide = null;\n this.current = this.target = y;\n this.write(y);\n o.onComplete?.();\n return;\n }\n this.target = y;\n this.glide = { from: this.current, to: y, t: 0, d: o.duration ?? this.o.duration ?? Math.min(1200, 400 + Math.abs(y - this.current) * 0.4), ease: this.easeOf(o.ease ?? this.o.ease), done: o.onComplete };\n this.start();\n }\n /** Pause smoothing (native scrolling everywhere) — e.g. while a modal is open. */\n stop(): void {\n this.stopped = true;\n this.halt();\n this.el.classList.remove('usa-smooth');\n }\n /** Resume after `stop()`. */\n resume(): void {\n this.stopped = false;\n this.current = this.target = this.native;\n this.el.classList.toggle('usa-smooth', !this.reduced);\n }\n /** Listen to every smoothed frame; returns an unsubscribe function. */\n onScroll(fn: (s: SmoothScroll) => void): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n /** Remove all listeners and restore native scrolling. */\n destroy(): void {\n this.halt();\n this.off.forEach((f) => f());\n this.off = [];\n this.listeners.clear();\n this.el.classList.remove('usa-smooth');\n instances.delete(this);\n }\n}\n\n/** Start smooth scrolling (see module docs). Off under reduced motion. */\nexport function smoothScroll(o: SmoothOptions = {}): SmoothScroll {\n return new SmoothScroll(o);\n}\n\n/** Every live instance. */\nexport const allSmooth = (): SmoothScroll[] => Array.from(instances);\n\nexport interface SmoothApi {\n smoothScroll: typeof smoothScroll;\n allSmooth: typeof allSmooth;\n SmoothScroll: typeof SmoothScroll;\n}\n\n/** The module object for `use(smooth)`. */\nexport const smooth: RuntimeModule<SmoothApi> = { id: 'smooth', version: RUNTIME_VERSION, requires: ['core'], api: { smoothScroll, allSmooth, SmoothScroll } };\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var registry = require('../chunks/registry-tzwKkldE.cjs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `motionary/runtime/text` (10.3) — split text into characters, words and
|
|
7
|
+
* lines for animation, keeping it accessible (original implementation).
|
|
8
|
+
*
|
|
9
|
+
* - `segment(text, 'chars' | 'words')` — pure, works anywhere (SSR, workers):
|
|
10
|
+
* grapheme clusters via `Intl.Segmenter` when available (emoji, combining
|
|
11
|
+
* marks, CJK stay whole), whitespace-aware words.
|
|
12
|
+
* - `splitText(el, { type: 'chars,words,lines' })` — wraps the element's text
|
|
13
|
+
* in spans (nested elements such as `<a>`, `<em>` keep their markup), groups
|
|
14
|
+
* words into lines by their rendered position, sets `aria-label` on the
|
|
15
|
+
* element with the original text and hides the pieces from assistive tech.
|
|
16
|
+
* `revert()` restores the original markup; `resplit()` re-measures lines
|
|
17
|
+
* (e.g. after a resize).
|
|
18
|
+
*/
|
|
19
|
+
/** Split a string into graphemes ('chars') or words + whitespace runs ('words'). */
|
|
20
|
+
function segment(text, by = 'chars') {
|
|
21
|
+
const Seg = Intl.Segmenter;
|
|
22
|
+
if (by === 'chars') {
|
|
23
|
+
if (Seg)
|
|
24
|
+
return Array.from(new Seg(undefined, { granularity: 'grapheme' }).segment(text), (s) => s.segment);
|
|
25
|
+
return Array.from(text);
|
|
26
|
+
}
|
|
27
|
+
return text.split(/(\s+)/).filter((s) => s !== '');
|
|
28
|
+
}
|
|
29
|
+
const types = (t) => new Set((t || 'chars,words').split(/[\s,]+/).filter(Boolean));
|
|
30
|
+
/** Split an element's text (see module docs). Needs a DOM. */
|
|
31
|
+
function splitText(el, o = {}) {
|
|
32
|
+
if (typeof document === 'undefined')
|
|
33
|
+
throw new Error('[motionary] splitText needs a DOM — use segment() on the server');
|
|
34
|
+
const want = types(o.type);
|
|
35
|
+
const pre = o.className || 'usa-split';
|
|
36
|
+
const original = el.innerHTML;
|
|
37
|
+
const hadLabel = el.getAttribute('aria-label');
|
|
38
|
+
const text = (el.textContent || '').replace(/\s+/g, ' ').trim();
|
|
39
|
+
const chars = [], words = [];
|
|
40
|
+
const mk = (cls, txt) => {
|
|
41
|
+
const s = document.createElement('span');
|
|
42
|
+
s.className = cls;
|
|
43
|
+
s.setAttribute('aria-hidden', 'true');
|
|
44
|
+
s.style.display = 'inline-block';
|
|
45
|
+
if (txt !== undefined)
|
|
46
|
+
s.textContent = txt;
|
|
47
|
+
return s;
|
|
48
|
+
};
|
|
49
|
+
const wantWords = want.has('words') || want.has('lines');
|
|
50
|
+
const walk = (node) => {
|
|
51
|
+
for (const child of Array.from(node.childNodes)) {
|
|
52
|
+
if (child.nodeType === 3) {
|
|
53
|
+
const frag = document.createDocumentFragment();
|
|
54
|
+
for (const part of segment(child.textContent || '', 'words')) {
|
|
55
|
+
if (/^\s+$/.test(part)) {
|
|
56
|
+
frag.appendChild(document.createTextNode(' '));
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const w = wantWords ? mk(`${pre}-word`) : null;
|
|
60
|
+
if (want.has('chars')) {
|
|
61
|
+
for (const g of segment(part, 'chars')) {
|
|
62
|
+
const c = mk(`${pre}-char`, g);
|
|
63
|
+
chars.push(c);
|
|
64
|
+
(w || frag).appendChild(c);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (w)
|
|
68
|
+
w.textContent = part;
|
|
69
|
+
else
|
|
70
|
+
frag.appendChild(document.createTextNode(part));
|
|
71
|
+
if (w) {
|
|
72
|
+
words.push(w);
|
|
73
|
+
frag.appendChild(w);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
child.replaceWith(frag);
|
|
77
|
+
}
|
|
78
|
+
else if (child.nodeType === 1 && !child.classList.contains(`${pre}-word`))
|
|
79
|
+
walk(child);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
walk(el);
|
|
83
|
+
if (text && hadLabel === null)
|
|
84
|
+
el.setAttribute('aria-label', text);
|
|
85
|
+
el.setAttribute('data-split', Array.from(want).join(' '));
|
|
86
|
+
const lines = [];
|
|
87
|
+
if (want.has('lines') && words.length) {
|
|
88
|
+
// group words by their rendered top; wrap each group in a line span (flat text only)
|
|
89
|
+
let top = NaN, cur = [];
|
|
90
|
+
const groups = [];
|
|
91
|
+
for (const w of words) {
|
|
92
|
+
const t = Math.round(w.offsetTop);
|
|
93
|
+
if (cur.length && Math.abs(t - top) > 2) {
|
|
94
|
+
groups.push(cur);
|
|
95
|
+
cur = [];
|
|
96
|
+
}
|
|
97
|
+
if (!cur.length)
|
|
98
|
+
top = t;
|
|
99
|
+
cur.push(w);
|
|
100
|
+
}
|
|
101
|
+
if (cur.length)
|
|
102
|
+
groups.push(cur);
|
|
103
|
+
const flat = words.every((w) => w.parentElement === el);
|
|
104
|
+
if (flat) {
|
|
105
|
+
el.textContent = '';
|
|
106
|
+
for (const g of groups) {
|
|
107
|
+
const line = mk(`${pre}-line`);
|
|
108
|
+
line.style.display = 'block';
|
|
109
|
+
g.forEach((w, i) => {
|
|
110
|
+
if (i)
|
|
111
|
+
line.appendChild(document.createTextNode(' '));
|
|
112
|
+
line.appendChild(w);
|
|
113
|
+
});
|
|
114
|
+
lines.push(line);
|
|
115
|
+
el.appendChild(line);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else
|
|
119
|
+
groups.forEach((g, i) => g.forEach((w) => w.setAttribute('data-line', String(i))));
|
|
120
|
+
}
|
|
121
|
+
if (o.indexVar !== false)
|
|
122
|
+
for (const list of [chars, words, lines])
|
|
123
|
+
list.forEach((s, i) => s.style.setProperty('--i', String(i)));
|
|
124
|
+
const result = {
|
|
125
|
+
chars,
|
|
126
|
+
words: want.has('words') ? words : [],
|
|
127
|
+
lines,
|
|
128
|
+
revert() {
|
|
129
|
+
el.innerHTML = original;
|
|
130
|
+
el.removeAttribute('data-split');
|
|
131
|
+
if (hadLabel === null)
|
|
132
|
+
el.removeAttribute('aria-label');
|
|
133
|
+
},
|
|
134
|
+
resplit() {
|
|
135
|
+
result.revert();
|
|
136
|
+
return splitText(el, o);
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
/** The module object for `use(text)`. */
|
|
142
|
+
const text = { id: 'text', version: registry.RUNTIME_VERSION, requires: ['core'], api: { segment, splitText } };
|
|
143
|
+
|
|
144
|
+
exports.segment = segment;
|
|
145
|
+
exports.splitText = splitText;
|
|
146
|
+
exports.text = text;
|
|
147
|
+
//# sourceMappingURL=text.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.cjs","sources":["../../src/runtime/text.ts"],"sourcesContent":["/**\n * `motionary/runtime/text` (10.3) — split text into characters, words and\n * lines for animation, keeping it accessible (original implementation).\n *\n * - `segment(text, 'chars' | 'words')` — pure, works anywhere (SSR, workers):\n * grapheme clusters via `Intl.Segmenter` when available (emoji, combining\n * marks, CJK stay whole), whitespace-aware words.\n * - `splitText(el, { type: 'chars,words,lines' })` — wraps the element's text\n * in spans (nested elements such as `<a>`, `<em>` keep their markup), groups\n * words into lines by their rendered position, sets `aria-label` on the\n * element with the original text and hides the pieces from assistive tech.\n * `revert()` restores the original markup; `resplit()` re-measures lines\n * (e.g. after a resize).\n */\nimport { RUNTIME_VERSION, type RuntimeModule } from './registry';\n\nexport type SplitType = 'chars' | 'words' | 'lines';\n\n/** Split a string into graphemes ('chars') or words + whitespace runs ('words'). */\nexport function segment(text: string, by: 'chars' | 'words' = 'chars'): string[] {\n const Seg = (Intl as any).Segmenter;\n if (by === 'chars') {\n if (Seg) return Array.from(new Seg(undefined, { granularity: 'grapheme' }).segment(text), (s: any) => s.segment as string);\n return Array.from(text);\n }\n return text.split(/(\\s+)/).filter((s) => s !== '');\n}\n\nexport interface SplitOptions {\n /** Any of chars, words, lines (comma / space separated). Default 'chars,words'. */\n type?: string;\n /** Class prefix (default 'usa-split'): pieces get `<prefix>-char`, `-word`, `-line`. */\n className?: string;\n /** Set a `--i` custom property (index) on each piece for CSS staggering (default true). */\n indexVar?: boolean;\n}\n\nexport interface SplitResult {\n chars: HTMLElement[];\n words: HTMLElement[];\n lines: HTMLElement[];\n /** Restore the original markup. */\n revert(): void;\n /** Revert and split again (re-measures lines). */\n resplit(): SplitResult;\n}\n\nconst types = (t?: string): Set<SplitType> => new Set((t || 'chars,words').split(/[\\s,]+/).filter(Boolean) as SplitType[]);\n\n/** Split an element's text (see module docs). Needs a DOM. */\nexport function splitText(el: HTMLElement, o: SplitOptions = {}): SplitResult {\n if (typeof document === 'undefined') throw new Error('[motionary] splitText needs a DOM — use segment() on the server');\n const want = types(o.type);\n const pre = o.className || 'usa-split';\n const original = el.innerHTML;\n const hadLabel = el.getAttribute('aria-label');\n const text = (el.textContent || '').replace(/\\s+/g, ' ').trim();\n const chars: HTMLElement[] = [], words: HTMLElement[] = [];\n const mk = (cls: string, txt?: string) => {\n const s = document.createElement('span');\n s.className = cls;\n s.setAttribute('aria-hidden', 'true');\n s.style.display = 'inline-block';\n if (txt !== undefined) s.textContent = txt;\n return s;\n };\n const wantWords = want.has('words') || want.has('lines');\n const walk = (node: Node) => {\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === 3) {\n const frag = document.createDocumentFragment();\n for (const part of segment(child.textContent || '', 'words')) {\n if (/^\\s+$/.test(part)) {\n frag.appendChild(document.createTextNode(' '));\n continue;\n }\n const w = wantWords ? mk(`${pre}-word`) : null;\n if (want.has('chars')) {\n for (const g of segment(part, 'chars')) {\n const c = mk(`${pre}-char`, g);\n chars.push(c);\n (w || frag).appendChild(c);\n }\n } else if (w) w.textContent = part;\n else frag.appendChild(document.createTextNode(part));\n if (w) {\n words.push(w);\n frag.appendChild(w);\n }\n }\n child.replaceWith(frag);\n } else if (child.nodeType === 1 && !(child as Element).classList.contains(`${pre}-word`)) walk(child);\n }\n };\n walk(el);\n if (text && hadLabel === null) el.setAttribute('aria-label', text);\n el.setAttribute('data-split', Array.from(want).join(' '));\n const lines: HTMLElement[] = [];\n if (want.has('lines') && words.length) {\n // group words by their rendered top; wrap each group in a line span (flat text only)\n let top = NaN, cur: HTMLElement[] = [];\n const groups: HTMLElement[][] = [];\n for (const w of words) {\n const t = Math.round(w.offsetTop);\n if (cur.length && Math.abs(t - top) > 2) {\n groups.push(cur);\n cur = [];\n }\n if (!cur.length) top = t;\n cur.push(w);\n }\n if (cur.length) groups.push(cur);\n const flat = words.every((w) => w.parentElement === el);\n if (flat) {\n el.textContent = '';\n for (const g of groups) {\n const line = mk(`${pre}-line`);\n line.style.display = 'block';\n g.forEach((w, i) => {\n if (i) line.appendChild(document.createTextNode(' '));\n line.appendChild(w);\n });\n lines.push(line);\n el.appendChild(line);\n }\n } else groups.forEach((g, i) => g.forEach((w) => w.setAttribute('data-line', String(i))));\n }\n if (o.indexVar !== false) for (const list of [chars, words, lines]) list.forEach((s, i) => s.style.setProperty('--i', String(i)));\n const result: SplitResult = {\n chars,\n words: want.has('words') ? words : [],\n lines,\n revert() {\n el.innerHTML = original;\n el.removeAttribute('data-split');\n if (hadLabel === null) el.removeAttribute('aria-label');\n },\n resplit() {\n result.revert();\n return splitText(el, o);\n },\n };\n return result;\n}\n\nexport interface TextApi {\n segment: typeof segment;\n splitText: typeof splitText;\n}\n\n/** The module object for `use(text)`. */\nexport const text: RuntimeModule<TextApi> = { id: 'text', version: RUNTIME_VERSION, requires: ['core'], api: { segment, splitText } };\n"],"names":["RUNTIME_VERSION"],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** A runtime module: `{ id, version, api }`, registered with `use()`. */
|
|
2
|
+
interface RuntimeModule<A = unknown> {
|
|
3
|
+
/** Module id: 'core', 'format-css', 'scroll', … (import path `motionary/runtime/<id>`). */
|
|
4
|
+
id: string;
|
|
5
|
+
version: string;
|
|
6
|
+
/** Other modules this one needs (registered first by `use()` callers). */
|
|
7
|
+
requires?: string[];
|
|
8
|
+
/** The module's public API (what `requireModule(id)` returns). */
|
|
9
|
+
api: A;
|
|
10
|
+
/** Optional one-time setup, called on first registration. */
|
|
11
|
+
setup?(registry: RuntimeRegistry): void;
|
|
12
|
+
}
|
|
13
|
+
interface RuntimeRegistry {
|
|
14
|
+
version: string;
|
|
15
|
+
modules: Map<string, RuntimeModule>;
|
|
16
|
+
/** Shared per-page state slots (the ticker lives here). */
|
|
17
|
+
slots: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* `motionary/runtime/text` (10.3) — split text into characters, words and
|
|
22
|
+
* lines for animation, keeping it accessible (original implementation).
|
|
23
|
+
*
|
|
24
|
+
* - `segment(text, 'chars' | 'words')` — pure, works anywhere (SSR, workers):
|
|
25
|
+
* grapheme clusters via `Intl.Segmenter` when available (emoji, combining
|
|
26
|
+
* marks, CJK stay whole), whitespace-aware words.
|
|
27
|
+
* - `splitText(el, { type: 'chars,words,lines' })` — wraps the element's text
|
|
28
|
+
* in spans (nested elements such as `<a>`, `<em>` keep their markup), groups
|
|
29
|
+
* words into lines by their rendered position, sets `aria-label` on the
|
|
30
|
+
* element with the original text and hides the pieces from assistive tech.
|
|
31
|
+
* `revert()` restores the original markup; `resplit()` re-measures lines
|
|
32
|
+
* (e.g. after a resize).
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
type SplitType = 'chars' | 'words' | 'lines';
|
|
36
|
+
/** Split a string into graphemes ('chars') or words + whitespace runs ('words'). */
|
|
37
|
+
declare function segment(text: string, by?: 'chars' | 'words'): string[];
|
|
38
|
+
interface SplitOptions {
|
|
39
|
+
/** Any of chars, words, lines (comma / space separated). Default 'chars,words'. */
|
|
40
|
+
type?: string;
|
|
41
|
+
/** Class prefix (default 'usa-split'): pieces get `<prefix>-char`, `-word`, `-line`. */
|
|
42
|
+
className?: string;
|
|
43
|
+
/** Set a `--i` custom property (index) on each piece for CSS staggering (default true). */
|
|
44
|
+
indexVar?: boolean;
|
|
45
|
+
}
|
|
46
|
+
interface SplitResult {
|
|
47
|
+
chars: HTMLElement[];
|
|
48
|
+
words: HTMLElement[];
|
|
49
|
+
lines: HTMLElement[];
|
|
50
|
+
/** Restore the original markup. */
|
|
51
|
+
revert(): void;
|
|
52
|
+
/** Revert and split again (re-measures lines). */
|
|
53
|
+
resplit(): SplitResult;
|
|
54
|
+
}
|
|
55
|
+
/** Split an element's text (see module docs). Needs a DOM. */
|
|
56
|
+
declare function splitText(el: HTMLElement, o?: SplitOptions): SplitResult;
|
|
57
|
+
interface TextApi {
|
|
58
|
+
segment: typeof segment;
|
|
59
|
+
splitText: typeof splitText;
|
|
60
|
+
}
|
|
61
|
+
/** The module object for `use(text)`. */
|
|
62
|
+
declare const text: RuntimeModule<TextApi>;
|
|
63
|
+
|
|
64
|
+
export { segment, splitText, text };
|
|
65
|
+
export type { SplitOptions, SplitResult, SplitType, TextApi };
|