use-scroll-animate 3.8.0 → 4.0.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/CHANGELOG.md +47 -0
- package/README.md +17 -14
- package/README_ja.md +11 -11
- package/README_zh.md +12 -12
- package/dist/chunks/{base-BpROOcey.js → base-ZARFccur.js} +2 -2
- package/dist/chunks/{base-BpROOcey.js.map → base-ZARFccur.js.map} +1 -1
- package/dist/chunks/core-Co-6AL0h.js +218 -0
- package/dist/chunks/core-Co-6AL0h.js.map +1 -0
- package/dist/chunks/{core-uxs3ETou.js → core-DKY-fVzR.js} +2 -2
- package/dist/chunks/{core-uxs3ETou.js.map → core-DKY-fVzR.js.map} +1 -1
- package/dist/chunks/core-DXqZm5Il.cjs +222 -0
- package/dist/chunks/core-DXqZm5Il.cjs.map +1 -0
- package/dist/chunks/{index-tags-BANJ-e4H.js → index-tags-43Xtd01A.js} +3 -2
- package/dist/chunks/index-tags-43Xtd01A.js.map +1 -0
- package/dist/chunks/{index-tags-wbuPiMR6.cjs → index-tags-BQh_uGqH.cjs} +3 -2
- package/dist/chunks/index-tags-BQh_uGqH.cjs.map +1 -0
- package/dist/chunks/{spring-C-fw7_9f.js → spring-E2ickYNI.js} +2 -2
- package/dist/chunks/{spring-C-fw7_9f.js.map → spring-E2ickYNI.js.map} +1 -1
- package/dist/chunks/{variants-CHe1VbSn.js → variants-DvnxvRCM.js} +2 -2
- package/dist/chunks/{variants-CHe1VbSn.js.map → variants-DvnxvRCM.js.map} +1 -1
- package/dist/components/angular.cjs +3 -1
- package/dist/components/angular.cjs.map +1 -1
- package/dist/components/angular.d.cts +29 -17
- package/dist/components/angular.d.ts +29 -17
- package/dist/components/angular.js +7 -5
- package/dist/components/angular.js.map +1 -1
- package/dist/components/background.js +3 -3
- package/dist/components/cards.js +3 -3
- package/dist/components/click.js +3 -3
- package/dist/components/depth.js +4 -4
- package/dist/components/feedback.js +2 -2
- package/dist/components/gesture.js +5 -5
- package/dist/components/interaction.js +2 -2
- package/dist/components/jsx.d.cts +2 -1
- package/dist/components/jsx.d.ts +2 -1
- package/dist/components/layout.js +2 -2
- package/dist/components/lazy.cjs +2 -1
- package/dist/components/lazy.cjs.map +1 -1
- package/dist/components/lazy.d.cts +2 -1
- package/dist/components/lazy.d.ts +2 -1
- package/dist/components/lazy.js +2 -1
- package/dist/components/lazy.js.map +1 -1
- package/dist/components/packs.cjs +194 -0
- package/dist/components/packs.cjs.map +1 -0
- package/dist/components/packs.css +3 -0
- package/dist/components/packs.d.cts +107 -0
- package/dist/components/packs.d.ts +107 -0
- package/dist/components/packs.js +185 -0
- package/dist/components/packs.js.map +1 -0
- package/dist/components/page.js +3 -3
- package/dist/components/physics.js +4 -4
- package/dist/components/react.cjs +2 -2
- package/dist/components/react.cjs.map +1 -1
- package/dist/components/react.d.cts +1 -1
- package/dist/components/react.d.ts +1 -1
- package/dist/components/react.js +2 -2
- package/dist/components/react.js.map +1 -1
- package/dist/components/reveal.js +2 -2
- package/dist/components/solid.cjs +3 -1
- package/dist/components/solid.cjs.map +1 -1
- package/dist/components/solid.d.cts +29 -17
- package/dist/components/solid.d.ts +29 -17
- package/dist/components/solid.js +7 -5
- package/dist/components/solid.js.map +1 -1
- package/dist/components/svelte.cjs +3 -1
- package/dist/components/svelte.cjs.map +1 -1
- package/dist/components/svelte.d.cts +29 -17
- package/dist/components/svelte.d.ts +29 -17
- package/dist/components/svelte.js +7 -5
- package/dist/components/svelte.js.map +1 -1
- package/dist/components/svg.js +2 -2
- package/dist/components/text.js +2 -2
- package/dist/components/timeline.cjs +6 -219
- package/dist/components/timeline.cjs.map +1 -1
- package/dist/components/timeline.js +5 -217
- package/dist/components/timeline.js.map +1 -1
- package/dist/components/transitions.cjs +7 -120
- package/dist/components/transitions.cjs.map +1 -1
- package/dist/components/transitions.css +0 -1
- package/dist/components/transitions.d.cts +5 -32
- package/dist/components/transitions.d.ts +5 -32
- package/dist/components/transitions.js +10 -121
- package/dist/components/transitions.js.map +1 -1
- package/dist/components/ui.js +5 -5
- package/dist/components/vue.cjs +3 -1
- package/dist/components/vue.cjs.map +1 -1
- package/dist/components/vue.d.cts +29 -17
- package/dist/components/vue.d.ts +29 -17
- package/dist/components/vue.js +7 -5
- package/dist/components/vue.js.map +1 -1
- package/dist/components/webgl.js +2 -2
- package/dist/components.cjs +18 -10
- package/dist/components.cjs.map +1 -1
- package/dist/components.css +1 -1
- package/dist/components.d.cts +67 -33
- package/dist/components.d.ts +67 -33
- package/dist/components.js +14 -10
- package/dist/components.js.map +1 -1
- package/dist/components.umd.js +2 -2
- package/dist/components.umd.js.map +1 -1
- package/dist/index.cjs +5 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -30
- package/dist/index.d.ts +72 -30
- package/dist/index.js +4 -103
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +2 -2
- package/dist/index.umd.js.map +1 -1
- package/docs/API.md +6 -6
- package/docs/ROADMAP.md +14 -0
- package/docs/components.md +16 -4
- package/docs/migration-from-aos.md +1 -1
- package/docs/migration-from-gsap-scrolltrigger.md +6 -6
- package/docs/upgrading-4.md +65 -0
- package/package.json +13 -2
- package/dist/chunks/index-tags-BANJ-e4H.js.map +0 -1
- package/dist/chunks/index-tags-wbuPiMR6.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,53 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.0.0] - 2026-10-07
|
|
11
|
+
|
|
12
|
+
4.0 completes the 3.x release train by consolidating overlapping APIs. Every removal has a drop-in replacement that shipped during 3.x — see **[Upgrading to 4.0](./docs/upgrading-4.md)** (run your app on 3.9 first: it warns once wherever removed APIs are used).
|
|
13
|
+
|
|
14
|
+
### ⚠ Breaking changes
|
|
15
|
+
- **`sequence()` removed** from `use-scroll-animate` → use **`timeline()`**, now also exported from the root entry (`import { timeline } from 'use-scroll-animate'`, `ScrollAnimate.timeline` in the UMD build) alongside `resolvePosition` and `TIMELINE_PRESETS`. `SequenceStep` / `SequenceOptions` / `SequenceController` types removed (use `Timeline`, `TimelineOptions`, `TimelineStepOptions`).
|
|
16
|
+
- **`connectedAnimation()` removed** from `components/transitions` → use **`sharedTransition(update)`** with `data-shared="id"` (`components/layout`; View Transitions API + FLIP fallback). `ConnectedOptions` type removed.
|
|
17
|
+
- **`<usa-flip-list>` / `defineFlipList()` removed** from `components/transitions` → use **`<usa-auto-animate>` / `autoAnimate()`** (`components/layout`), which also animates additions, removals and size changes. `flip()` stays.
|
|
18
|
+
- CDN snippets in docs and the showcase now point at `use-scroll-animate@4`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- The Animation Store's timeline recipe, the vanilla example, README (EN / 中文 / 日本語), API docs and the AOS / GSAP migration guides use `timeline()`.
|
|
22
|
+
- The component gallery's transitions category shows a `flip()` demo instead of the removed helpers.
|
|
23
|
+
|
|
24
|
+
### Docs
|
|
25
|
+
- New **[docs/upgrading-4.md](./docs/upgrading-4.md)** (step-by-step migration with before / after code).
|
|
26
|
+
- New **[docs/ROADMAP.md](./docs/ROADMAP.md)** — the post-4.0 plan (v4.1 → v5.0).
|
|
27
|
+
|
|
28
|
+
### Migration
|
|
29
|
+
| 3.x | 4.0 |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `sequence([{ target: '.a' }, { target: '.b', gap: -200 }], { trigger: '.hero' })` | `timeline().to('.a', 'fade-up').to('.b', 'fade-up', { at: '-=200' })` + play on view / `scrub()` |
|
|
32
|
+
| `connectedAnimation(thumb, detail)` | `sharedTransition(() => { … })` with `data-shared="id"` on both |
|
|
33
|
+
| `<usa-flip-list>` | `<usa-auto-animate>` |
|
|
34
|
+
|
|
35
|
+
npm: **4.0.0 is published as `latest`**; 3.x remains installable as `use-scroll-animate@3`.
|
|
36
|
+
|
|
37
|
+
## [3.9.0] - 2026-10-07
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- **Effect packs** — new category `use-scroll-animate/components/packs`: ready-made motion for whole page types. Mark elements with `data-role` and apply a pack with `<usa-pack name="…">` or `applyPack(name, root)` (returns undo):
|
|
41
|
+
- `ecommerce` — `product` (reveal + lift), `add-to-cart` (press + fly to cart), `cart` (bump), `price` (count up), `badge` (pulse)
|
|
42
|
+
- `portfolio` — `project`, `heading`, `stat`, `contact`
|
|
43
|
+
- `dashboard` — `card`, `stat`, `alert`, `action`
|
|
44
|
+
- `game` — `button`, `score`, `item` (float), `hit` (shake), `reward`
|
|
45
|
+
- `landing` — `hero`, `feature`, `cta`, `logo`, `stat`
|
|
46
|
+
- Helpers: `flyToCart(from, to)` (arc flight + cart bump), `countUp(el)` (keeps currency / separators / decimals, accessible label), `PACKS`, `PACK_PRIMITIVES`.
|
|
47
|
+
- Reduced motion: packs leave content static (numbers show their final value, no flights / pulses / floats).
|
|
48
|
+
- Showcase: new **Effect packs** gallery category with a live demo per pack and a `flyToCart()` demo.
|
|
49
|
+
|
|
50
|
+
### Deprecated (removed in 4.0)
|
|
51
|
+
- `sequence()` → `timeline()` (since 3.1).
|
|
52
|
+
- `connectedAnimation()` → `sharedTransition()` (since 3.6).
|
|
53
|
+
- `<usa-flip-list>` / `defineFlipList()` → `<usa-auto-animate>` / `autoAnimate()` (since 3.6).
|
|
54
|
+
|
|
55
|
+
Each logs a one-time console warning linking to the new **[Upgrading to 4.0](./docs/upgrading-4.md)** guide.
|
|
56
|
+
|
|
10
57
|
## [3.8.0] - 2026-10-07
|
|
11
58
|
|
|
12
59
|
### Added
|
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
**[✨ Live showcase — every effect, live, with copy-paste code](https://harrisoncn.github.io/use-scroll-animate/)** · **[🧩 Component gallery](https://harrisoncn.github.io/use-scroll-animate/showcase/components.html)** · **[🎛 Playground](https://harrisoncn.github.io/use-scroll-animate/showcase/playground.html)**
|
|
14
14
|
|
|
15
|
+
> **4.0** consolidates the API: `timeline()` replaces `sequence()`, `sharedTransition()` replaces `connectedAnimation()`, `<usa-auto-animate>` replaces `<usa-flip-list>` — see [Upgrading to 4.0](./docs/upgrading-4.md) · [Roadmap](./docs/ROADMAP.md).
|
|
16
|
+
|
|
15
17
|
</div>
|
|
16
18
|
|
|
17
19
|
## Why `use-scroll-animate`?
|
|
@@ -37,7 +39,7 @@ defineComponents(); // or per category: import { defineTextComponents } from 'us
|
|
|
37
39
|
|
|
38
40
|
```html
|
|
39
41
|
<!-- or with no build step -->
|
|
40
|
-
<script src="https://unpkg.com/use-scroll-animate@
|
|
42
|
+
<script src="https://unpkg.com/use-scroll-animate@4/dist/components.umd.js"></script>
|
|
41
43
|
<usa-typewriter words="Hello, Windows.|Hello, web."></usa-typewriter>
|
|
42
44
|
<usa-spinner kind="fluent"></usa-spinner>
|
|
43
45
|
```
|
|
@@ -49,7 +51,7 @@ defineComponents(); // or per category: import { defineTextComponents } from 'us
|
|
|
49
51
|
| **Interaction** (`/components/interaction`) | `<usa-ripple>` · `<usa-magnetic>` · `<usa-tilt>` · `<usa-spotlight>` (Fluent reveal highlight) · `<usa-press>` · `<usa-toggle>` |
|
|
50
52
|
| **Loading & feedback** (`/components/feedback`) | `<usa-spinner>` (WinUI ring, Windows dots, ring, dots, pulse, bars) · `<usa-skeleton>` · `<usa-progress>` · `<usa-toaster>` + `toast()` · `<usa-check>` |
|
|
51
53
|
| **Background & decoration** (`/components/background`) | `<usa-aurora>` · `<usa-particles>` · `<usa-grain>` · `<usa-marquee>` · `<usa-acrylic>` (Acrylic / Mica) · `<usa-grid-glow>` · `<usa-blobs>` · `<usa-water-ripple>` · `<usa-dot-network>` · `fluentPreset()` (Mica · Acrylic · Reveal) |
|
|
52
|
-
| **Transitions** (`/components/transitions`) | `<usa-dialog>` (modal / drawer / sheet) · `<usa-accordion>` · `<usa-
|
|
54
|
+
| **Transitions** (`/components/transitions`) | `<usa-dialog>` (modal / drawer / sheet) · `<usa-accordion>` · `<usa-view-switch>` · `viewTransition()` · `flip()` |
|
|
53
55
|
| **Spring & physics** (`/components/physics`) | `<usa-spring>` (bounce-in · pop · drop · jelly · rubber-band) · `<usa-draggable>` (spring-back · inertia · snap) · `<usa-overscroll>` · `spring()` · `createSpring()` · `SPRING_PRESETS` |
|
|
54
56
|
| **Card effects** (`/components/cards`) | `<usa-card>` (flip · holo · glass · border-glow · conic-border · lift · spotlight · sheen · parallax-layers · expand — combinable) · `<usa-card-stack>` (swipe) · `<usa-sticky-stack>` · `<usa-carousel-3d>` |
|
|
55
57
|
| **Click & tap** (`/components/click`) | `<usa-button>` **button click deformation** (squash · wobble · gooey · dent · shape morph · submit→loading→success) · `<usa-icon-morph>` · `<usa-click>` (ripple · burst · confetti · squish · press-spring · shake) · `<usa-like>` · `<usa-hold>` · `<usa-double-tap>` · `<usa-checkbox>` · `confetti()` · `haptic()` |
|
|
@@ -61,6 +63,7 @@ defineComponents(); // or per category: import { defineTextComponents } from 'us
|
|
|
61
63
|
| **Canvas & WebGL** (`/components/webgl`) | `<usa-shader>` (gradient · plasma · waves · aurora · custom GLSL) · `<usa-distort>` · `<usa-liquid>` · `glQuad()` — graceful fallback |
|
|
62
64
|
| **3D & depth** (`/components/depth`) | `<usa-cube>` · `<usa-depth>` (pointer · gyroscope · scroll depth parallax) · `deviceTilt()` · (+ `<usa-carousel-3d>` in cards) |
|
|
63
65
|
| **Layout animation** (`/components/layout`) | `<usa-auto-animate>` / `autoAnimate()` (list & grid reflow) · `<usa-masonry>` · `sharedTransition()` (shared elements) |
|
|
66
|
+
| **Effect packs** (`/components/packs`) | `<usa-pack>` (`name="ecommerce \| portfolio \| dashboard \| game \| landing"`) · `applyPack()` · `flyToCart()` · `countUp()` |
|
|
64
67
|
|
|
65
68
|
Whole bundle ≈ 22 kB gzip (JS + CSS); one category 3.5–6.4 kB; a single component ≈ 2 kB. The scroll-animation core below is unaffected.
|
|
66
69
|
|
|
@@ -108,7 +111,7 @@ Notes:
|
|
|
108
111
|
- With the native engine, `duration`, `delay`, `threshold`, `offset` and `stagger` don't apply; the animation spans `viewRange` (default `['entry 0%', 'entry 100%']`, i.e. from the moment the element starts entering until it is fully in view). `easing` still applies.
|
|
109
112
|
- `once` (default) freezes the end state when the animation completes, so scrolling back up does not reverse it; with `repeat: true` it keeps following the scroll in both directions.
|
|
110
113
|
- Callbacks (`onEnter`, `onLeave`, `onStart`, `onComplete`), `onProgress`, `progressVar` and `parallax` keep working.
|
|
111
|
-
- Class-name mode (`useClassNames`), `prefers-reduced-motion`, `animate()`, `
|
|
114
|
+
- Class-name mode (`useClassNames`), `prefers-reduced-motion`, `animate()`, `timeline()` and `staggerChildren()` always use the JS engine.
|
|
112
115
|
- `supportsScrollTimeline()` is exported if you want to branch on support yourself.
|
|
113
116
|
|
|
114
117
|
## v1.4.0 New Features ✨
|
|
@@ -136,21 +139,21 @@ const stop = staggerChildren(document.querySelector('#feed'), {
|
|
|
136
139
|
// later: stop();
|
|
137
140
|
```
|
|
138
141
|
|
|
139
|
-
### Timelines with `
|
|
140
|
-
Chain animations across elements. Each step starts when the previous one ends; `
|
|
142
|
+
### Timelines with `timeline()`
|
|
143
|
+
Chain animations across elements on one playhead. Each step starts when the previous one ends; `at` overlaps (`'-=300'`), waits (`'+=200'`), aligns with the previous step (`'<'`), jumps to a label or an absolute time. Play it, reverse it, seek it, or scrub it with scroll. (Replaces `sequence()`, removed in 4.0 — see [upgrading-4.md](./docs/upgrading-4.md).)
|
|
141
144
|
|
|
142
145
|
```js
|
|
143
|
-
import {
|
|
146
|
+
import { timeline } from 'use-scroll-animate';
|
|
144
147
|
|
|
145
|
-
const tl =
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
], { trigger: '.hero', easing: 'soft-spring' }); // auto-plays once when .hero enters
|
|
148
|
+
const tl = timeline({ defaults: { duration: 700 } })
|
|
149
|
+
.to('.hero h1', 'fade-up')
|
|
150
|
+
.to('.hero p', 'blur', { at: '-=300' })
|
|
151
|
+
.to('.hero .btn', 'scale', { stagger: 80 });
|
|
150
152
|
|
|
151
|
-
await tl.play();
|
|
152
|
-
tl.
|
|
153
|
+
await tl.play(); // resolves at the end
|
|
154
|
+
tl.scrub(document.querySelector('.hero')); // or tie progress to scroll
|
|
153
155
|
```
|
|
156
|
+
Declaratively: `<usa-timeline>` with `data-tl="fade-up"` children (`use-scroll-animate/components/timeline`).
|
|
154
157
|
|
|
155
158
|
### New presets
|
|
156
159
|
`scale-up`, `blur-in-up`, `flip-up`, `flip-down`, `rotate-left`, `rotate-right`, and clip-path reveals `clip-up`, `clip-down`, `clip-left`, `clip-right`, `clip-circle`.
|
|
@@ -310,7 +313,7 @@ ScrollAnimate.destroy(); // disconnect everything
|
|
|
310
313
|
const sa = createScrollAnimate({ root: document.querySelector('#scroller') }); // isolated instance
|
|
311
314
|
|
|
312
315
|
// Helpers (tree-shakeable)
|
|
313
|
-
import {
|
|
316
|
+
import { timeline, staggerChildren, getScrollProgress } from 'use-scroll-animate';
|
|
314
317
|
```
|
|
315
318
|
|
|
316
319
|
### Watching the DOM (`watch()`)
|
package/README_ja.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
`use-scroll-animate` は違います:
|
|
20
20
|
- ⚡ **依存関係なし**:純粋な Vanilla JS/TypeScript。
|
|
21
21
|
- 🚀 **高パフォーマンス**:`IntersectionObserver` とネイティブの `Web Animations API` で駆動。デフォルトではスクロールイベントリスナーなし(オプトインのスクロール進捗モードは、対象要素が画面内にある間だけ passive・rAF スロットルのリスナーを1つ使用)、レイアウトスラッシングなし。
|
|
22
|
-
- 🪶 **超軽量**:Gzip後コア約4.8KB(`
|
|
22
|
+
- 🪶 **超軽量**:Gzip後コア約4.8KB(`timeline`・`staggerChildren`・React/Vue ヘルパーを含む全体で約6.1KB)。
|
|
23
23
|
- 🧩 **フレームワークに依存しない**:Vanilla JS、React、Vue、Svelteなどとシームレスに動作。一流の React Hooks と Vue Composables を内蔵。
|
|
24
24
|
- ♿ **アクセシブル**:`prefers-reduced-motion` を標準でサポート。
|
|
25
25
|
|
|
@@ -39,7 +39,7 @@ defineComponents(); // カテゴリ単位: import { defineTextComponents } from
|
|
|
39
39
|
| **インタラクション**(`/components/interaction`) | `<usa-ripple>` · `<usa-magnetic>` · `<usa-tilt>` · `<usa-spotlight>`(Fluent Reveal)· `<usa-press>` · `<usa-toggle>` |
|
|
40
40
|
| **ローディング・フィードバック**(`/components/feedback`) | `<usa-spinner>` · `<usa-skeleton>` · `<usa-progress>` · `<usa-toaster>` + `toast()` · `<usa-check>` |
|
|
41
41
|
| **背景・装飾**(`/components/background`) | `<usa-aurora>` · `<usa-particles>` · `<usa-grain>` · `<usa-marquee>` · `<usa-acrylic>`(Acrylic / Mica) · `<usa-grid-glow>` · `<usa-blobs>` · `<usa-water-ripple>` · `<usa-dot-network>` · `fluentPreset()` |
|
|
42
|
-
| **トランジション**(`/components/transitions`) | `<usa-dialog>` · `<usa-accordion>` · `<usa-
|
|
42
|
+
| **トランジション**(`/components/transitions`) | `<usa-dialog>` · `<usa-accordion>` · `<usa-view-switch>` · `viewTransition()` · `flip()` |
|
|
43
43
|
| **スプリング・物理**(`/components/physics`) | `<usa-spring>`(bounce-in · pop · drop · jelly · rubber-band)· `<usa-draggable>` · `<usa-overscroll>` · `spring()` · `createSpring()` |
|
|
44
44
|
| **カード効果**(`/components/cards`) | `<usa-card>`(flip · holo · glass · border-glow · conic-border · lift · spotlight · sheen · parallax-layers · expand)· `<usa-card-stack>` · `<usa-sticky-stack>` · `<usa-carousel-3d>` |
|
|
45
45
|
| **クリック・タップ**(`/components/click`) | `<usa-button>`(squash · wobble · gooey · dent · shape morph · submit)· `<usa-icon-morph>` · `<usa-click>` · `<usa-like>` · `<usa-hold>` · `<usa-double-tap>` · `<usa-checkbox>` |
|
|
@@ -51,6 +51,7 @@ defineComponents(); // カテゴリ単位: import { defineTextComponents } from
|
|
|
51
51
|
| **Canvas / WebGL** (`/components/webgl`) | `<usa-shader>`(gradient · plasma · waves · aurora · カスタム GLSL)· `<usa-distort>` · `<usa-liquid>` · `glQuad()` |
|
|
52
52
|
| **3D / 奥行き** (`/components/depth`) | `<usa-cube>` · `<usa-depth>`(ポインター · ジャイロ · スクロール視差)· `deviceTilt()` |
|
|
53
53
|
| **レイアウト** (`/components/layout`) | `<usa-auto-animate>` / `autoAnimate()` · `<usa-masonry>` · `sharedTransition()`(共有要素) |
|
|
54
|
+
| **エフェクトパック** (`/components/packs`) | `<usa-pack>` (`name="ecommerce \| portfolio \| dashboard \| game \| landing"`) · `applyPack()` · `flyToCart()` |
|
|
54
55
|
|
|
55
56
|
## ドキュメント
|
|
56
57
|
|
|
@@ -92,7 +93,7 @@ const sa = createScrollAnimate({ defaultEngine: 'auto' });
|
|
|
92
93
|
|
|
93
94
|
- `'auto'`:**2.0 からのデフォルト**。対応ブラウザではネイティブ、非対応なら JS。要素が `duration`・`delay`・`offset`・`stagger` を自分で指定した場合も JS。`'css'`:対応時は常にネイティブ。`'js'`:1.x の動作(`defaultEngine: 'js'` で全体に適用)。
|
|
94
95
|
- ネイティブエンジンでは `duration`・`delay`・`threshold`・`offset`・`stagger` は無効で、範囲は `viewRange`(デフォルト `['entry 0%', 'entry 100%']`)。`easing` は有効。HTML:`data-sa-engine`、`data-sa-view-range`。
|
|
95
|
-
- `once`(デフォルト)は完了時に最終状態を固定、`repeat: true` ではスクロールに双方向で追従。クラス名モード・reduced motion・`animate()`・`
|
|
96
|
+
- `once`(デフォルト)は完了時に最終状態を固定、`repeat: true` ではスクロールに双方向で追従。クラス名モード・reduced motion・`animate()`・`timeline()`・`staggerChildren()` は常に JS エンジン。`supportsScrollTimeline()` もエクスポート。
|
|
96
97
|
|
|
97
98
|
## v1.4.0 の新機能 ✨
|
|
98
99
|
|
|
@@ -112,16 +113,15 @@ const sa = createScrollAnimate({ defaultEngine: 'auto' });
|
|
|
112
113
|
const stop = staggerChildren(document.querySelector('#feed'), { stagger: 60, observeChildren: true });
|
|
113
114
|
```
|
|
114
115
|
|
|
115
|
-
- **タイムライン `
|
|
116
|
+
- **タイムライン `timeline()`**:1 つの再生ヘッドで複数要素のアニメーションを連結。既定では前のステップの終了後に開始し、`at` で重ね(`'-=300'`)、待機(`'+=200'`)、前と同時(`'<'`)、ラベル・絶対時刻を指定。再生・逆再生・シーク・スクロール連動(scrub)に対応。(4.0 で削除された `sequence()` の後継。[upgrading-4.md](./docs/upgrading-4.md) 参照。)
|
|
116
117
|
|
|
117
118
|
```js
|
|
118
|
-
import {
|
|
119
|
-
const tl =
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
await tl.play(); // すべて完了すると resolve。tl.cancel() で停止し要素は表示されたまま
|
|
119
|
+
import { timeline } from 'use-scroll-animate';
|
|
120
|
+
const tl = timeline({ defaults: { duration: 700 } })
|
|
121
|
+
.to('.hero h1', 'fade-up')
|
|
122
|
+
.to('.hero p', 'blur', { at: '-=300' })
|
|
123
|
+
.to('.hero .btn', 'scale', { stagger: 80 });
|
|
124
|
+
await tl.play(); // 完了で resolve。tl.scrub(hero) でスクロール連動
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
- **新しいプリセット**:`scale-up`、`blur-in-up`、`flip-up`、`flip-down`、`rotate-left`、`rotate-right`、clip-path による `clip-up`、`clip-down`、`clip-left`、`clip-right`、`clip-circle`。
|
package/README_zh.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
`use-scroll-animate` 的设计初衷截然不同:
|
|
22
22
|
- ⚡ **零依赖**:纯原生 JS/TypeScript 编写。
|
|
23
23
|
- 🚀 **高性能**:由 `IntersectionObserver` 和原生 `Web Animations API` 驱动。默认不监听滚动事件(可选的滚动进度模式仅在被追踪元素可见时使用一个 passive、rAF 节流的监听器),无布局抖动。
|
|
24
|
-
- 🪶 **极轻量**:Gzip 后核心约 4.8KB(含 `
|
|
24
|
+
- 🪶 **极轻量**:Gzip 后核心约 4.8KB(含 `timeline`、`staggerChildren` 与 React/Vue 辅助在内全部约 6.1KB)。
|
|
25
25
|
- 🧩 **框架无关**:完美支持原生 JS、React、Vue、Svelte 等。内置一流的 React Hooks 和 Vue Composables。
|
|
26
26
|
- ♿ **无障碍**:原生支持 `prefers-reduced-motion`。
|
|
27
27
|
|
|
@@ -36,7 +36,7 @@ defineComponents(); // 或按分类:import { defineTextComponents } from 'use-
|
|
|
36
36
|
|
|
37
37
|
```html
|
|
38
38
|
<!-- 或免构建直接使用 -->
|
|
39
|
-
<script src="https://unpkg.com/use-scroll-animate@
|
|
39
|
+
<script src="https://unpkg.com/use-scroll-animate@4/dist/components.umd.js"></script>
|
|
40
40
|
<usa-typewriter words="你好,Windows。|你好,Web。"></usa-typewriter>
|
|
41
41
|
<usa-spinner kind="fluent"></usa-spinner>
|
|
42
42
|
```
|
|
@@ -48,7 +48,7 @@ defineComponents(); // 或按分类:import { defineTextComponents } from 'use-
|
|
|
48
48
|
| **交互反馈**(`/components/interaction`) | `<usa-ripple>` 水波纹 · `<usa-magnetic>` 磁吸按钮 · `<usa-tilt>` 3D 倾斜卡片 · `<usa-spotlight>` Fluent 光照高亮 · `<usa-press>` 按压反馈 · `<usa-toggle>` 切换开关 |
|
|
49
49
|
| **加载与反馈**(`/components/feedback`) | `<usa-spinner>`(WinUI 进度环、Windows 圆点等 6 种)· `<usa-skeleton>` 骨架屏 · `<usa-progress>` 进度条 · `<usa-toaster>` + `toast()` 通知 · `<usa-check>` 结果图标 |
|
|
50
50
|
| **背景与装饰**(`/components/background`) | `<usa-aurora>` 极光 · `<usa-particles>` 粒子 · `<usa-grain>` 胶片颗粒 · `<usa-marquee>` 无限跑马灯 · `<usa-acrylic>` 亚克力 / 云母材质 · `<usa-grid-glow>` 网格光晕 · `<usa-blobs>` 流体色块 · `<usa-water-ripple>` 水波 · `<usa-dot-network>` 点阵 · `fluentPreset()` Fluent 预设 |
|
|
51
|
-
| **过渡动画**(`/components/transitions`) | `<usa-dialog>` 弹窗 / 抽屉 / 底部面板 · `<usa-accordion>` 手风琴 · `<usa-
|
|
51
|
+
| **过渡动画**(`/components/transitions`) | `<usa-dialog>` 弹窗 / 抽屉 / 底部面板 · `<usa-accordion>` 手风琴 · `<usa-view-switch>` 视图切换 · `viewTransition()` · `flip()` |
|
|
52
52
|
| **弹簧与物理**(`/components/physics`) | `<usa-spring>` 弹入 / 弹出 / 掉落 / 果冻 / 橡皮筋 · `<usa-draggable>` 拖拽回弹、惯性、吸附 · `<usa-overscroll>` 弹性越界 · `spring()` · `createSpring()` · 预设 gentle / wobbly / stiff / bouncy |
|
|
53
53
|
| **卡片效果**(`/components/cards`) | `<usa-card>` 翻转 · 全息 · 玻璃 · 边框光晕 · 流光边框 · 悬浮 · 聚光 · 扫光 · 视差分层 · 展开详情(可组合)· `<usa-card-stack>` 滑动卡堆 · `<usa-sticky-stack>` 滚动堆叠 · `<usa-carousel-3d>` 3D 轮播 |
|
|
54
54
|
| **点击与轻触**(`/components/click`) | `<usa-button>` 按钮点击形变(挤压拉伸 · 弹性圆角 · 液态粘滞 · 按压凹陷 · 形状变形 · 提交→加载→成功)· `<usa-icon-morph>` 图标变形 · `<usa-click>` 水波纹 / 迸发 / 彩带 / 抖动 · `<usa-like>` · `<usa-hold>` · `<usa-double-tap>` · `<usa-checkbox>` |
|
|
@@ -60,6 +60,7 @@ defineComponents(); // 或按分类:import { defineTextComponents } from 'use-
|
|
|
60
60
|
| **Canvas 与 WebGL** (`/components/webgl`) | `<usa-shader>`(gradient · plasma · waves · aurora · 自定义 GLSL)· `<usa-distort>` · `<usa-liquid>` · `glQuad()` —— 优雅降级 |
|
|
61
61
|
| **3D 与景深** (`/components/depth`) | `<usa-cube>` · `<usa-depth>`(指针 · 陀螺仪 · 滚动景深视差)· `deviceTilt()` ·(另见 cards 中的 `<usa-carousel-3d>`) |
|
|
62
62
|
| **布局动画** (`/components/layout`) | `<usa-auto-animate>` / `autoAnimate()`(列表与网格重排)· `<usa-masonry>`(瀑布流)· `sharedTransition()`(共享元素) |
|
|
63
|
+
| **效果包** (`/components/packs`) | `<usa-pack>` (`name="ecommerce \| portfolio \| dashboard \| game \| landing"`) · `applyPack()` · `flyToCart()` · `countUp()` |
|
|
63
64
|
|
|
64
65
|
完整包约 22 kB gzip(JS + CSS);单个分类 3.5–6.4 kB;单个组件约 2 kB。下方的滚动动画核心不受影响。
|
|
65
66
|
|
|
@@ -106,7 +107,7 @@ const sa = createScrollAnimate({ defaultEngine: 'auto' }); // 实例级默认
|
|
|
106
107
|
- `'auto'`:**2.0 起的默认值**,支持时使用原生时间线,否则回退 JS;若元素自行设置了 `duration`、`delay`、`offset` 或 `stagger`,则使用 JS。`'css'`:支持时始终使用原生时间线。`'js'`:1.x 的行为(`defaultEngine: 'js'` 可全局恢复)。
|
|
107
108
|
- 原生引擎下 `duration`、`delay`、`threshold`、`offset`、`stagger` 不生效;动画区间由 `viewRange` 决定(默认 `['entry 0%', 'entry 100%']`),`easing` 仍然有效。HTML:`data-sa-engine`、`data-sa-view-range="entry 0%, cover 40%"`。
|
|
108
109
|
- `once`(默认)在动画完成后固定最终状态;`repeat: true` 时随滚动双向播放。回调、`onProgress`、`progressVar`、视差照常工作。
|
|
109
|
-
- 类名模式、`prefers-reduced-motion`、`animate()`、`
|
|
110
|
+
- 类名模式、`prefers-reduced-motion`、`animate()`、`timeline()`、`staggerChildren()` 始终使用 JS 引擎。另导出 `supportsScrollTimeline()`。
|
|
110
111
|
|
|
111
112
|
## v1.4.0 新特性 ✨
|
|
112
113
|
|
|
@@ -126,16 +127,15 @@ const sa = createScrollAnimate({ defaultEngine: 'auto' }); // 实例级默认
|
|
|
126
127
|
const stop = staggerChildren(document.querySelector('#feed'), { stagger: 60, observeChildren: true });
|
|
127
128
|
```
|
|
128
129
|
|
|
129
|
-
- **时间线 `
|
|
130
|
+
- **时间线 `timeline()`**:在同一播放头上串联多个元素的动画。默认每步在上一步结束后开始;`at` 可重叠(`'-=300'`)、延后(`'+=200'`)、与上一步同时(`'<'`)、对齐标签或绝对时间;支持播放、倒放、跳转与随滚动擦洗。(取代 4.0 中移除的 `sequence()`,见 [upgrading-4.md](./docs/upgrading-4.md)。)
|
|
130
131
|
|
|
131
132
|
```js
|
|
132
|
-
import {
|
|
133
|
-
const tl =
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
await tl.play(); // 全部完成后 resolve;tl.cancel() 停止并保持元素可见
|
|
133
|
+
import { timeline } from 'use-scroll-animate';
|
|
134
|
+
const tl = timeline({ defaults: { duration: 700 } })
|
|
135
|
+
.to('.hero h1', 'fade-up')
|
|
136
|
+
.to('.hero p', 'blur', { at: '-=300' })
|
|
137
|
+
.to('.hero .btn', 'scale', { stagger: 80 });
|
|
138
|
+
await tl.play(); // 全部完成后 resolve;或 tl.scrub(hero) 随滚动
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
- **新预设**:`scale-up`、`blur-in-up`、`flip-up`、`flip-down`、`rotate-left`、`rotate-right`,以及 clip-path 揭示 `clip-up`、`clip-down`、`clip-left`、`clip-right`、`clip-circle`。
|
|
@@ -241,5 +241,5 @@ function kindOf(el, valid, fallback) {
|
|
|
241
241
|
}
|
|
242
242
|
const clamp = (v, min, max) => Math.min(max, Math.max(min, v));
|
|
243
243
|
|
|
244
|
-
export { EASE_SPRING as E, FLUENT_DECELERATE as F, MOTION_SCALE as M, configureComponents as a,
|
|
245
|
-
//# sourceMappingURL=base-
|
|
244
|
+
export { EASE_SPRING as E, FLUENT_DECELERATE as F, MOTION_SCALE as M, configureComponents as a, caf as b, canDefine as c, clamp as d, applyFrame as e, adoptStyles as f, getMotionIntensity as g, defineElement as h, EASE_OUT as i, srText as j, kindOf as k, motionScale as m, now as n, prefersReducedMotion as p, raf as r, shadowStyles as s };
|
|
245
|
+
//# sourceMappingURL=base-ZARFccur.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-BpROOcey.js","sources":["../../src/components/base.ts"],"sourcesContent":["/**\n * use-scroll-animate/components — shared base for the `<usa-*>` custom elements.\n *\n * Everything here is lazy: nothing touches `window`, `document`,\n * `HTMLElement` or `matchMedia` at import time, so the components can be\n * imported during SSR (Next, Nuxt, Astro…) and in Electron/Tauri preload\n * scripts. Classes are created the first time a `define*()` function runs.\n */\n\nexport interface ComponentsConfig {\n /**\n * Inject each component's CSS when it is defined (default `true`). Uses a\n * constructable stylesheet (`document.adoptedStyleSheets`, which a strict\n * `style-src` CSP does not block) and falls back to a `<style>` tag. Set\n * to `false` when you load `use-scroll-animate/components.css` yourself.\n */\n injectStyles?: boolean;\n /**\n * `'user'` (default) follows `prefers-reduced-motion`; `'reduce'` always\n * uses the reduced variants (e.g. a kiosk / battery-saver mode);\n * `'no-preference'` ignores the OS setting (only for demos — respect your users).\n */\n reducedMotion?: 'user' | 'reduce' | 'no-preference';\n /**\n * Global motion intensity (v2.7): `'off'` (same as reduced motion),\n * `'low'` (shorter, calmer), `'normal'` (default) or `'high'`. Scales every\n * component animation's duration and sets `--usa-motion` (0 / 0.6 / 1 /\n * 1.25) on `<html>` for your own CSS. See `setMotionIntensity()`.\n */\n motionIntensity?: MotionIntensity;\n}\n\nexport type MotionIntensity = 'off' | 'low' | 'normal' | 'high';\nexport const MOTION_SCALE: Record<MotionIntensity, number> = { off: 0, low: 0.6, normal: 1, high: 1.25 };\n\nconst config: Required<ComponentsConfig> = { injectStyles: true, reducedMotion: 'user', motionIntensity: 'normal' };\n\n/** Change global component settings (call before `define*()` for `injectStyles`). */\nexport function configureComponents(options: ComponentsConfig): void {\n Object.assign(config, options);\n if (options.motionIntensity && typeof document !== 'undefined') {\n document.documentElement.style.setProperty('--usa-motion', String(MOTION_SCALE[options.motionIntensity] ?? 1));\n document.documentElement.setAttribute('data-usa-motion', options.motionIntensity);\n }\n}\n\n/** The current global motion intensity. */\nexport function getMotionIntensity(): MotionIntensity {\n return config.motionIntensity;\n}\n\n/** Duration multiplier for the current intensity (1 when `normal`). */\nexport function motionScale(): number {\n return MOTION_SCALE[config.motionIntensity] ?? 1;\n}\n\nexport const canDefine = (): boolean => typeof customElements !== 'undefined' && typeof HTMLElement !== 'undefined';\n\n/** `true` when animations should be reduced (OS setting or `configureComponents`). */\nexport function prefersReducedMotion(): boolean {\n if (config.motionIntensity === 'off') return true;\n if (config.reducedMotion !== 'user') return config.reducedMotion === 'reduce';\n return typeof matchMedia === 'function' && !!matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\nconst injected = new Set<string>();\n\n/** Add a component's stylesheet to the document once. */\nexport function adoptStyles(id: string, css: string): void {\n if (!config.injectStyles || !css || injected.has(id) || typeof document === 'undefined') return;\n injected.add(id);\n try {\n if (typeof CSSStyleSheet === 'function' && 'adoptedStyleSheets' in document) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(css);\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];\n return;\n }\n } catch {\n /* fall through to <style> */\n }\n const style = document.createElement('style');\n style.setAttribute('data-usa', id);\n style.textContent = css;\n (document.head || document.documentElement).appendChild(style);\n}\n\n/** Attach `css` to a shadow root (constructable sheet where supported, else `<style>`). */\nexport function shadowStyles(root: ShadowRoot, css: string): void {\n try {\n if (typeof CSSStyleSheet === 'function' && 'adoptedStyleSheets' in root) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(css);\n root.adoptedStyleSheets = [sheet];\n return;\n }\n } catch {\n /* fall through */\n }\n const style = document.createElement('style');\n style.textContent = css;\n root.prepend(style);\n}\n\nexport type Cleanup = () => void;\n\n/**\n * Members shared by every `<usa-*>` element. Attribute helpers, a cleanup\n * bag that is emptied on disconnect, and motion helpers that degrade to the\n * final state without WAAPI or under reduced motion.\n */\nexport interface UsaElement extends HTMLElement {\n /** `true` while reduced motion applies to this element. */\n readonly reduced: boolean;\n}\n\nexport interface UsaBase extends UsaElement {\n mount(): void;\n changed(name: string): void;\n unmount(): void;\n str(name: string, fallback?: string): string;\n num(name: string, fallback: number): number;\n flag(name: string): boolean;\n setFlag(name: string, on: boolean): void;\n onCleanup(fn: Cleanup): void;\n listen<K extends keyof HTMLElementEventMap>(\n target: EventTarget,\n type: K | string,\n fn: (e: any) => void,\n options?: AddEventListenerOptions\n ): void;\n inView(cb: (visible: boolean, entry?: IntersectionObserverEntry) => void, init?: IntersectionObserverInit, target?: Element): void;\n motion(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;\n emit(type: string, detail?: unknown): boolean;\n}\n\ntype BaseCtor = new () => UsaBase;\nlet baseClass: BaseCtor | null = null;\n\n/** The lazily created base class (needs `HTMLElement`). */\nexport function getBase(): BaseCtor {\n if (baseClass) return baseClass;\n class Base extends HTMLElement {\n private _cleanups: Cleanup[] = [];\n private _connected = false;\n\n get reduced(): boolean {\n return prefersReducedMotion();\n }\n\n connectedCallback(): void {\n if (this._connected) return;\n this._connected = true;\n // Upgraded while the parser is still inside us (a <script> in <head>\n // defined the element): children/text are not there yet, so wait.\n if (typeof document !== 'undefined' && document.readyState === 'loading' && !this.nextSibling && !this.childNodes.length) {\n const go = () => {\n if (this._connected && this.isConnected) this.mount();\n };\n document.addEventListener('DOMContentLoaded', go, { once: true });\n this._cleanups.push(() => document.removeEventListener('DOMContentLoaded', go));\n return;\n }\n this.mount();\n }\n\n disconnectedCallback(): void {\n this._connected = false;\n this.teardown();\n }\n\n attributeChangedCallback(_name: string, oldValue: string | null, value: string | null): void {\n if (!this._connected || oldValue === value) return;\n this.changed(_name);\n }\n\n /** Re-mount on attribute change (override for finer updates). */\n changed(_name: string): void {\n this.teardown();\n this.mount();\n }\n\n private teardown(): void {\n this._cleanups.splice(0).reverse().forEach((fn) => fn());\n this.unmount();\n }\n\n mount(): void {}\n unmount(): void {}\n\n str(name: string, fallback = ''): string {\n const v = this.getAttribute(name);\n return v === null ? fallback : v;\n }\n\n num(name: string, fallback: number): number {\n const v = this.getAttribute(name);\n const n = v === null || v.trim() === '' ? NaN : Number(v);\n return Number.isFinite(n) ? n : fallback;\n }\n\n /** Boolean attribute: present and not `\"false\"`. */\n flag(name: string): boolean {\n const v = this.getAttribute(name);\n return v !== null && v !== 'false';\n }\n\n setFlag(name: string, on: boolean): void {\n if (on) this.setAttribute(name, '');\n else this.removeAttribute(name);\n }\n\n onCleanup(fn: Cleanup): void {\n this._cleanups.push(fn);\n }\n\n listen(target: EventTarget, type: string, fn: (e: any) => void, options?: AddEventListenerOptions): void {\n target.addEventListener(type, fn, options);\n this.onCleanup(() => target.removeEventListener(type, fn, options));\n }\n\n /** Calls `cb(true/false)` as the element enters / leaves the viewport. */\n inView(cb: (visible: boolean, entry?: IntersectionObserverEntry) => void, init?: IntersectionObserverInit, target: Element = this): void {\n if (typeof IntersectionObserver === 'undefined') {\n cb(true);\n return;\n }\n const io = new IntersectionObserver((entries) => {\n for (const e of entries) cb(e.isIntersecting, e);\n }, init);\n io.observe(target);\n this.onCleanup(() => io.disconnect());\n }\n\n /** `el.animate()` that returns `null` (and applies the last frame) without WAAPI. */\n motion(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null {\n if (typeof (el as HTMLElement).animate !== 'function') {\n applyFrame(el as HTMLElement, keyframes[keyframes.length - 1]);\n return null;\n }\n const k = motionScale();\n if (k !== 1 && k > 0 && typeof options.duration === 'number') options = { ...options, duration: options.duration * k, delay: (options.delay || 0) * k };\n return (el as HTMLElement).animate(keyframes, options);\n }\n\n emit(type: string, detail?: unknown): boolean {\n return this.dispatchEvent(new CustomEvent(`usa:${type}`, { detail, bubbles: true, cancelable: true }));\n }\n }\n baseClass = Base as unknown as BaseCtor;\n return baseClass;\n}\n\n/** Write a keyframe's properties as inline styles (no-WAAPI fallback). */\nexport function applyFrame(el: HTMLElement, frame?: Keyframe): void {\n if (!frame) return;\n for (const [k, v] of Object.entries(frame)) {\n if (k === 'offset' || k === 'easing' || k === 'composite' || v == null) continue;\n (el.style as any)[k] = String(v);\n }\n}\n\n/**\n * Register `tag` with the class built by `make(Base)`. Returns the\n * constructor, the already registered one, or `undefined` without DOM.\n */\nexport function defineElement(\n tag: string,\n make: (Base: BaseCtor) => CustomElementConstructor,\n css?: { id: string; text: string }\n): CustomElementConstructor | undefined {\n if (!canDefine()) return undefined;\n adoptStyles('base', BASE_CSS);\n if (css) adoptStyles(css.id, css.text);\n const existing = customElements.get(tag);\n if (existing) return existing;\n const ctor = make(getBase());\n customElements.define(tag, ctor);\n return ctor;\n}\n\nconst BASE_CSS = '.usa-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}';\n\n/** A visually hidden copy of `text` for screen readers (the animated copy is `aria-hidden`). */\nexport function srText(text: string): HTMLSpanElement {\n const s = document.createElement('span');\n s.className = 'usa-sr';\n s.textContent = text;\n return s;\n}\n\n/** requestAnimationFrame with a timeout fallback (jsdom / hidden documents). */\nexport const raf = (cb: FrameRequestCallback): number =>\n typeof requestAnimationFrame === 'function' ? requestAnimationFrame(cb) : (setTimeout(() => cb(Date.now()), 16) as unknown as number);\n/** Monotonic time in ms (rAF callback timestamps differ between environments, so loops use this). */\nexport const now = (): number => (typeof performance !== 'undefined' ? performance.now() : Date.now());\nexport const caf = (id: number): void => {\n if (typeof cancelAnimationFrame === 'function') cancelAnimationFrame(id);\n else clearTimeout(id);\n};\n\n/** Spring-ish easing used across the components. */\nexport const EASE_OUT = 'cubic-bezier(0.22, 1, 0.36, 1)';\nexport const EASE_SPRING = 'cubic-bezier(0.34, 1.56, 0.64, 1)';\n/** Windows Fluent \"decelerate\" / \"point-to-point\" curves. */\nexport const FLUENT_DECELERATE = 'cubic-bezier(0.1, 0.9, 0.2, 1)';\n\nconst warned = new Set<string>();\n/** Log a deprecation once per key (console.warn). */\nexport function deprecate(key: string, message: string): void {\n if (warned.has(key)) return;\n warned.add(key);\n if (typeof console !== 'undefined') console.warn(`[use-scroll-animate] ${message}`);\n}\n\n/**\n * The `kind` attribute of `<usa-spinner>`, `<usa-check>`, `<usa-dialog>` and\n * `<usa-acrylic>` (3.0: `variant` only selects a style variant).\n */\nexport function kindOf(el: Element, valid: readonly string[] | Record<string, unknown>, fallback: string): string {\n const k = el.getAttribute('kind');\n return k && (Array.isArray(valid) ? valid.includes(k) : k in (valid as object)) ? k : fallback;\n}\n\nexport const clamp = (v: number, min: number, max: number): number => Math.min(max, Math.max(min, v));\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base-ZARFccur.js","sources":["../../src/components/base.ts"],"sourcesContent":["/**\n * use-scroll-animate/components — shared base for the `<usa-*>` custom elements.\n *\n * Everything here is lazy: nothing touches `window`, `document`,\n * `HTMLElement` or `matchMedia` at import time, so the components can be\n * imported during SSR (Next, Nuxt, Astro…) and in Electron/Tauri preload\n * scripts. Classes are created the first time a `define*()` function runs.\n */\n\nexport interface ComponentsConfig {\n /**\n * Inject each component's CSS when it is defined (default `true`). Uses a\n * constructable stylesheet (`document.adoptedStyleSheets`, which a strict\n * `style-src` CSP does not block) and falls back to a `<style>` tag. Set\n * to `false` when you load `use-scroll-animate/components.css` yourself.\n */\n injectStyles?: boolean;\n /**\n * `'user'` (default) follows `prefers-reduced-motion`; `'reduce'` always\n * uses the reduced variants (e.g. a kiosk / battery-saver mode);\n * `'no-preference'` ignores the OS setting (only for demos — respect your users).\n */\n reducedMotion?: 'user' | 'reduce' | 'no-preference';\n /**\n * Global motion intensity (v2.7): `'off'` (same as reduced motion),\n * `'low'` (shorter, calmer), `'normal'` (default) or `'high'`. Scales every\n * component animation's duration and sets `--usa-motion` (0 / 0.6 / 1 /\n * 1.25) on `<html>` for your own CSS. See `setMotionIntensity()`.\n */\n motionIntensity?: MotionIntensity;\n}\n\nexport type MotionIntensity = 'off' | 'low' | 'normal' | 'high';\nexport const MOTION_SCALE: Record<MotionIntensity, number> = { off: 0, low: 0.6, normal: 1, high: 1.25 };\n\nconst config: Required<ComponentsConfig> = { injectStyles: true, reducedMotion: 'user', motionIntensity: 'normal' };\n\n/** Change global component settings (call before `define*()` for `injectStyles`). */\nexport function configureComponents(options: ComponentsConfig): void {\n Object.assign(config, options);\n if (options.motionIntensity && typeof document !== 'undefined') {\n document.documentElement.style.setProperty('--usa-motion', String(MOTION_SCALE[options.motionIntensity] ?? 1));\n document.documentElement.setAttribute('data-usa-motion', options.motionIntensity);\n }\n}\n\n/** The current global motion intensity. */\nexport function getMotionIntensity(): MotionIntensity {\n return config.motionIntensity;\n}\n\n/** Duration multiplier for the current intensity (1 when `normal`). */\nexport function motionScale(): number {\n return MOTION_SCALE[config.motionIntensity] ?? 1;\n}\n\nexport const canDefine = (): boolean => typeof customElements !== 'undefined' && typeof HTMLElement !== 'undefined';\n\n/** `true` when animations should be reduced (OS setting or `configureComponents`). */\nexport function prefersReducedMotion(): boolean {\n if (config.motionIntensity === 'off') return true;\n if (config.reducedMotion !== 'user') return config.reducedMotion === 'reduce';\n return typeof matchMedia === 'function' && !!matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\nconst injected = new Set<string>();\n\n/** Add a component's stylesheet to the document once. */\nexport function adoptStyles(id: string, css: string): void {\n if (!config.injectStyles || !css || injected.has(id) || typeof document === 'undefined') return;\n injected.add(id);\n try {\n if (typeof CSSStyleSheet === 'function' && 'adoptedStyleSheets' in document) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(css);\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];\n return;\n }\n } catch {\n /* fall through to <style> */\n }\n const style = document.createElement('style');\n style.setAttribute('data-usa', id);\n style.textContent = css;\n (document.head || document.documentElement).appendChild(style);\n}\n\n/** Attach `css` to a shadow root (constructable sheet where supported, else `<style>`). */\nexport function shadowStyles(root: ShadowRoot, css: string): void {\n try {\n if (typeof CSSStyleSheet === 'function' && 'adoptedStyleSheets' in root) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(css);\n root.adoptedStyleSheets = [sheet];\n return;\n }\n } catch {\n /* fall through */\n }\n const style = document.createElement('style');\n style.textContent = css;\n root.prepend(style);\n}\n\nexport type Cleanup = () => void;\n\n/**\n * Members shared by every `<usa-*>` element. Attribute helpers, a cleanup\n * bag that is emptied on disconnect, and motion helpers that degrade to the\n * final state without WAAPI or under reduced motion.\n */\nexport interface UsaElement extends HTMLElement {\n /** `true` while reduced motion applies to this element. */\n readonly reduced: boolean;\n}\n\nexport interface UsaBase extends UsaElement {\n mount(): void;\n changed(name: string): void;\n unmount(): void;\n str(name: string, fallback?: string): string;\n num(name: string, fallback: number): number;\n flag(name: string): boolean;\n setFlag(name: string, on: boolean): void;\n onCleanup(fn: Cleanup): void;\n listen<K extends keyof HTMLElementEventMap>(\n target: EventTarget,\n type: K | string,\n fn: (e: any) => void,\n options?: AddEventListenerOptions\n ): void;\n inView(cb: (visible: boolean, entry?: IntersectionObserverEntry) => void, init?: IntersectionObserverInit, target?: Element): void;\n motion(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;\n emit(type: string, detail?: unknown): boolean;\n}\n\ntype BaseCtor = new () => UsaBase;\nlet baseClass: BaseCtor | null = null;\n\n/** The lazily created base class (needs `HTMLElement`). */\nexport function getBase(): BaseCtor {\n if (baseClass) return baseClass;\n class Base extends HTMLElement {\n private _cleanups: Cleanup[] = [];\n private _connected = false;\n\n get reduced(): boolean {\n return prefersReducedMotion();\n }\n\n connectedCallback(): void {\n if (this._connected) return;\n this._connected = true;\n // Upgraded while the parser is still inside us (a <script> in <head>\n // defined the element): children/text are not there yet, so wait.\n if (typeof document !== 'undefined' && document.readyState === 'loading' && !this.nextSibling && !this.childNodes.length) {\n const go = () => {\n if (this._connected && this.isConnected) this.mount();\n };\n document.addEventListener('DOMContentLoaded', go, { once: true });\n this._cleanups.push(() => document.removeEventListener('DOMContentLoaded', go));\n return;\n }\n this.mount();\n }\n\n disconnectedCallback(): void {\n this._connected = false;\n this.teardown();\n }\n\n attributeChangedCallback(_name: string, oldValue: string | null, value: string | null): void {\n if (!this._connected || oldValue === value) return;\n this.changed(_name);\n }\n\n /** Re-mount on attribute change (override for finer updates). */\n changed(_name: string): void {\n this.teardown();\n this.mount();\n }\n\n private teardown(): void {\n this._cleanups.splice(0).reverse().forEach((fn) => fn());\n this.unmount();\n }\n\n mount(): void {}\n unmount(): void {}\n\n str(name: string, fallback = ''): string {\n const v = this.getAttribute(name);\n return v === null ? fallback : v;\n }\n\n num(name: string, fallback: number): number {\n const v = this.getAttribute(name);\n const n = v === null || v.trim() === '' ? NaN : Number(v);\n return Number.isFinite(n) ? n : fallback;\n }\n\n /** Boolean attribute: present and not `\"false\"`. */\n flag(name: string): boolean {\n const v = this.getAttribute(name);\n return v !== null && v !== 'false';\n }\n\n setFlag(name: string, on: boolean): void {\n if (on) this.setAttribute(name, '');\n else this.removeAttribute(name);\n }\n\n onCleanup(fn: Cleanup): void {\n this._cleanups.push(fn);\n }\n\n listen(target: EventTarget, type: string, fn: (e: any) => void, options?: AddEventListenerOptions): void {\n target.addEventListener(type, fn, options);\n this.onCleanup(() => target.removeEventListener(type, fn, options));\n }\n\n /** Calls `cb(true/false)` as the element enters / leaves the viewport. */\n inView(cb: (visible: boolean, entry?: IntersectionObserverEntry) => void, init?: IntersectionObserverInit, target: Element = this): void {\n if (typeof IntersectionObserver === 'undefined') {\n cb(true);\n return;\n }\n const io = new IntersectionObserver((entries) => {\n for (const e of entries) cb(e.isIntersecting, e);\n }, init);\n io.observe(target);\n this.onCleanup(() => io.disconnect());\n }\n\n /** `el.animate()` that returns `null` (and applies the last frame) without WAAPI. */\n motion(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null {\n if (typeof (el as HTMLElement).animate !== 'function') {\n applyFrame(el as HTMLElement, keyframes[keyframes.length - 1]);\n return null;\n }\n const k = motionScale();\n if (k !== 1 && k > 0 && typeof options.duration === 'number') options = { ...options, duration: options.duration * k, delay: (options.delay || 0) * k };\n return (el as HTMLElement).animate(keyframes, options);\n }\n\n emit(type: string, detail?: unknown): boolean {\n return this.dispatchEvent(new CustomEvent(`usa:${type}`, { detail, bubbles: true, cancelable: true }));\n }\n }\n baseClass = Base as unknown as BaseCtor;\n return baseClass;\n}\n\n/** Write a keyframe's properties as inline styles (no-WAAPI fallback). */\nexport function applyFrame(el: HTMLElement, frame?: Keyframe): void {\n if (!frame) return;\n for (const [k, v] of Object.entries(frame)) {\n if (k === 'offset' || k === 'easing' || k === 'composite' || v == null) continue;\n (el.style as any)[k] = String(v);\n }\n}\n\n/**\n * Register `tag` with the class built by `make(Base)`. Returns the\n * constructor, the already registered one, or `undefined` without DOM.\n */\nexport function defineElement(\n tag: string,\n make: (Base: BaseCtor) => CustomElementConstructor,\n css?: { id: string; text: string }\n): CustomElementConstructor | undefined {\n if (!canDefine()) return undefined;\n adoptStyles('base', BASE_CSS);\n if (css) adoptStyles(css.id, css.text);\n const existing = customElements.get(tag);\n if (existing) return existing;\n const ctor = make(getBase());\n customElements.define(tag, ctor);\n return ctor;\n}\n\nconst BASE_CSS = '.usa-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}';\n\n/** A visually hidden copy of `text` for screen readers (the animated copy is `aria-hidden`). */\nexport function srText(text: string): HTMLSpanElement {\n const s = document.createElement('span');\n s.className = 'usa-sr';\n s.textContent = text;\n return s;\n}\n\n/** requestAnimationFrame with a timeout fallback (jsdom / hidden documents). */\nexport const raf = (cb: FrameRequestCallback): number =>\n typeof requestAnimationFrame === 'function' ? requestAnimationFrame(cb) : (setTimeout(() => cb(Date.now()), 16) as unknown as number);\n/** Monotonic time in ms (rAF callback timestamps differ between environments, so loops use this). */\nexport const now = (): number => (typeof performance !== 'undefined' ? performance.now() : Date.now());\nexport const caf = (id: number): void => {\n if (typeof cancelAnimationFrame === 'function') cancelAnimationFrame(id);\n else clearTimeout(id);\n};\n\n/** Spring-ish easing used across the components. */\nexport const EASE_OUT = 'cubic-bezier(0.22, 1, 0.36, 1)';\nexport const EASE_SPRING = 'cubic-bezier(0.34, 1.56, 0.64, 1)';\n/** Windows Fluent \"decelerate\" / \"point-to-point\" curves. */\nexport const FLUENT_DECELERATE = 'cubic-bezier(0.1, 0.9, 0.2, 1)';\n\nconst warned = new Set<string>();\n/** Log a deprecation once per key (console.warn). */\nexport function deprecate(key: string, message: string): void {\n if (warned.has(key)) return;\n warned.add(key);\n if (typeof console !== 'undefined') console.warn(`[use-scroll-animate] ${message}`);\n}\n\n/**\n * The `kind` attribute of `<usa-spinner>`, `<usa-check>`, `<usa-dialog>` and\n * `<usa-acrylic>` (3.0: `variant` only selects a style variant).\n */\nexport function kindOf(el: Element, valid: readonly string[] | Record<string, unknown>, fallback: string): string {\n const k = el.getAttribute('kind');\n return k && (Array.isArray(valid) ? valid.includes(k) : k in (valid as object)) ? k : fallback;\n}\n\nexport const clamp = (v: number, min: number, max: number): number => Math.min(max, Math.max(min, v));\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { p as prefersReducedMotion, b as caf, d as clamp, e as applyFrame, r as raf, m as motionScale, n as now } from './base-ZARFccur.js';
|
|
2
|
+
|
|
3
|
+
/** Keyframe presets usable by name in `to()` and `data-tl`. */
|
|
4
|
+
const TIMELINE_PRESETS = {
|
|
5
|
+
fade: [{ opacity: 0 }, { opacity: 1 }],
|
|
6
|
+
'fade-up': [{ opacity: 0, transform: 'translateY(24px)' }, { opacity: 1, transform: 'none' }],
|
|
7
|
+
'fade-down': [{ opacity: 0, transform: 'translateY(-24px)' }, { opacity: 1, transform: 'none' }],
|
|
8
|
+
'fade-left': [{ opacity: 0, transform: 'translateX(24px)' }, { opacity: 1, transform: 'none' }],
|
|
9
|
+
'fade-right': [{ opacity: 0, transform: 'translateX(-24px)' }, { opacity: 1, transform: 'none' }],
|
|
10
|
+
scale: [{ opacity: 0, transform: 'scale(0.85)' }, { opacity: 1, transform: 'none' }],
|
|
11
|
+
blur: [{ opacity: 0, filter: 'blur(12px)' }, { opacity: 1, filter: 'blur(0)' }],
|
|
12
|
+
rotate: [{ opacity: 0, transform: 'rotate(-12deg) scale(0.9)' }, { opacity: 1, transform: 'none' }],
|
|
13
|
+
'clip-up': [{ clipPath: 'inset(100% 0 0 0)' }, { clipPath: 'inset(0 0 0 0)' }],
|
|
14
|
+
'clip-right': [{ clipPath: 'inset(0 100% 0 0)' }, { clipPath: 'inset(0 0 0 0)' }],
|
|
15
|
+
};
|
|
16
|
+
/** Resolve a position against the previous step and labels (pure). */
|
|
17
|
+
function resolvePosition(pos, end, prevStart, labels = {}) {
|
|
18
|
+
if (pos === undefined || pos === '' || pos === '>')
|
|
19
|
+
return end;
|
|
20
|
+
if (typeof pos === 'number')
|
|
21
|
+
return Math.max(0, pos);
|
|
22
|
+
const s = String(pos).trim();
|
|
23
|
+
if (/^-?\d+(\.\d+)?$/.test(s))
|
|
24
|
+
return Math.max(0, Number(s));
|
|
25
|
+
const m = /^(<|>|[A-Za-z_][\w-]*)?\s*(?:([+-])=\s*(\d+(?:\.\d+)?))?$/.exec(s);
|
|
26
|
+
if (!m)
|
|
27
|
+
return end;
|
|
28
|
+
const base = m[1] === '<' ? prevStart : m[1] === '>' || !m[1] ? end : labels[m[1]] ?? end;
|
|
29
|
+
const delta = m[2] ? (m[2] === '-' ? -1 : 1) * Number(m[3]) : 0;
|
|
30
|
+
return Math.max(0, base + delta);
|
|
31
|
+
}
|
|
32
|
+
const toEls = (t) => typeof t === 'string' ? (typeof document === 'undefined' ? [] : Array.from(document.querySelectorAll(t))) : t instanceof Element ? [t] : Array.from(t);
|
|
33
|
+
/**
|
|
34
|
+
* Choreograph animations on one clock: chain, overlap, label, seek, reverse and
|
|
35
|
+
* scrub them with scroll. Built on WAAPI (paused animations driven by one
|
|
36
|
+
* playhead); without WAAPI or under reduced motion it jumps to the end state.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const tl = timeline({ defaults: { duration: 500 } })
|
|
40
|
+
* .to('.title', 'fade-up')
|
|
41
|
+
* .label('cards')
|
|
42
|
+
* .to('.card', 'scale', { stagger: 80, at: '-=200' })
|
|
43
|
+
* .to('.cta', [{ opacity: 0 }, { opacity: 1 }], { at: 'cards+=400' });
|
|
44
|
+
* tl.play(); // or tl.scrub(document.querySelector('.hero'))
|
|
45
|
+
*/
|
|
46
|
+
function timeline(options = {}) {
|
|
47
|
+
const d = { duration: 600, easing: 'cubic-bezier(0.22, 1, 0.36, 1)', stagger: 0, ...options.defaults };
|
|
48
|
+
const steps = [];
|
|
49
|
+
const cues = [];
|
|
50
|
+
const labels = {};
|
|
51
|
+
let end = 0;
|
|
52
|
+
let prevStart = 0;
|
|
53
|
+
let t = 0;
|
|
54
|
+
let frame = 0;
|
|
55
|
+
let dir = 1;
|
|
56
|
+
let settle;
|
|
57
|
+
let built = false;
|
|
58
|
+
const total = () => Math.max(end, ...cues.map((c) => c.at), 0);
|
|
59
|
+
const build = () => {
|
|
60
|
+
if (built)
|
|
61
|
+
return;
|
|
62
|
+
built = true;
|
|
63
|
+
for (const s of steps) {
|
|
64
|
+
if (typeof s.el.animate !== 'function') {
|
|
65
|
+
s.anim = null;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
s.anim = s.el.animate(s.frames, { duration: s.duration, delay: s.start, easing: s.easing, fill: 'both' });
|
|
69
|
+
s.anim.pause?.();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const render = (to, from) => {
|
|
73
|
+
build();
|
|
74
|
+
t = clamp(to, 0, total());
|
|
75
|
+
for (const s of steps) {
|
|
76
|
+
if (s.anim)
|
|
77
|
+
s.anim.currentTime = t;
|
|
78
|
+
else
|
|
79
|
+
applyFrame(s.el, s.frames[t >= s.start ? s.frames.length - 1 : 0]);
|
|
80
|
+
}
|
|
81
|
+
for (const c of cues)
|
|
82
|
+
if ((from < c.at && t >= c.at) || (from > c.at && t <= c.at))
|
|
83
|
+
c.fn();
|
|
84
|
+
options.onUpdate?.(total() ? t / total() : 1);
|
|
85
|
+
};
|
|
86
|
+
const stop = () => {
|
|
87
|
+
if (frame)
|
|
88
|
+
caf(frame);
|
|
89
|
+
frame = 0;
|
|
90
|
+
};
|
|
91
|
+
const run = (direction) => {
|
|
92
|
+
stop();
|
|
93
|
+
settle?.();
|
|
94
|
+
dir = direction;
|
|
95
|
+
const target = dir > 0 ? total() : 0;
|
|
96
|
+
const k = motionScale();
|
|
97
|
+
if (prefersReducedMotion() || k === 0 || !total()) {
|
|
98
|
+
render(target, t);
|
|
99
|
+
options.onComplete?.();
|
|
100
|
+
return Promise.resolve();
|
|
101
|
+
}
|
|
102
|
+
const rate = (options.speed ?? 1) / k;
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
settle = () => { settle = undefined; resolve(); };
|
|
105
|
+
let last = now();
|
|
106
|
+
const loop = () => {
|
|
107
|
+
const n = now();
|
|
108
|
+
const next = t + (n - last) * rate * dir;
|
|
109
|
+
last = n;
|
|
110
|
+
render(next, t);
|
|
111
|
+
if ((dir > 0 && t >= target) || (dir < 0 && t <= 0)) {
|
|
112
|
+
frame = 0;
|
|
113
|
+
options.onComplete?.();
|
|
114
|
+
settle?.();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
frame = raf(loop);
|
|
118
|
+
};
|
|
119
|
+
frame = raf(loop);
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
const api = {
|
|
123
|
+
get duration() { return total(); },
|
|
124
|
+
get labels() { return { ...labels }; },
|
|
125
|
+
get time() { return t; },
|
|
126
|
+
to(target, frames, o = {}) {
|
|
127
|
+
const kf = typeof frames === 'string' ? TIMELINE_PRESETS[frames] || TIMELINE_PRESETS.fade : frames;
|
|
128
|
+
const start = resolvePosition(o.at, end, prevStart, labels);
|
|
129
|
+
const duration = o.duration ?? d.duration;
|
|
130
|
+
const stagger = o.stagger ?? d.stagger;
|
|
131
|
+
let last = start;
|
|
132
|
+
toEls(target).forEach((el, i) => {
|
|
133
|
+
const s = start + i * stagger;
|
|
134
|
+
steps.push({ el, frames: kf, start: s, duration, easing: o.easing ?? d.easing });
|
|
135
|
+
last = Math.max(last, s + duration);
|
|
136
|
+
});
|
|
137
|
+
prevStart = start;
|
|
138
|
+
end = Math.max(end, last);
|
|
139
|
+
built = false;
|
|
140
|
+
steps.forEach((s) => s.anim?.cancel?.());
|
|
141
|
+
return api;
|
|
142
|
+
},
|
|
143
|
+
label(name, at) {
|
|
144
|
+
labels[name] = resolvePosition(at, end, prevStart, labels);
|
|
145
|
+
return api;
|
|
146
|
+
},
|
|
147
|
+
call(fn, at) {
|
|
148
|
+
cues.push({ fn, at: resolvePosition(at, end, prevStart, labels) });
|
|
149
|
+
return api;
|
|
150
|
+
},
|
|
151
|
+
play(from) {
|
|
152
|
+
if (from !== undefined)
|
|
153
|
+
render(resolvePosition(from, 0, 0, labels), t);
|
|
154
|
+
else if (t >= total())
|
|
155
|
+
render(0, -1);
|
|
156
|
+
return run(1);
|
|
157
|
+
},
|
|
158
|
+
reverse() {
|
|
159
|
+
return run(-1);
|
|
160
|
+
},
|
|
161
|
+
pause() {
|
|
162
|
+
stop();
|
|
163
|
+
return api;
|
|
164
|
+
},
|
|
165
|
+
seek(to) {
|
|
166
|
+
stop();
|
|
167
|
+
render(resolvePosition(to, 0, 0, labels), t);
|
|
168
|
+
return api;
|
|
169
|
+
},
|
|
170
|
+
progress(p) {
|
|
171
|
+
if (p !== undefined)
|
|
172
|
+
api.seek(clamp(p, 0, 1) * total());
|
|
173
|
+
return total() ? t / total() : 0;
|
|
174
|
+
},
|
|
175
|
+
scrub(source, o = {}) {
|
|
176
|
+
stop();
|
|
177
|
+
if (prefersReducedMotion() || typeof window === 'undefined') {
|
|
178
|
+
render(total(), t);
|
|
179
|
+
return () => { };
|
|
180
|
+
}
|
|
181
|
+
let id = 0;
|
|
182
|
+
let cur = t;
|
|
183
|
+
const update = () => {
|
|
184
|
+
id = 0;
|
|
185
|
+
const r = source.getBoundingClientRect();
|
|
186
|
+
const vh = window.innerHeight || 1;
|
|
187
|
+
const p = clamp((vh + (o.offset ?? 0) - r.top) / (vh + r.height || 1), 0, 1);
|
|
188
|
+
const goal = p * total();
|
|
189
|
+
const sm = clamp(o.smooth ?? 0, 0, 0.95);
|
|
190
|
+
cur = sm ? cur + (goal - cur) * (1 - sm) : goal;
|
|
191
|
+
render(cur, t);
|
|
192
|
+
if (sm && Math.abs(goal - cur) > 0.5)
|
|
193
|
+
id = raf(update);
|
|
194
|
+
};
|
|
195
|
+
const onScroll = () => { if (!id)
|
|
196
|
+
id = raf(update); };
|
|
197
|
+
window.addEventListener('scroll', onScroll, { passive: true });
|
|
198
|
+
window.addEventListener('resize', onScroll, { passive: true });
|
|
199
|
+
update();
|
|
200
|
+
return () => {
|
|
201
|
+
window.removeEventListener('scroll', onScroll);
|
|
202
|
+
window.removeEventListener('resize', onScroll);
|
|
203
|
+
if (id)
|
|
204
|
+
caf(id);
|
|
205
|
+
};
|
|
206
|
+
},
|
|
207
|
+
cancel() {
|
|
208
|
+
stop();
|
|
209
|
+
settle?.();
|
|
210
|
+
steps.forEach((s) => s.anim?.cancel?.());
|
|
211
|
+
built = false;
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
return api;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export { TIMELINE_PRESETS as T, resolvePosition as r, timeline as t };
|
|
218
|
+
//# sourceMappingURL=core-Co-6AL0h.js.map
|