svg-scroll-draw 2.13.0 → 2.14.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/README.md +18 -4
- package/dist/aos/index.d.mts +53 -0
- package/dist/aos/index.d.ts +53 -0
- package/dist/cinematic/index.d.mts +72 -0
- package/dist/cinematic/index.d.ts +72 -0
- package/dist/cli/init.js +284 -13
- package/dist/devtools/index.d.mts +12 -0
- package/dist/devtools/index.d.ts +12 -0
- package/dist/text/index.d.mts +52 -0
- package/dist/text/index.d.ts +52 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -363,7 +363,7 @@ import { ScrollDraw } from 'svg-scroll-draw/vue';
|
|
|
363
363
|
## AOS drop-in — switch from AOS in one line
|
|
364
364
|
|
|
365
365
|
Already using [AOS](https://github.com/michalsnik/aos)? `svg-scroll-draw/aos` speaks its API and
|
|
366
|
-
reads its markup, so the move is an import change
|
|
366
|
+
reads its markup, so the move is an import change — or one command: `npx svg-scroll-draw migrate`. Keep every `data-aos`, `data-aos-offset`,
|
|
367
367
|
`data-aos-delay`, `data-aos-anchor-placement` and custom animation; delete `aos.css` — the styles ship
|
|
368
368
|
inside the module. 3.0 KB gzipped with the styles, against 6.7 KB for AOS 2.3.4 with its stylesheet.
|
|
369
369
|
|
|
@@ -403,7 +403,8 @@ Differences, on purpose:
|
|
|
403
403
|
|
|
404
404
|
On [ScrollReveal](https://scrollrevealjs.org)? It is GPL-3.0 (with a paid licence for commercial work)
|
|
405
405
|
and has not shipped since 4.0.9. `svg-scroll-draw/scrollreveal` is an independent, MIT-licensed
|
|
406
|
-
implementation of the same API, so the move is an import change
|
|
406
|
+
implementation of the same API, so the move is an import change — or one command: `npx svg-scroll-draw migrate`.
|
|
407
|
+
4.5 KB gzipped, against 5.6 KB.
|
|
407
408
|
|
|
408
409
|
```diff
|
|
409
410
|
- import ScrollReveal from 'scrollreveal';
|
|
@@ -434,8 +435,8 @@ Differences, on purpose:
|
|
|
434
435
|
## vivus drop-in — keep your `new Vivus()` code
|
|
435
436
|
|
|
436
437
|
On [vivus](https://github.com/maxwellito/vivus)? It has not shipped since 0.4.6 (April 2021).
|
|
437
|
-
`svg-scroll-draw/vivus` runs the same API, so the move is an import change
|
|
438
|
-
4.1 KB.
|
|
438
|
+
`svg-scroll-draw/vivus` runs the same API, so the move is an import change — or one command:
|
|
439
|
+
`npx svg-scroll-draw migrate`. 3.9 KB gzipped, against 4.1 KB.
|
|
439
440
|
|
|
440
441
|
```diff
|
|
441
442
|
- import Vivus from 'vivus';
|
|
@@ -604,6 +605,19 @@ npx svg-scroll-draw init
|
|
|
604
605
|
|
|
605
606
|
Scaffolds a ready-to-use starter file for React, Vue, Svelte, Solid, or Vanilla JS.
|
|
606
607
|
|
|
608
|
+
### Switching from AOS, ScrollReveal or vivus
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
npx svg-scroll-draw migrate --dry-run # see what would change
|
|
612
|
+
npx svg-scroll-draw migrate # apply it
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
Points every `import` / `require` of `aos`, `scrollreveal` and `vivus` at the matching drop-in, swaps CDN
|
|
616
|
+
`<script>` tags for the script-tag builds (dropping any stale `integrity` hash), removes AOS's `aos.css`
|
|
617
|
+
imports, `<link>`s and `@import`s, and swaps the dependency in `package.json`. It rewrites module names,
|
|
618
|
+
URLs and dependency entries only — never the code that uses them — skips `node_modules` and build output,
|
|
619
|
+
and will not write over uncommitted git changes unless you pass `--force`.
|
|
620
|
+
|
|
607
621
|
---
|
|
608
622
|
|
|
609
623
|
## Browser support
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
type AOSAnchorPlacement = 'top-bottom' | 'top-center' | 'top-top' | 'center-bottom' | 'center-center' | 'center-top' | 'bottom-bottom' | 'bottom-center' | 'bottom-top';
|
|
2
|
+
interface AOSOptions {
|
|
3
|
+
/** Px from the trigger point before the animation starts. Default 120. */
|
|
4
|
+
offset?: number;
|
|
5
|
+
/** Ms to wait before animating in. Default 0. */
|
|
6
|
+
delay?: number;
|
|
7
|
+
/** Animation length in ms. Default 400. */
|
|
8
|
+
duration?: number;
|
|
9
|
+
/** An AOS easing name (`'ease-out-back'`…) or any CSS timing function. Default `'ease'`. */
|
|
10
|
+
easing?: string;
|
|
11
|
+
/** Animate only the first time the element scrolls in. Default false. */
|
|
12
|
+
once?: boolean;
|
|
13
|
+
/** Animate out again when the element scrolls past the top. Default false. */
|
|
14
|
+
mirror?: boolean;
|
|
15
|
+
/** Which edge of the element meets which edge of the window. Default `'top-bottom'`. */
|
|
16
|
+
anchorPlacement?: AOSAnchorPlacement;
|
|
17
|
+
/** Skip animations entirely: a boolean, a predicate, or a viewport class. */
|
|
18
|
+
disable?: boolean | 'phone' | 'tablet' | 'mobile' | (() => boolean);
|
|
19
|
+
/** Document event that starts AOS. Default `'DOMContentLoaded'`. */
|
|
20
|
+
startEvent?: string;
|
|
21
|
+
/** Do not watch the DOM for new `[data-aos]` elements. Default false. */
|
|
22
|
+
disableMutationObserver?: boolean;
|
|
23
|
+
/** Class added at init. Default `'aos-init'`. */
|
|
24
|
+
initClassName?: string;
|
|
25
|
+
/** Class added while animated in. Default `'aos-animate'`. */
|
|
26
|
+
animatedClassName?: string;
|
|
27
|
+
/** Also add the `data-aos` value as classes (for animate.css-style sets). Default false. */
|
|
28
|
+
useClassNames?: boolean;
|
|
29
|
+
/** Accepted for compatibility; scroll handling is batched per frame instead. */
|
|
30
|
+
throttleDelay?: number;
|
|
31
|
+
/** Accepted for compatibility; resize handling is debounced internally. */
|
|
32
|
+
debounceDelay?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Start animating every `[data-aos]` element. Same options as AOS. */
|
|
35
|
+
declare function init(options?: AOSOptions): HTMLElement[];
|
|
36
|
+
/** Recalculate every trigger position (after a layout change). */
|
|
37
|
+
declare function refresh(): void;
|
|
38
|
+
/** Find `[data-aos]` elements again (after adding or removing some), then refresh. */
|
|
39
|
+
declare function refreshHard(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Stop listening and remove the injected stylesheet. Not in AOS — added for
|
|
42
|
+
* single-page apps that unmount the page AOS was started on. Elements keep
|
|
43
|
+
* whatever classes they have.
|
|
44
|
+
*/
|
|
45
|
+
declare function destroy(): void;
|
|
46
|
+
declare const AOS: {
|
|
47
|
+
init: typeof init;
|
|
48
|
+
refresh: typeof refresh;
|
|
49
|
+
refreshHard: typeof refreshHard;
|
|
50
|
+
destroy: typeof destroy;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { type AOSAnchorPlacement, type AOSOptions, AOS as default, destroy, init, refresh, refreshHard };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
type AOSAnchorPlacement = 'top-bottom' | 'top-center' | 'top-top' | 'center-bottom' | 'center-center' | 'center-top' | 'bottom-bottom' | 'bottom-center' | 'bottom-top';
|
|
2
|
+
interface AOSOptions {
|
|
3
|
+
/** Px from the trigger point before the animation starts. Default 120. */
|
|
4
|
+
offset?: number;
|
|
5
|
+
/** Ms to wait before animating in. Default 0. */
|
|
6
|
+
delay?: number;
|
|
7
|
+
/** Animation length in ms. Default 400. */
|
|
8
|
+
duration?: number;
|
|
9
|
+
/** An AOS easing name (`'ease-out-back'`…) or any CSS timing function. Default `'ease'`. */
|
|
10
|
+
easing?: string;
|
|
11
|
+
/** Animate only the first time the element scrolls in. Default false. */
|
|
12
|
+
once?: boolean;
|
|
13
|
+
/** Animate out again when the element scrolls past the top. Default false. */
|
|
14
|
+
mirror?: boolean;
|
|
15
|
+
/** Which edge of the element meets which edge of the window. Default `'top-bottom'`. */
|
|
16
|
+
anchorPlacement?: AOSAnchorPlacement;
|
|
17
|
+
/** Skip animations entirely: a boolean, a predicate, or a viewport class. */
|
|
18
|
+
disable?: boolean | 'phone' | 'tablet' | 'mobile' | (() => boolean);
|
|
19
|
+
/** Document event that starts AOS. Default `'DOMContentLoaded'`. */
|
|
20
|
+
startEvent?: string;
|
|
21
|
+
/** Do not watch the DOM for new `[data-aos]` elements. Default false. */
|
|
22
|
+
disableMutationObserver?: boolean;
|
|
23
|
+
/** Class added at init. Default `'aos-init'`. */
|
|
24
|
+
initClassName?: string;
|
|
25
|
+
/** Class added while animated in. Default `'aos-animate'`. */
|
|
26
|
+
animatedClassName?: string;
|
|
27
|
+
/** Also add the `data-aos` value as classes (for animate.css-style sets). Default false. */
|
|
28
|
+
useClassNames?: boolean;
|
|
29
|
+
/** Accepted for compatibility; scroll handling is batched per frame instead. */
|
|
30
|
+
throttleDelay?: number;
|
|
31
|
+
/** Accepted for compatibility; resize handling is debounced internally. */
|
|
32
|
+
debounceDelay?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Start animating every `[data-aos]` element. Same options as AOS. */
|
|
35
|
+
declare function init(options?: AOSOptions): HTMLElement[];
|
|
36
|
+
/** Recalculate every trigger position (after a layout change). */
|
|
37
|
+
declare function refresh(): void;
|
|
38
|
+
/** Find `[data-aos]` elements again (after adding or removing some), then refresh. */
|
|
39
|
+
declare function refreshHard(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Stop listening and remove the injected stylesheet. Not in AOS — added for
|
|
42
|
+
* single-page apps that unmount the page AOS was started on. Elements keep
|
|
43
|
+
* whatever classes they have.
|
|
44
|
+
*/
|
|
45
|
+
declare function destroy(): void;
|
|
46
|
+
declare const AOS: {
|
|
47
|
+
init: typeof init;
|
|
48
|
+
refresh: typeof refresh;
|
|
49
|
+
refreshHard: typeof refreshHard;
|
|
50
|
+
destroy: typeof destroy;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { type AOSAnchorPlacement, type AOSOptions, AOS as default, destroy, init, refresh, refreshHard };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
type StoryEasing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | 'bounce' | 'elastic';
|
|
2
|
+
/** A traced path that strokes itself on across a scroll range. */
|
|
3
|
+
interface DrawAnimation {
|
|
4
|
+
type: 'draw';
|
|
5
|
+
/** DOM id the runtime binds to (with leading '#'), e.g. "#path-3". */
|
|
6
|
+
target: string;
|
|
7
|
+
/** SVG path data, in canvas coordinates. */
|
|
8
|
+
d: string;
|
|
9
|
+
/** Pre-measured total path length (px). */
|
|
10
|
+
length: number;
|
|
11
|
+
/** Scroll progress where the draw begins, e.g. "20%". */
|
|
12
|
+
start: string;
|
|
13
|
+
/** Scroll progress where the draw completes, e.g. "50%". */
|
|
14
|
+
end: string;
|
|
15
|
+
stroke: string;
|
|
16
|
+
strokeWidth: number;
|
|
17
|
+
easing: StoryEasing;
|
|
18
|
+
}
|
|
19
|
+
/** Any layer fading opacity across a scroll range. */
|
|
20
|
+
interface FadeAnimation {
|
|
21
|
+
type: 'fade';
|
|
22
|
+
target: string;
|
|
23
|
+
start: string;
|
|
24
|
+
end: string;
|
|
25
|
+
from: number;
|
|
26
|
+
to: number;
|
|
27
|
+
}
|
|
28
|
+
type StoryAnimation = DrawAnimation | FadeAnimation;
|
|
29
|
+
interface StoryScene {
|
|
30
|
+
id: string;
|
|
31
|
+
/** Optional background layer (a product photo) as a data URL or remote URL. */
|
|
32
|
+
background?: string;
|
|
33
|
+
animations: StoryAnimation[];
|
|
34
|
+
}
|
|
35
|
+
interface Story {
|
|
36
|
+
version: 1;
|
|
37
|
+
/** Total scroll height of the experience, e.g. "400vh". */
|
|
38
|
+
totalHeight: string;
|
|
39
|
+
/** The authoring viewBox the coordinates are expressed in. */
|
|
40
|
+
canvas: {
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
};
|
|
44
|
+
scenes: StoryScene[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface CinematicOptions {
|
|
48
|
+
/** Mount point — a selector or element. Becomes the scroll wrapper. */
|
|
49
|
+
wrapper: string | HTMLElement;
|
|
50
|
+
}
|
|
51
|
+
interface CinematicInstance {
|
|
52
|
+
/** Stop the scroll loop and detach observers (built DOM is left in place). */
|
|
53
|
+
destroy: () => void;
|
|
54
|
+
/** Current global scroll progress through the story (0–1). */
|
|
55
|
+
getProgress: () => number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The viral loader. Reads a Cinematic Story (authored in the Studio) and wires
|
|
59
|
+
* a scroll-scrubbed timeline: paths stroke themselves on and layers fade in as
|
|
60
|
+
* the user scrolls, all driven off the wrapper's scroll progress.
|
|
61
|
+
*
|
|
62
|
+
* import { Cinematic } from "svg-scroll-draw";
|
|
63
|
+
* import story from "./story.json";
|
|
64
|
+
* new Cinematic({ wrapper: "#app" }).loadStory(story);
|
|
65
|
+
*/
|
|
66
|
+
declare class Cinematic {
|
|
67
|
+
private mount;
|
|
68
|
+
constructor(options: CinematicOptions);
|
|
69
|
+
loadStory(story: Story): CinematicInstance;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { Cinematic, type CinematicInstance, type CinematicOptions, type DrawAnimation, type FadeAnimation, type Story, type StoryAnimation, type StoryEasing, type StoryScene };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
type StoryEasing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | 'bounce' | 'elastic';
|
|
2
|
+
/** A traced path that strokes itself on across a scroll range. */
|
|
3
|
+
interface DrawAnimation {
|
|
4
|
+
type: 'draw';
|
|
5
|
+
/** DOM id the runtime binds to (with leading '#'), e.g. "#path-3". */
|
|
6
|
+
target: string;
|
|
7
|
+
/** SVG path data, in canvas coordinates. */
|
|
8
|
+
d: string;
|
|
9
|
+
/** Pre-measured total path length (px). */
|
|
10
|
+
length: number;
|
|
11
|
+
/** Scroll progress where the draw begins, e.g. "20%". */
|
|
12
|
+
start: string;
|
|
13
|
+
/** Scroll progress where the draw completes, e.g. "50%". */
|
|
14
|
+
end: string;
|
|
15
|
+
stroke: string;
|
|
16
|
+
strokeWidth: number;
|
|
17
|
+
easing: StoryEasing;
|
|
18
|
+
}
|
|
19
|
+
/** Any layer fading opacity across a scroll range. */
|
|
20
|
+
interface FadeAnimation {
|
|
21
|
+
type: 'fade';
|
|
22
|
+
target: string;
|
|
23
|
+
start: string;
|
|
24
|
+
end: string;
|
|
25
|
+
from: number;
|
|
26
|
+
to: number;
|
|
27
|
+
}
|
|
28
|
+
type StoryAnimation = DrawAnimation | FadeAnimation;
|
|
29
|
+
interface StoryScene {
|
|
30
|
+
id: string;
|
|
31
|
+
/** Optional background layer (a product photo) as a data URL or remote URL. */
|
|
32
|
+
background?: string;
|
|
33
|
+
animations: StoryAnimation[];
|
|
34
|
+
}
|
|
35
|
+
interface Story {
|
|
36
|
+
version: 1;
|
|
37
|
+
/** Total scroll height of the experience, e.g. "400vh". */
|
|
38
|
+
totalHeight: string;
|
|
39
|
+
/** The authoring viewBox the coordinates are expressed in. */
|
|
40
|
+
canvas: {
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
};
|
|
44
|
+
scenes: StoryScene[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface CinematicOptions {
|
|
48
|
+
/** Mount point — a selector or element. Becomes the scroll wrapper. */
|
|
49
|
+
wrapper: string | HTMLElement;
|
|
50
|
+
}
|
|
51
|
+
interface CinematicInstance {
|
|
52
|
+
/** Stop the scroll loop and detach observers (built DOM is left in place). */
|
|
53
|
+
destroy: () => void;
|
|
54
|
+
/** Current global scroll progress through the story (0–1). */
|
|
55
|
+
getProgress: () => number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The viral loader. Reads a Cinematic Story (authored in the Studio) and wires
|
|
59
|
+
* a scroll-scrubbed timeline: paths stroke themselves on and layers fade in as
|
|
60
|
+
* the user scrolls, all driven off the wrapper's scroll progress.
|
|
61
|
+
*
|
|
62
|
+
* import { Cinematic } from "svg-scroll-draw";
|
|
63
|
+
* import story from "./story.json";
|
|
64
|
+
* new Cinematic({ wrapper: "#app" }).loadStory(story);
|
|
65
|
+
*/
|
|
66
|
+
declare class Cinematic {
|
|
67
|
+
private mount;
|
|
68
|
+
constructor(options: CinematicOptions);
|
|
69
|
+
loadStory(story: Story): CinematicInstance;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { Cinematic, type CinematicInstance, type CinematicOptions, type DrawAnimation, type FadeAnimation, type Story, type StoryAnimation, type StoryEasing, type StoryScene };
|
package/dist/cli/init.js
CHANGED
|
@@ -25,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli/init.ts
|
|
27
27
|
var readline = __toESM(require("readline"));
|
|
28
|
-
var
|
|
29
|
-
var
|
|
28
|
+
var fs2 = __toESM(require("fs"));
|
|
29
|
+
var path2 = __toESM(require("path"));
|
|
30
30
|
|
|
31
31
|
// src/cli/generators.ts
|
|
32
32
|
var SAMPLE_SVG_JSX = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
|
|
@@ -138,6 +138,254 @@ function needsSelector(framework) {
|
|
|
138
138
|
return framework === "vanilla";
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
// src/cli/migrate.ts
|
|
142
|
+
var fs = __toESM(require("fs"));
|
|
143
|
+
var path = __toESM(require("path"));
|
|
144
|
+
var import_node_child_process = require("child_process");
|
|
145
|
+
var LIBS = ["aos", "scrollreveal", "vivus"];
|
|
146
|
+
var LABEL = { aos: "AOS", scrollreveal: "ScrollReveal", vivus: "vivus" };
|
|
147
|
+
var esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
148
|
+
function rewriteSpecifiers(src, changes) {
|
|
149
|
+
let out = src;
|
|
150
|
+
for (const lib of LIBS) {
|
|
151
|
+
const spec = lib === "aos" ? `aos(?:\\/dist\\/aos(?:\\.js)?)?` : esc(lib);
|
|
152
|
+
const target = `svg-scroll-draw/${lib}`;
|
|
153
|
+
const fromRe = new RegExp(`(\\bfrom\\s*)(['"])${spec}\\2`, "g");
|
|
154
|
+
const dynRe = new RegExp(`(\\bimport\\s*\\(\\s*)(['"])${spec}\\2(\\s*\\))`, "g");
|
|
155
|
+
const reqRe = new RegExp(`(\\brequire\\s*\\(\\s*)(['"])${spec}\\2(\\s*\\))`, "g");
|
|
156
|
+
let n = 0;
|
|
157
|
+
out = out.replace(fromRe, (_m, pre, q) => {
|
|
158
|
+
n++;
|
|
159
|
+
return `${pre}${q}${target}${q}`;
|
|
160
|
+
});
|
|
161
|
+
out = out.replace(dynRe, (_m, pre, q, post) => {
|
|
162
|
+
n++;
|
|
163
|
+
return `${pre}${q}${target}${q}${post}`;
|
|
164
|
+
});
|
|
165
|
+
out = out.replace(reqRe, (_m, pre, q, post) => {
|
|
166
|
+
n++;
|
|
167
|
+
return lib === "aos" ? `${pre}${q}${target}${q}${post}` : `${pre}${q}${target}${q}${post}.default`;
|
|
168
|
+
});
|
|
169
|
+
if (n) changes.push(`${LABEL[lib]}: ${n} import${n === 1 ? "" : "s"} \u2192 ${target}`);
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
function dropAosCssImports(src, changes) {
|
|
174
|
+
let n = 0;
|
|
175
|
+
const out = src.replace(/^[ \t]*import\s+(['"])aos\/dist\/aos(?:\.min)?\.css\1;?[ \t]*\r?\n?/gm, () => {
|
|
176
|
+
n++;
|
|
177
|
+
return "";
|
|
178
|
+
}).replace(/^[ \t]*require\s*\(\s*(['"])aos\/dist\/aos(?:\.min)?\.css\1\s*\);?[ \t]*\r?\n?/gm, () => {
|
|
179
|
+
n++;
|
|
180
|
+
return "";
|
|
181
|
+
});
|
|
182
|
+
if (n) changes.push(`AOS: removed ${n} aos.css import${n === 1 ? "" : "s"} (the drop-in ships its styles)`);
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
var SCRIPT_URL = {
|
|
186
|
+
aos: /^(?:https?:)?\/\/(?:unpkg\.com\/aos(?:@[^/]+)?(?:\/dist\/aos(?:\.min)?\.js)?|cdn\.jsdelivr\.net\/npm\/aos(?:@[^/]+)?(?:\/dist\/aos(?:\.min)?\.js)?|cdnjs\.cloudflare\.com\/ajax\/libs\/aos\/[^/]+\/aos(?:\.min)?\.js)$|(?:^|\/)node_modules\/aos\/dist\/aos(?:\.min)?\.js$/,
|
|
187
|
+
scrollreveal: /^(?:https?:)?\/\/(?:unpkg\.com\/scrollreveal(?:@[^/]+)?(?:\/dist\/scrollreveal(?:\.min)?\.js)?|cdn\.jsdelivr\.net\/npm\/scrollreveal(?:@[^/]+)?(?:\/dist\/scrollreveal(?:\.min)?\.js)?|cdnjs\.cloudflare\.com\/ajax\/libs\/scrollReveal\.js\/[^/]+\/scrollreveal(?:\.min)?\.js)$|(?:^|\/)node_modules\/scrollreveal\/dist\/scrollreveal(?:\.min)?\.js$/i,
|
|
188
|
+
vivus: /^(?:https?:)?\/\/(?:unpkg\.com\/vivus(?:@[^/]+)?(?:\/dist\/vivus(?:\.min)?\.js)?|cdn\.jsdelivr\.net\/npm\/vivus(?:@[^/]+)?(?:\/dist\/vivus(?:\.min)?\.js)?|cdnjs\.cloudflare\.com\/ajax\/libs\/vivus\/[^/]+\/vivus(?:\.min)?\.js)$|(?:^|\/)node_modules\/vivus\/dist\/vivus(?:\.min)?\.js$/
|
|
189
|
+
};
|
|
190
|
+
var AOS_CSS_URL = /^(?:https?:)?\/\/(?:unpkg\.com\/aos(?:@[^/]+)?\/dist\/aos\.css|cdn\.jsdelivr\.net\/npm\/aos(?:@[^/]+)?\/dist\/aos\.css|cdnjs\.cloudflare\.com\/ajax\/libs\/aos\/[^/]+\/aos(?:\.min)?\.css)$|(?:^|\/)node_modules\/aos\/dist\/aos\.css$/;
|
|
191
|
+
function rewriteScriptTags(src, version, changes) {
|
|
192
|
+
return src.replace(/<script\b([^>]*)>/gi, (tag, attrs) => {
|
|
193
|
+
const m = /\bsrc\s*=\s*(["'])([^"']+)\1/i.exec(attrs);
|
|
194
|
+
if (!m) return tag;
|
|
195
|
+
const lib = LIBS.find((l) => SCRIPT_URL[l].test(m[2]));
|
|
196
|
+
if (!lib) return tag;
|
|
197
|
+
const url = `https://unpkg.com/svg-scroll-draw@${version}/dist/cdn/${lib}.global.js`;
|
|
198
|
+
const hadIntegrity = /\bintegrity\s*=/i.test(attrs);
|
|
199
|
+
const next = attrs.replace(m[0], `src=${m[1]}${url}${m[1]}`).replace(/\s+integrity\s*=\s*(["'])[^"']*\1/gi, "");
|
|
200
|
+
changes.push(`${LABEL[lib]}: <script> \u2192 ${url}${hadIntegrity ? " (old integrity hash removed)" : ""}`);
|
|
201
|
+
return `<script${next}>`;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function dropAosCssLinks(src, changes) {
|
|
205
|
+
let n = 0;
|
|
206
|
+
const out = src.replace(/^[ \t]*<link\b[^>]*>[ \t]*\r?\n?/gim, (line) => {
|
|
207
|
+
const m = /\bhref\s*=\s*(["'])([^"']+)\1/i.exec(line);
|
|
208
|
+
if (m && AOS_CSS_URL.test(m[2])) {
|
|
209
|
+
n++;
|
|
210
|
+
return "";
|
|
211
|
+
}
|
|
212
|
+
return line;
|
|
213
|
+
});
|
|
214
|
+
if (n) changes.push(`AOS: removed ${n} aos.css <link> (the drop-in ships its styles)`);
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
function dropAosCssAtImports(src, changes) {
|
|
218
|
+
let n = 0;
|
|
219
|
+
const out = src.replace(
|
|
220
|
+
/^[ \t]*@import\s+(?:url\(\s*)?(['"]?)~?aos\/dist\/aos(?:\.min)?\.css\1\s*\)?\s*;?[ \t]*\r?\n?/gm,
|
|
221
|
+
() => {
|
|
222
|
+
n++;
|
|
223
|
+
return "";
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
if (n) changes.push(`AOS: removed ${n} @import of aos.css (the drop-in ships its styles)`);
|
|
227
|
+
return out;
|
|
228
|
+
}
|
|
229
|
+
var SCRIPT_EXT = /\.(?:[cm]?[jt]sx?|vue|svelte|astro)$/i;
|
|
230
|
+
var HTML_EXT = /\.(?:html?|vue|svelte|astro|php|ejs|hbs|njk|liquid|erb)$/i;
|
|
231
|
+
var CSS_EXT = /\.(?:css|scss|sass|less)$/i;
|
|
232
|
+
function migrateSource(src, filename, version) {
|
|
233
|
+
const changes = [];
|
|
234
|
+
let code = src;
|
|
235
|
+
if (SCRIPT_EXT.test(filename)) {
|
|
236
|
+
code = dropAosCssImports(code, changes);
|
|
237
|
+
code = rewriteSpecifiers(code, changes);
|
|
238
|
+
}
|
|
239
|
+
if (HTML_EXT.test(filename)) {
|
|
240
|
+
code = rewriteScriptTags(code, version, changes);
|
|
241
|
+
code = dropAosCssLinks(code, changes);
|
|
242
|
+
}
|
|
243
|
+
if (CSS_EXT.test(filename) || /\.(?:vue|svelte|astro)$/i.test(filename)) {
|
|
244
|
+
code = dropAosCssAtImports(code, changes);
|
|
245
|
+
}
|
|
246
|
+
return { code, changes };
|
|
247
|
+
}
|
|
248
|
+
function migratePackageJson(text, version) {
|
|
249
|
+
const changes = [];
|
|
250
|
+
let pkg;
|
|
251
|
+
try {
|
|
252
|
+
pkg = JSON.parse(text);
|
|
253
|
+
} catch {
|
|
254
|
+
return { code: text, changes };
|
|
255
|
+
}
|
|
256
|
+
const remove = [...LIBS, "@types/aos"];
|
|
257
|
+
let home = null;
|
|
258
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
259
|
+
const deps = pkg[field];
|
|
260
|
+
if (!deps) continue;
|
|
261
|
+
for (const name of remove) {
|
|
262
|
+
if (name in deps) {
|
|
263
|
+
delete deps[name];
|
|
264
|
+
changes.push(`package.json: removed ${name} from ${field}`);
|
|
265
|
+
if (!home && name !== "@types/aos") home = field;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (!home) return { code: text, changes };
|
|
270
|
+
const already = ["dependencies", "devDependencies"].some(
|
|
271
|
+
(f) => pkg[f]?.["svg-scroll-draw"]
|
|
272
|
+
);
|
|
273
|
+
if (!already) {
|
|
274
|
+
const deps = pkg[home] ?? (pkg[home] = {});
|
|
275
|
+
deps["svg-scroll-draw"] = `^${version}`;
|
|
276
|
+
pkg[home] = Object.fromEntries(Object.entries(deps).sort(([a], [b]) => a.localeCompare(b)));
|
|
277
|
+
changes.push(`package.json: added svg-scroll-draw ^${version} to ${home}`);
|
|
278
|
+
}
|
|
279
|
+
const indent = /^\{\r?\n(\t| +)/.exec(text)?.[1] ?? " ";
|
|
280
|
+
return { code: JSON.stringify(pkg, null, indent) + (text.endsWith("\n") ? "\n" : ""), changes };
|
|
281
|
+
}
|
|
282
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
283
|
+
"node_modules",
|
|
284
|
+
".git",
|
|
285
|
+
"dist",
|
|
286
|
+
"build",
|
|
287
|
+
"out",
|
|
288
|
+
".next",
|
|
289
|
+
".nuxt",
|
|
290
|
+
".output",
|
|
291
|
+
".svelte-kit",
|
|
292
|
+
".vercel",
|
|
293
|
+
".netlify",
|
|
294
|
+
".turbo",
|
|
295
|
+
".cache",
|
|
296
|
+
"coverage",
|
|
297
|
+
".parcel-cache",
|
|
298
|
+
"vendor"
|
|
299
|
+
]);
|
|
300
|
+
var MAX_BYTES = 2 * 1024 * 1024;
|
|
301
|
+
function* walk(dir) {
|
|
302
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
303
|
+
if (entry.isDirectory()) {
|
|
304
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith(".")) yield* walk(path.join(dir, entry.name));
|
|
305
|
+
} else if (entry.isFile()) {
|
|
306
|
+
yield path.join(dir, entry.name);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function installCommand(dir) {
|
|
311
|
+
if (fs.existsSync(path.join(dir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
312
|
+
if (fs.existsSync(path.join(dir, "yarn.lock"))) return "yarn install";
|
|
313
|
+
if (fs.existsSync(path.join(dir, "bun.lockb")) || fs.existsSync(path.join(dir, "bun.lock"))) return "bun install";
|
|
314
|
+
return "npm install";
|
|
315
|
+
}
|
|
316
|
+
function gitDirty(dir) {
|
|
317
|
+
try {
|
|
318
|
+
return (0, import_node_child_process.execSync)("git status --porcelain", { cwd: dir, stdio: ["ignore", "pipe", "ignore"] }).toString().trim() !== "";
|
|
319
|
+
} catch {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
var HELP = `
|
|
324
|
+
svg-scroll-draw migrate [dir] [--dry-run] [--force]
|
|
325
|
+
|
|
326
|
+
Moves a project off AOS, ScrollReveal and vivus onto svg-scroll-draw's drop-ins:
|
|
327
|
+
\u2022 imports / requires of 'aos', 'scrollreveal', 'vivus' \u2192 svg-scroll-draw/<lib>
|
|
328
|
+
\u2022 CDN <script> tags \u2192 svg-scroll-draw's script-tag builds
|
|
329
|
+
\u2022 AOS's aos.css imports, <link>s and @imports removed (the drop-in ships its styles)
|
|
330
|
+
\u2022 package.json: the old packages swapped for svg-scroll-draw
|
|
331
|
+
|
|
332
|
+
--dry-run show what would change, write nothing
|
|
333
|
+
--force write even if the git working tree has uncommitted changes
|
|
334
|
+
`;
|
|
335
|
+
function runMigrate(args, version, log = console.log) {
|
|
336
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
337
|
+
log(HELP);
|
|
338
|
+
return 0;
|
|
339
|
+
}
|
|
340
|
+
const dryRun = args.includes("--dry-run");
|
|
341
|
+
const force = args.includes("--force");
|
|
342
|
+
const dir = path.resolve(args.find((a) => !a.startsWith("-")) ?? ".");
|
|
343
|
+
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
344
|
+
log(` \u2717 Not a directory: ${dir}`);
|
|
345
|
+
return 1;
|
|
346
|
+
}
|
|
347
|
+
const edits = [];
|
|
348
|
+
for (const file of walk(dir)) {
|
|
349
|
+
const base = path.basename(file);
|
|
350
|
+
const isPkg = base === "package.json";
|
|
351
|
+
if (!isPkg && !SCRIPT_EXT.test(base) && !HTML_EXT.test(base) && !CSS_EXT.test(base)) continue;
|
|
352
|
+
if (fs.statSync(file).size > MAX_BYTES) continue;
|
|
353
|
+
const text = fs.readFileSync(file, "utf8");
|
|
354
|
+
if (!isPkg && !/aos|scrollreveal|vivus/i.test(text)) continue;
|
|
355
|
+
const result = isPkg ? migratePackageJson(text, version) : migrateSource(text, base, version);
|
|
356
|
+
if (result.changes.length && result.code !== text) edits.push({ file, code: result.code, changes: result.changes });
|
|
357
|
+
}
|
|
358
|
+
log(`
|
|
359
|
+
svg-scroll-draw migrate${dryRun ? " (dry run)" : ""} \u2014 ${dir}
|
|
360
|
+
`);
|
|
361
|
+
if (!edits.length) {
|
|
362
|
+
log(" No AOS, ScrollReveal or vivus usage found. Nothing to do.\n");
|
|
363
|
+
return 0;
|
|
364
|
+
}
|
|
365
|
+
for (const { file, changes } of edits) {
|
|
366
|
+
log(` ${path.relative(dir, file) || path.basename(file)}`);
|
|
367
|
+
for (const c of changes) log(` \u2022 ${c}`);
|
|
368
|
+
}
|
|
369
|
+
if (dryRun) {
|
|
370
|
+
log(`
|
|
371
|
+
${edits.length} file${edits.length === 1 ? "" : "s"} would change. Run again without --dry-run to apply.
|
|
372
|
+
`);
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
if (!force && gitDirty(dir)) {
|
|
376
|
+
log("\n \u2717 The git working tree has uncommitted changes. Commit or stash them first so the");
|
|
377
|
+
log(" migration is a clean diff you can review, or pass --force to write anyway.\n");
|
|
378
|
+
return 1;
|
|
379
|
+
}
|
|
380
|
+
for (const { file, code } of edits) fs.writeFileSync(file, code);
|
|
381
|
+
const touchedPkg = edits.some((e) => path.basename(e.file) === "package.json");
|
|
382
|
+
log(`
|
|
383
|
+
\u2713 Updated ${edits.length} file${edits.length === 1 ? "" : "s"}.`);
|
|
384
|
+
log(` Next: ${touchedPkg ? `run \`${installCommand(dir)}\`, then ` : ""}review the diff (git diff) and try the page.
|
|
385
|
+
`);
|
|
386
|
+
return 0;
|
|
387
|
+
}
|
|
388
|
+
|
|
141
389
|
// src/cli/init.ts
|
|
142
390
|
var RESET = "\x1B[0m";
|
|
143
391
|
var BOLD = "\x1B[1m";
|
|
@@ -147,19 +395,19 @@ var GREEN = "\x1B[32m";
|
|
|
147
395
|
var CYAN = "\x1B[36m";
|
|
148
396
|
function ask(rl, question, fallback) {
|
|
149
397
|
return new Promise(
|
|
150
|
-
(
|
|
151
|
-
|
|
398
|
+
(resolve2) => rl.question(` ${CYAN}?${RESET} ${question} ${DIM}(${fallback})${RESET} `, (ans) => {
|
|
399
|
+
resolve2(ans.trim() || fallback);
|
|
152
400
|
})
|
|
153
401
|
);
|
|
154
402
|
}
|
|
155
403
|
function pick(rl, question, options, fallback) {
|
|
156
404
|
const opts = options.map((o, i) => `${DIM}${i + 1})${RESET} ${o}`).join(" ");
|
|
157
405
|
return new Promise(
|
|
158
|
-
(
|
|
406
|
+
(resolve2) => rl.question(` ${CYAN}?${RESET} ${question}
|
|
159
407
|
${opts}
|
|
160
408
|
${DIM}(${fallback})${RESET} `, (ans) => {
|
|
161
409
|
const idx = parseInt(ans) - 1;
|
|
162
|
-
|
|
410
|
+
resolve2(idx >= 0 && idx < options.length ? options[idx] : fallback);
|
|
163
411
|
})
|
|
164
412
|
);
|
|
165
413
|
}
|
|
@@ -179,8 +427,8 @@ async function main() {
|
|
|
179
427
|
}
|
|
180
428
|
const selector = needsSelector(framework) ? await ask(rl, "CSS selector for your SVG container?", "#my-svg") : "#my-svg";
|
|
181
429
|
const outFile = FILE_NAMES[framework] ?? "scroll-draw.js";
|
|
182
|
-
const outPath =
|
|
183
|
-
if (
|
|
430
|
+
const outPath = path2.join(process.cwd(), outFile);
|
|
431
|
+
if (fs2.existsSync(outPath)) {
|
|
184
432
|
const overwrite = await ask(rl, `${outFile} already exists. Overwrite?`, "y");
|
|
185
433
|
if (overwrite.toLowerCase() !== "y") {
|
|
186
434
|
console.log(`
|
|
@@ -190,7 +438,7 @@ async function main() {
|
|
|
190
438
|
}
|
|
191
439
|
}
|
|
192
440
|
const code = GENERATORS[framework]?.({ selector, easing, preset }) ?? "";
|
|
193
|
-
|
|
441
|
+
fs2.writeFileSync(outPath, code, "utf8");
|
|
194
442
|
console.log(`
|
|
195
443
|
${GREEN}\u2713${RESET} ${BOLD}${outFile}${RESET} created.
|
|
196
444
|
`);
|
|
@@ -208,7 +456,30 @@ async function main() {
|
|
|
208
456
|
rl.close();
|
|
209
457
|
}
|
|
210
458
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
459
|
+
function ownVersion() {
|
|
460
|
+
try {
|
|
461
|
+
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version;
|
|
462
|
+
} catch {
|
|
463
|
+
return "latest";
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
var USAGE = `
|
|
467
|
+
npx svg-scroll-draw init scaffold a starter file
|
|
468
|
+
npx svg-scroll-draw migrate switch a project from AOS, ScrollReveal or vivus (--dry-run to preview)
|
|
469
|
+
`;
|
|
470
|
+
var [command, ...rest] = process.argv.slice(2);
|
|
471
|
+
if (command === "help" || command === "--help" || command === "-h") {
|
|
472
|
+
console.log(USAGE);
|
|
473
|
+
} else if (command === "migrate") {
|
|
474
|
+
process.exitCode = runMigrate(rest, ownVersion());
|
|
475
|
+
} else if (command === void 0 || command === "init") {
|
|
476
|
+
main().catch((e) => {
|
|
477
|
+
console.error(e);
|
|
478
|
+
process.exit(1);
|
|
479
|
+
});
|
|
480
|
+
} else {
|
|
481
|
+
console.error(`
|
|
482
|
+
Unknown command "${command}".
|
|
483
|
+
${USAGE}`);
|
|
484
|
+
process.exitCode = 1;
|
|
485
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare function enable(): void;
|
|
2
|
+
declare function disable(): void;
|
|
3
|
+
declare function toggle(): void;
|
|
4
|
+
declare function highlight(target: string | Element): void;
|
|
5
|
+
declare const devtools: {
|
|
6
|
+
enable: typeof enable;
|
|
7
|
+
disable: typeof disable;
|
|
8
|
+
toggle: typeof toggle;
|
|
9
|
+
highlight: typeof highlight;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { devtools };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare function enable(): void;
|
|
2
|
+
declare function disable(): void;
|
|
3
|
+
declare function toggle(): void;
|
|
4
|
+
declare function highlight(target: string | Element): void;
|
|
5
|
+
declare const devtools: {
|
|
6
|
+
enable: typeof enable;
|
|
7
|
+
disable: typeof disable;
|
|
8
|
+
toggle: typeof toggle;
|
|
9
|
+
highlight: typeof highlight;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { devtools };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | 'bounce' | 'elastic';
|
|
2
|
+
interface TriggerConfig {
|
|
3
|
+
start?: string;
|
|
4
|
+
end?: string;
|
|
5
|
+
}
|
|
6
|
+
interface ScrollDrawInstance {
|
|
7
|
+
destroy: () => void;
|
|
8
|
+
/** Reset and replay the animation from the beginning. */
|
|
9
|
+
replay: () => void;
|
|
10
|
+
/** Pause the animation at the current progress. */
|
|
11
|
+
pause: () => void;
|
|
12
|
+
/** Resume a paused animation. */
|
|
13
|
+
resume: () => void;
|
|
14
|
+
/** Jump to a specific progress value (0–1) and pause. */
|
|
15
|
+
seek: (progress: number) => void;
|
|
16
|
+
/** Returns current draw progress (0–1). */
|
|
17
|
+
getProgress: () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Re-measure after a layout change: path lengths, and the scroll trigger window.
|
|
20
|
+
*
|
|
21
|
+
* The engine already re-measures on `resize`, on `orientationchange`, and via a
|
|
22
|
+
* `ResizeObserver` on the document element — but none of those fire for a layout
|
|
23
|
+
* change that leaves the document height alone, such as a tab switching, a
|
|
24
|
+
* sibling collapsing, or a font swapping inside a fixed-height box. Call this
|
|
25
|
+
* after one of those.
|
|
26
|
+
*
|
|
27
|
+
* Optional on this shared type because several instances here are fan-outs over
|
|
28
|
+
* other instances or SSR no-op stubs. `scrollDraw`, `scrollPin`,
|
|
29
|
+
* `scrollHorizontal`, `scrollDrawTimeline` and the group APIs all provide it;
|
|
30
|
+
* use `instance.refresh?.()` if you hold an instance of unknown origin.
|
|
31
|
+
*/
|
|
32
|
+
refresh?: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface ScrollTextOptions {
|
|
36
|
+
split?: 'chars' | 'words' | 'lines';
|
|
37
|
+
stagger?: number;
|
|
38
|
+
easing?: EasingName | ((t: number) => number);
|
|
39
|
+
from?: {
|
|
40
|
+
opacity?: number;
|
|
41
|
+
y?: number;
|
|
42
|
+
x?: number;
|
|
43
|
+
rotate?: number;
|
|
44
|
+
scale?: number;
|
|
45
|
+
};
|
|
46
|
+
trigger?: TriggerConfig;
|
|
47
|
+
once?: boolean;
|
|
48
|
+
onComplete?: () => void;
|
|
49
|
+
}
|
|
50
|
+
declare function scrollText(target: string | Element, options?: ScrollTextOptions): ScrollDrawInstance;
|
|
51
|
+
|
|
52
|
+
export { type ScrollTextOptions, scrollText };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | 'bounce' | 'elastic';
|
|
2
|
+
interface TriggerConfig {
|
|
3
|
+
start?: string;
|
|
4
|
+
end?: string;
|
|
5
|
+
}
|
|
6
|
+
interface ScrollDrawInstance {
|
|
7
|
+
destroy: () => void;
|
|
8
|
+
/** Reset and replay the animation from the beginning. */
|
|
9
|
+
replay: () => void;
|
|
10
|
+
/** Pause the animation at the current progress. */
|
|
11
|
+
pause: () => void;
|
|
12
|
+
/** Resume a paused animation. */
|
|
13
|
+
resume: () => void;
|
|
14
|
+
/** Jump to a specific progress value (0–1) and pause. */
|
|
15
|
+
seek: (progress: number) => void;
|
|
16
|
+
/** Returns current draw progress (0–1). */
|
|
17
|
+
getProgress: () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Re-measure after a layout change: path lengths, and the scroll trigger window.
|
|
20
|
+
*
|
|
21
|
+
* The engine already re-measures on `resize`, on `orientationchange`, and via a
|
|
22
|
+
* `ResizeObserver` on the document element — but none of those fire for a layout
|
|
23
|
+
* change that leaves the document height alone, such as a tab switching, a
|
|
24
|
+
* sibling collapsing, or a font swapping inside a fixed-height box. Call this
|
|
25
|
+
* after one of those.
|
|
26
|
+
*
|
|
27
|
+
* Optional on this shared type because several instances here are fan-outs over
|
|
28
|
+
* other instances or SSR no-op stubs. `scrollDraw`, `scrollPin`,
|
|
29
|
+
* `scrollHorizontal`, `scrollDrawTimeline` and the group APIs all provide it;
|
|
30
|
+
* use `instance.refresh?.()` if you hold an instance of unknown origin.
|
|
31
|
+
*/
|
|
32
|
+
refresh?: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface ScrollTextOptions {
|
|
36
|
+
split?: 'chars' | 'words' | 'lines';
|
|
37
|
+
stagger?: number;
|
|
38
|
+
easing?: EasingName | ((t: number) => number);
|
|
39
|
+
from?: {
|
|
40
|
+
opacity?: number;
|
|
41
|
+
y?: number;
|
|
42
|
+
x?: number;
|
|
43
|
+
rotate?: number;
|
|
44
|
+
scale?: number;
|
|
45
|
+
};
|
|
46
|
+
trigger?: TriggerConfig;
|
|
47
|
+
once?: boolean;
|
|
48
|
+
onComplete?: () => void;
|
|
49
|
+
}
|
|
50
|
+
declare function scrollText(target: string | Element, options?: ScrollTextOptions): ScrollDrawInstance;
|
|
51
|
+
|
|
52
|
+
export { type ScrollTextOptions, scrollText };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svg-scroll-draw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "Scroll-driven animation for the web — draw SVG paths, reveal elements, pin sections, scrub video. Zero dependencies, native CSS fast path, works with React, Vue, Svelte, Solid, Angular, Astro and vanilla JS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svg",
|