scroll-arrows 0.1.3 → 0.2.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 +118 -2
- package/dist/{chunk-GKWBGFLA.js → chunk-LIT577GH.js} +272 -38
- package/dist/index.cjs +274 -35
- package/dist/index.d.cts +69 -3
- package/dist/index.d.ts +69 -3
- package/dist/index.js +6 -3
- package/dist/react.cjs +294 -35
- package/dist/react.d.cts +20 -2
- package/dist/react.d.ts +20 -2
- package/dist/react.js +25 -2
- package/dist/{types-CDd8JqZX.d.cts → types-Cpvz9wtr.d.cts} +79 -1
- package/dist/{types-CDd8JqZX.d.ts → types-Cpvz9wtr.d.ts} +79 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,20 +24,24 @@ function docRect(el) {
|
|
|
24
24
|
height: r2.height
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
+
function isDegenerateRect(r2) {
|
|
28
|
+
return r2.width <= 0 || r2.height <= 0;
|
|
29
|
+
}
|
|
27
30
|
function center(r2) {
|
|
28
31
|
return { x: r2.left + r2.width / 2, y: r2.top + r2.height / 2 };
|
|
29
32
|
}
|
|
30
|
-
function socketPoint(r2, side) {
|
|
33
|
+
function socketPoint(r2, side, offset = 0) {
|
|
31
34
|
const c = center(r2);
|
|
35
|
+
const o = offset < -0.5 ? -0.5 : offset > 0.5 ? 0.5 : offset;
|
|
32
36
|
switch (side) {
|
|
33
37
|
case "top":
|
|
34
|
-
return { x: c.x, y: r2.top };
|
|
38
|
+
return { x: c.x + o * r2.width, y: r2.top };
|
|
35
39
|
case "bottom":
|
|
36
|
-
return { x: c.x, y: r2.top + r2.height };
|
|
40
|
+
return { x: c.x + o * r2.width, y: r2.top + r2.height };
|
|
37
41
|
case "left":
|
|
38
|
-
return { x: r2.left, y: c.y };
|
|
42
|
+
return { x: r2.left, y: c.y + o * r2.height };
|
|
39
43
|
case "right":
|
|
40
|
-
return { x: r2.left + r2.width, y: c.y };
|
|
44
|
+
return { x: r2.left + r2.width, y: c.y + o * r2.height };
|
|
41
45
|
default:
|
|
42
46
|
return c;
|
|
43
47
|
}
|
|
@@ -70,12 +74,12 @@ function autoSide(self, other) {
|
|
|
70
74
|
}
|
|
71
75
|
return best;
|
|
72
76
|
}
|
|
73
|
-
function resolveEndpoints(startRect, endRect, startSocket, endSocket) {
|
|
77
|
+
function resolveEndpoints(startRect, endRect, startSocket, endSocket, startOffset = 0, endOffset = 0) {
|
|
74
78
|
const s = startSocket === "auto" ? autoSide(startRect, endRect) : startSocket;
|
|
75
79
|
const e = endSocket === "auto" ? autoSide(endRect, startRect) : endSocket;
|
|
76
80
|
return {
|
|
77
|
-
start: socketPoint(startRect, s),
|
|
78
|
-
end: socketPoint(endRect, e),
|
|
81
|
+
start: socketPoint(startRect, s, startOffset),
|
|
82
|
+
end: socketPoint(endRect, e, endOffset),
|
|
79
83
|
startNormal: socketNormal(s),
|
|
80
84
|
endNormal: socketNormal(e)
|
|
81
85
|
};
|
|
@@ -98,6 +102,26 @@ function buildPath(ep, curvature, belly = { x: 0, y: 0 }) {
|
|
|
98
102
|
};
|
|
99
103
|
return `M ${r(start.x)} ${r(start.y)} C ${r(c1.x)} ${r(c1.y)} ${r(c2.x)} ${r(c2.y)} ${r(end.x)} ${r(end.y)}`;
|
|
100
104
|
}
|
|
105
|
+
function buildElbowPath(ep) {
|
|
106
|
+
const { start: s, end: e, startNormal: sn, endNormal: en } = ep;
|
|
107
|
+
const dx = e.x - s.x;
|
|
108
|
+
const dy = e.y - s.y;
|
|
109
|
+
const startVertical = sn.y !== 0 || sn.x === 0 && Math.abs(dy) >= Math.abs(dx);
|
|
110
|
+
const endVertical = en.y !== 0 || en.x === 0 && Math.abs(dy) >= Math.abs(dx);
|
|
111
|
+
let pts;
|
|
112
|
+
if (startVertical && endVertical) {
|
|
113
|
+
const midY = (s.y + e.y) / 2;
|
|
114
|
+
pts = [s, { x: s.x, y: midY }, { x: e.x, y: midY }, e];
|
|
115
|
+
} else if (!startVertical && !endVertical) {
|
|
116
|
+
const midX = (s.x + e.x) / 2;
|
|
117
|
+
pts = [s, { x: midX, y: s.y }, { x: midX, y: e.y }, e];
|
|
118
|
+
} else if (startVertical) {
|
|
119
|
+
pts = [s, { x: s.x, y: e.y }, e];
|
|
120
|
+
} else {
|
|
121
|
+
pts = [s, { x: e.x, y: s.y }, e];
|
|
122
|
+
}
|
|
123
|
+
return `M ${r(pts[0].x)} ${r(pts[0].y)}` + pts.slice(1).map((p) => ` L ${r(p.x)} ${r(p.y)}`).join("");
|
|
124
|
+
}
|
|
101
125
|
function routeOffset(start, end, obstacles, padding = 14) {
|
|
102
126
|
const dx = end.x - start.x;
|
|
103
127
|
const dy = end.y - start.y;
|
|
@@ -173,12 +197,29 @@ function easeInOutCubic(t) {
|
|
|
173
197
|
function clamp01(t) {
|
|
174
198
|
return t < 0 ? 0 : t > 1 ? 1 : t;
|
|
175
199
|
}
|
|
200
|
+
function prefersReducedMotion() {
|
|
201
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
205
|
+
}
|
|
176
206
|
function scrollProgress(targetRect, range) {
|
|
177
207
|
const vh = window.innerHeight || 1;
|
|
178
208
|
const topFrac = (targetRect.top - window.scrollY) / vh;
|
|
179
209
|
const [enter, leave] = range;
|
|
180
210
|
return clamp01((enter - topFrac) / (enter - leave || 1));
|
|
181
211
|
}
|
|
212
|
+
function staggerWindows(n, stagger) {
|
|
213
|
+
if (n <= 0) return [];
|
|
214
|
+
const s = clamp01(stagger);
|
|
215
|
+
const span = 1 / (1 + (n - 1) * s);
|
|
216
|
+
const step = span * s;
|
|
217
|
+
return Array.from({ length: n }, (_, i) => ({ start: i * step, span }));
|
|
218
|
+
}
|
|
219
|
+
function windowProgress(p, w) {
|
|
220
|
+
if (w.span <= 0) return p > w.start ? 1 : 0;
|
|
221
|
+
return clamp01((p - w.start) / w.span);
|
|
222
|
+
}
|
|
182
223
|
function midpointRect(a, b) {
|
|
183
224
|
const ra = docRect(a);
|
|
184
225
|
const rb = docRect(b);
|
|
@@ -336,14 +377,36 @@ var ScrollArrow = class {
|
|
|
336
377
|
this.svg = getOverlay(this.container);
|
|
337
378
|
this.rc = rough__default.default.svg(this.svg);
|
|
338
379
|
this.svg.appendChild(this.group);
|
|
339
|
-
this.
|
|
380
|
+
this.reducedMotion = this.opts.respectReducedMotion !== false && prefersReducedMotion();
|
|
381
|
+
this.progress = this.reducedMotion ? 1 : clamp01(this.opts.progress);
|
|
340
382
|
this.refs = this.resolveRefs();
|
|
341
383
|
this.stroke = options.stroke ?? getComputedStyle(this.container).color ?? "#222";
|
|
342
384
|
this.seed = options.seed ?? deriveSeed(refKey(options.start), refKey(options.end));
|
|
385
|
+
this.enabled = this.opts.enabled ?? true;
|
|
386
|
+
if (!this.enabled) this.group.style.display = "none";
|
|
343
387
|
this.render();
|
|
344
388
|
this.bind();
|
|
345
389
|
this.update();
|
|
346
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Suspend or restore the arrow without tearing it down. Disabling hides it and
|
|
393
|
+
* stops all draw/scroll work; enabling shows it and recomputes geometry (so it
|
|
394
|
+
* reflects any layout change that happened while hidden). Idempotent. Wire it
|
|
395
|
+
* to `matchMedia` to switch arrows off below a breakpoint.
|
|
396
|
+
*/
|
|
397
|
+
setEnabled(on) {
|
|
398
|
+
if (on === this.enabled || this.destroyed) return;
|
|
399
|
+
this.enabled = on;
|
|
400
|
+
if (on) {
|
|
401
|
+
this.group.style.display = "";
|
|
402
|
+
this.render();
|
|
403
|
+
this.update();
|
|
404
|
+
} else {
|
|
405
|
+
this.group.style.display = "none";
|
|
406
|
+
cancelAnimationFrame(this.rafId);
|
|
407
|
+
this.rafId = 0;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
347
410
|
/** Manually set draw progress (0..1). Only meaningful when scroll is false. */
|
|
348
411
|
setProgress(p) {
|
|
349
412
|
this.progress = clamp01(p);
|
|
@@ -357,6 +420,7 @@ var ScrollArrow = class {
|
|
|
357
420
|
destroy() {
|
|
358
421
|
this.destroyed = true;
|
|
359
422
|
this.ro?.disconnect();
|
|
423
|
+
this.teardownReveal();
|
|
360
424
|
window.removeEventListener("scroll", this.onScroll, true);
|
|
361
425
|
window.removeEventListener("resize", this.onScroll);
|
|
362
426
|
cancelAnimationFrame(this.rafId);
|
|
@@ -382,17 +446,30 @@ var ScrollArrow = class {
|
|
|
382
446
|
const list = Array.isArray(a) ? a : [a];
|
|
383
447
|
return list.map(resolve).filter((el) => el !== null);
|
|
384
448
|
}
|
|
385
|
-
computeEndpoints() {
|
|
386
|
-
const sr = docRect(this.refs.start);
|
|
387
|
-
const er = docRect(this.refs.end);
|
|
449
|
+
computeEndpoints(sr, er) {
|
|
388
450
|
const ss = this.opts.startSocket ?? "auto";
|
|
389
451
|
const es = this.opts.endSocket ?? "auto";
|
|
390
|
-
return resolveEndpoints(
|
|
452
|
+
return resolveEndpoints(
|
|
453
|
+
sr,
|
|
454
|
+
er,
|
|
455
|
+
ss,
|
|
456
|
+
es,
|
|
457
|
+
this.opts.startSocketOffset ?? 0,
|
|
458
|
+
this.opts.endSocketOffset ?? 0
|
|
459
|
+
);
|
|
391
460
|
}
|
|
392
461
|
render() {
|
|
393
462
|
while (this.group.firstChild) this.group.removeChild(this.group.firstChild);
|
|
394
463
|
this.segments = [];
|
|
395
|
-
|
|
464
|
+
if (!this.enabled) return;
|
|
465
|
+
const sr = docRect(this.refs.start);
|
|
466
|
+
const er = docRect(this.refs.end);
|
|
467
|
+
if (isDegenerateRect(sr) || isDegenerateRect(er)) {
|
|
468
|
+
this.armReveal();
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
this.teardownReveal();
|
|
472
|
+
const ep = this.computeEndpoints(sr, er);
|
|
396
473
|
const origin = overlayOrigin(this.svg);
|
|
397
474
|
const shift = (e) => ({
|
|
398
475
|
start: { x: e.start.x - origin.x, y: e.start.y - origin.y },
|
|
@@ -409,24 +486,29 @@ var ScrollArrow = class {
|
|
|
409
486
|
this.seed,
|
|
410
487
|
this.opts.anchorEnds ?? true
|
|
411
488
|
);
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
489
|
+
let d;
|
|
490
|
+
if (this.opts.route === "elbow") {
|
|
491
|
+
d = buildElbowPath(local);
|
|
492
|
+
} else {
|
|
493
|
+
const obstacles = this.resolveAvoid().map((el) => {
|
|
494
|
+
const dr = docRect(el);
|
|
495
|
+
return {
|
|
496
|
+
left: dr.left - origin.x,
|
|
497
|
+
top: dr.top - origin.y,
|
|
498
|
+
width: dr.width,
|
|
499
|
+
height: dr.height
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
const clear = routeOffset(
|
|
503
|
+
local.start,
|
|
504
|
+
local.end,
|
|
505
|
+
obstacles,
|
|
506
|
+
this.opts.avoidPadding ?? 14
|
|
507
|
+
);
|
|
508
|
+
const BOW = 1.6;
|
|
509
|
+
const belly = { x: clear.x * BOW, y: clear.y * BOW };
|
|
510
|
+
d = buildPath(local, curvature, belly);
|
|
511
|
+
}
|
|
430
512
|
this.appendDrawable(this.rc.path(d, roughOpts), "line");
|
|
431
513
|
const head = this.opts.head;
|
|
432
514
|
const size = this.opts.headSize;
|
|
@@ -537,19 +619,37 @@ var ScrollArrow = class {
|
|
|
537
619
|
if (this.labelBgEl) this.labelBgEl.style.opacity = String(op);
|
|
538
620
|
}
|
|
539
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* Watch the anchors for the moment a hidden one becomes laid out, then redraw.
|
|
624
|
+
* IntersectionObserver fires when a previously `display:none` element gains a
|
|
625
|
+
* box — a transition ResizeObserver does not reliably report. Armed lazily and
|
|
626
|
+
* idempotently; torn down by the next successful render(). Guarded so it no-ops
|
|
627
|
+
* in environments without IntersectionObserver (older engines, some SSR/jsdom).
|
|
628
|
+
*/
|
|
629
|
+
armReveal() {
|
|
630
|
+
if (this.revealObs || this.destroyed) return;
|
|
631
|
+
if (typeof IntersectionObserver === "undefined") return;
|
|
632
|
+
this.revealObs = new IntersectionObserver(() => this.render());
|
|
633
|
+
this.revealObs.observe(this.refs.start);
|
|
634
|
+
this.revealObs.observe(this.refs.end);
|
|
635
|
+
}
|
|
636
|
+
teardownReveal() {
|
|
637
|
+
this.revealObs?.disconnect();
|
|
638
|
+
this.revealObs = void 0;
|
|
639
|
+
}
|
|
540
640
|
bind() {
|
|
541
641
|
const targets = [this.refs.start, this.refs.end, ...this.resolveAvoid()];
|
|
542
642
|
if (this.refs.target) targets.push(this.refs.target);
|
|
543
643
|
this.ro = new ResizeObserver(() => this.render());
|
|
544
644
|
targets.forEach((t) => this.ro.observe(t));
|
|
545
|
-
if (this.opts.scroll !== false) {
|
|
645
|
+
if (this.opts.scroll !== false && !this.reducedMotion) {
|
|
546
646
|
window.addEventListener("scroll", this.onScroll, true);
|
|
547
647
|
window.addEventListener("resize", this.onScroll);
|
|
548
648
|
}
|
|
549
649
|
}
|
|
550
650
|
update() {
|
|
551
|
-
if (this.destroyed) return;
|
|
552
|
-
if (this.opts.scroll === false) {
|
|
651
|
+
if (this.destroyed || !this.enabled) return;
|
|
652
|
+
if (this.opts.scroll === false || this.reducedMotion) {
|
|
553
653
|
this.applyProgress();
|
|
554
654
|
return;
|
|
555
655
|
}
|
|
@@ -571,13 +671,152 @@ function clampAt(t) {
|
|
|
571
671
|
return t < 0 ? 0 : t > 1 ? 1 : t;
|
|
572
672
|
}
|
|
573
673
|
|
|
674
|
+
// src/group.ts
|
|
675
|
+
var ScrollArrowGroup = class {
|
|
676
|
+
constructor(options) {
|
|
677
|
+
this.elements = [];
|
|
678
|
+
this.target = null;
|
|
679
|
+
this.progress = 0;
|
|
680
|
+
this.rafId = 0;
|
|
681
|
+
this.destroyed = false;
|
|
682
|
+
this.onScroll = () => {
|
|
683
|
+
if (this.rafId) return;
|
|
684
|
+
this.rafId = requestAnimationFrame(() => {
|
|
685
|
+
this.rafId = 0;
|
|
686
|
+
this.update();
|
|
687
|
+
});
|
|
688
|
+
};
|
|
689
|
+
if (!options.arrows || options.arrows.length === 0) {
|
|
690
|
+
throw new Error("[scroll-arrows] group needs at least one arrow");
|
|
691
|
+
}
|
|
692
|
+
this.opts = {
|
|
693
|
+
stagger: 1,
|
|
694
|
+
speed: 1,
|
|
695
|
+
easing: (t) => t,
|
|
696
|
+
...options
|
|
697
|
+
};
|
|
698
|
+
this.reducedMotion = this.opts.respectReducedMotion !== false && prefersReducedMotion();
|
|
699
|
+
this.enabled = this.opts.enabled ?? true;
|
|
700
|
+
this.arrows = options.arrows.map(
|
|
701
|
+
(a) => new ScrollArrow({
|
|
702
|
+
...a,
|
|
703
|
+
scroll: false,
|
|
704
|
+
progress: 0,
|
|
705
|
+
respectReducedMotion: false,
|
|
706
|
+
enabled: this.enabled
|
|
707
|
+
})
|
|
708
|
+
);
|
|
709
|
+
this.windows = staggerWindows(this.arrows.length, this.opts.stagger);
|
|
710
|
+
for (const a of options.arrows) {
|
|
711
|
+
const s = resolve2(a.start);
|
|
712
|
+
const e = resolve2(a.end);
|
|
713
|
+
if (s) this.elements.push(s);
|
|
714
|
+
if (e) this.elements.push(e);
|
|
715
|
+
}
|
|
716
|
+
const scroll = this.opts.scroll;
|
|
717
|
+
if (scroll !== false && scroll?.target) {
|
|
718
|
+
this.target = resolve2(scroll.target);
|
|
719
|
+
}
|
|
720
|
+
if (this.reducedMotion) this.progress = 1;
|
|
721
|
+
this.bind();
|
|
722
|
+
this.update();
|
|
723
|
+
}
|
|
724
|
+
/** Manually set group progress (0..1). Only meaningful when scroll is false. */
|
|
725
|
+
setProgress(p) {
|
|
726
|
+
this.progress = clamp01(p);
|
|
727
|
+
this.distribute();
|
|
728
|
+
}
|
|
729
|
+
/** Recompute geometry for every arrow (call after layout changes). */
|
|
730
|
+
refresh() {
|
|
731
|
+
this.arrows.forEach((a) => a.refresh());
|
|
732
|
+
this.update();
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Suspend or restore the whole group without tearing it down. Hides every
|
|
736
|
+
* arrow and stops scroll work when off; restores and recomputes when on.
|
|
737
|
+
* Idempotent. Wire to `matchMedia` for breakpoint-aware diagrams.
|
|
738
|
+
*/
|
|
739
|
+
setEnabled(on) {
|
|
740
|
+
if (on === this.enabled || this.destroyed) return;
|
|
741
|
+
this.enabled = on;
|
|
742
|
+
this.arrows.forEach((a) => a.setEnabled(on));
|
|
743
|
+
if (on) {
|
|
744
|
+
this.bind();
|
|
745
|
+
this.update();
|
|
746
|
+
} else {
|
|
747
|
+
window.removeEventListener("scroll", this.onScroll, true);
|
|
748
|
+
window.removeEventListener("resize", this.onScroll);
|
|
749
|
+
cancelAnimationFrame(this.rafId);
|
|
750
|
+
this.rafId = 0;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
destroy() {
|
|
754
|
+
this.destroyed = true;
|
|
755
|
+
window.removeEventListener("scroll", this.onScroll, true);
|
|
756
|
+
window.removeEventListener("resize", this.onScroll);
|
|
757
|
+
cancelAnimationFrame(this.rafId);
|
|
758
|
+
this.arrows.forEach((a) => a.destroy());
|
|
759
|
+
}
|
|
760
|
+
// --- internals ---------------------------------------------------------
|
|
761
|
+
bind() {
|
|
762
|
+
if (this.opts.scroll === false || this.reducedMotion || !this.enabled)
|
|
763
|
+
return;
|
|
764
|
+
window.addEventListener("scroll", this.onScroll, true);
|
|
765
|
+
window.addEventListener("resize", this.onScroll);
|
|
766
|
+
}
|
|
767
|
+
update() {
|
|
768
|
+
if (this.destroyed || !this.enabled) return;
|
|
769
|
+
if (this.opts.scroll === false || this.reducedMotion) {
|
|
770
|
+
this.distribute();
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
const scroll = this.opts.scroll ?? {};
|
|
774
|
+
const range = scroll.range ?? [0.85, 0.35];
|
|
775
|
+
const rect = this.target ? docRect(this.target) : this.groupRect();
|
|
776
|
+
const raw = scrollProgress(rect, range);
|
|
777
|
+
this.progress = clamp01(raw * this.opts.speed);
|
|
778
|
+
this.distribute();
|
|
779
|
+
}
|
|
780
|
+
/** Push each arrow to its sliced local progress for the current group value. */
|
|
781
|
+
distribute() {
|
|
782
|
+
const eased = clamp01(this.opts.easing(this.progress));
|
|
783
|
+
this.arrows.forEach((arrow, i) => {
|
|
784
|
+
arrow.setProgress(windowProgress(eased, this.windows[i]));
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
/** Synthetic rect spanning every endpoint, used as the default trigger. */
|
|
788
|
+
groupRect() {
|
|
789
|
+
const rects = this.elements.map(docRect);
|
|
790
|
+
if (rects.length === 0) return { left: 0, top: 0, width: 0, height: 0 };
|
|
791
|
+
let left = Infinity;
|
|
792
|
+
let top = Infinity;
|
|
793
|
+
let right = -Infinity;
|
|
794
|
+
let bottom = -Infinity;
|
|
795
|
+
for (const r2 of rects) {
|
|
796
|
+
left = Math.min(left, r2.left);
|
|
797
|
+
top = Math.min(top, r2.top);
|
|
798
|
+
right = Math.max(right, r2.left + r2.width);
|
|
799
|
+
bottom = Math.max(bottom, r2.top + r2.height);
|
|
800
|
+
}
|
|
801
|
+
return { left, top, width: right - left, height: bottom - top };
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
function resolve2(ref) {
|
|
805
|
+
return typeof ref === "string" ? document.querySelector(ref) : ref;
|
|
806
|
+
}
|
|
807
|
+
|
|
574
808
|
// src/index.ts
|
|
575
809
|
function scrollArrow(options) {
|
|
576
810
|
return new ScrollArrow(options);
|
|
577
811
|
}
|
|
812
|
+
function scrollArrowGroup(options) {
|
|
813
|
+
return new ScrollArrowGroup(options);
|
|
814
|
+
}
|
|
578
815
|
|
|
579
816
|
exports.ScrollArrow = ScrollArrow;
|
|
817
|
+
exports.ScrollArrowGroup = ScrollArrowGroup;
|
|
580
818
|
exports.easeInOutCubic = easeInOutCubic;
|
|
581
819
|
exports.scrollArrow = scrollArrow;
|
|
820
|
+
exports.scrollArrowGroup = scrollArrowGroup;
|
|
582
821
|
//# sourceMappingURL=index.cjs.map
|
|
583
822
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as ScrollArrowOptions } from './types-
|
|
2
|
-
export { A as ArrowHead, E as ElementRef, P as Point,
|
|
1
|
+
import { S as ScrollArrowOptions, a as ScrollArrowGroupOptions } from './types-Cpvz9wtr.cjs';
|
|
2
|
+
export { A as ArrowHead, E as ElementRef, P as Point, b as ScrollOptions, c as Socket } from './types-Cpvz9wtr.cjs';
|
|
3
3
|
|
|
4
4
|
/** A single hand-drawn arrow that draws itself between two elements on scroll. */
|
|
5
5
|
declare class ScrollArrow {
|
|
@@ -22,9 +22,25 @@ declare class ScrollArrow {
|
|
|
22
22
|
private labelBgEl;
|
|
23
23
|
private progress;
|
|
24
24
|
private ro?;
|
|
25
|
+
/**
|
|
26
|
+
* Lazily armed only while an anchor is hidden/zero-size, so the common path
|
|
27
|
+
* (both anchors visible) wires no extra observer. Fires render() on reveal.
|
|
28
|
+
*/
|
|
29
|
+
private revealObs?;
|
|
25
30
|
private rafId;
|
|
26
31
|
private destroyed;
|
|
32
|
+
/** Render static + fully drawn: user prefers reduced motion and we honor it. */
|
|
33
|
+
private reducedMotion;
|
|
34
|
+
/** When false the arrow is hidden and skips all draw/scroll work (no teardown). */
|
|
35
|
+
private enabled;
|
|
27
36
|
constructor(options: ScrollArrowOptions);
|
|
37
|
+
/**
|
|
38
|
+
* Suspend or restore the arrow without tearing it down. Disabling hides it and
|
|
39
|
+
* stops all draw/scroll work; enabling shows it and recomputes geometry (so it
|
|
40
|
+
* reflects any layout change that happened while hidden). Idempotent. Wire it
|
|
41
|
+
* to `matchMedia` to switch arrows off below a breakpoint.
|
|
42
|
+
*/
|
|
43
|
+
setEnabled(on: boolean): void;
|
|
28
44
|
/** Manually set draw progress (0..1). Only meaningful when scroll is false. */
|
|
29
45
|
setProgress(p: number): void;
|
|
30
46
|
/** Recompute geometry (call after layout changes you control). */
|
|
@@ -44,14 +60,64 @@ declare class ScrollArrow {
|
|
|
44
60
|
* once the line is complete.
|
|
45
61
|
*/
|
|
46
62
|
private applyProgress;
|
|
63
|
+
/**
|
|
64
|
+
* Watch the anchors for the moment a hidden one becomes laid out, then redraw.
|
|
65
|
+
* IntersectionObserver fires when a previously `display:none` element gains a
|
|
66
|
+
* box — a transition ResizeObserver does not reliably report. Armed lazily and
|
|
67
|
+
* idempotently; torn down by the next successful render(). Guarded so it no-ops
|
|
68
|
+
* in environments without IntersectionObserver (older engines, some SSR/jsdom).
|
|
69
|
+
*/
|
|
70
|
+
private armReveal;
|
|
71
|
+
private teardownReveal;
|
|
72
|
+
private bind;
|
|
73
|
+
private onScroll;
|
|
74
|
+
private update;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A coordinated set of arrows that draw in a staggered sequence off one shared
|
|
79
|
+
* scroll trigger (or manual `setProgress`). Owns its arrows; `destroy()` tears
|
|
80
|
+
* them all down.
|
|
81
|
+
*/
|
|
82
|
+
declare class ScrollArrowGroup {
|
|
83
|
+
private opts;
|
|
84
|
+
private arrows;
|
|
85
|
+
private windows;
|
|
86
|
+
private elements;
|
|
87
|
+
private target;
|
|
88
|
+
private progress;
|
|
89
|
+
private rafId;
|
|
90
|
+
private destroyed;
|
|
91
|
+
/** Render every arrow static + fully drawn when reduced motion is honored. */
|
|
92
|
+
private reducedMotion;
|
|
93
|
+
/** When false every arrow is hidden and the group does no scroll work. */
|
|
94
|
+
private enabled;
|
|
95
|
+
constructor(options: ScrollArrowGroupOptions);
|
|
96
|
+
/** Manually set group progress (0..1). Only meaningful when scroll is false. */
|
|
97
|
+
setProgress(p: number): void;
|
|
98
|
+
/** Recompute geometry for every arrow (call after layout changes). */
|
|
99
|
+
refresh(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Suspend or restore the whole group without tearing it down. Hides every
|
|
102
|
+
* arrow and stops scroll work when off; restores and recomputes when on.
|
|
103
|
+
* Idempotent. Wire to `matchMedia` for breakpoint-aware diagrams.
|
|
104
|
+
*/
|
|
105
|
+
setEnabled(on: boolean): void;
|
|
106
|
+
destroy(): void;
|
|
47
107
|
private bind;
|
|
48
108
|
private onScroll;
|
|
49
109
|
private update;
|
|
110
|
+
/** Push each arrow to its sliced local progress for the current group value. */
|
|
111
|
+
private distribute;
|
|
112
|
+
/** Synthetic rect spanning every endpoint, used as the default trigger. */
|
|
113
|
+
private groupRect;
|
|
50
114
|
}
|
|
51
115
|
|
|
52
116
|
declare function easeInOutCubic(t: number): number;
|
|
53
117
|
|
|
54
118
|
/** Convenience factory. `const a = scrollArrow({ start, end })`. */
|
|
55
119
|
declare function scrollArrow(options: ScrollArrowOptions): ScrollArrow;
|
|
120
|
+
/** Convenience factory. `const g = scrollArrowGroup({ arrows: [...] })`. */
|
|
121
|
+
declare function scrollArrowGroup(options: ScrollArrowGroupOptions): ScrollArrowGroup;
|
|
56
122
|
|
|
57
|
-
export { ScrollArrow, ScrollArrowOptions, easeInOutCubic, scrollArrow };
|
|
123
|
+
export { ScrollArrow, ScrollArrowGroup, ScrollArrowGroupOptions, ScrollArrowOptions, easeInOutCubic, scrollArrow, scrollArrowGroup };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as ScrollArrowOptions } from './types-
|
|
2
|
-
export { A as ArrowHead, E as ElementRef, P as Point,
|
|
1
|
+
import { S as ScrollArrowOptions, a as ScrollArrowGroupOptions } from './types-Cpvz9wtr.js';
|
|
2
|
+
export { A as ArrowHead, E as ElementRef, P as Point, b as ScrollOptions, c as Socket } from './types-Cpvz9wtr.js';
|
|
3
3
|
|
|
4
4
|
/** A single hand-drawn arrow that draws itself between two elements on scroll. */
|
|
5
5
|
declare class ScrollArrow {
|
|
@@ -22,9 +22,25 @@ declare class ScrollArrow {
|
|
|
22
22
|
private labelBgEl;
|
|
23
23
|
private progress;
|
|
24
24
|
private ro?;
|
|
25
|
+
/**
|
|
26
|
+
* Lazily armed only while an anchor is hidden/zero-size, so the common path
|
|
27
|
+
* (both anchors visible) wires no extra observer. Fires render() on reveal.
|
|
28
|
+
*/
|
|
29
|
+
private revealObs?;
|
|
25
30
|
private rafId;
|
|
26
31
|
private destroyed;
|
|
32
|
+
/** Render static + fully drawn: user prefers reduced motion and we honor it. */
|
|
33
|
+
private reducedMotion;
|
|
34
|
+
/** When false the arrow is hidden and skips all draw/scroll work (no teardown). */
|
|
35
|
+
private enabled;
|
|
27
36
|
constructor(options: ScrollArrowOptions);
|
|
37
|
+
/**
|
|
38
|
+
* Suspend or restore the arrow without tearing it down. Disabling hides it and
|
|
39
|
+
* stops all draw/scroll work; enabling shows it and recomputes geometry (so it
|
|
40
|
+
* reflects any layout change that happened while hidden). Idempotent. Wire it
|
|
41
|
+
* to `matchMedia` to switch arrows off below a breakpoint.
|
|
42
|
+
*/
|
|
43
|
+
setEnabled(on: boolean): void;
|
|
28
44
|
/** Manually set draw progress (0..1). Only meaningful when scroll is false. */
|
|
29
45
|
setProgress(p: number): void;
|
|
30
46
|
/** Recompute geometry (call after layout changes you control). */
|
|
@@ -44,14 +60,64 @@ declare class ScrollArrow {
|
|
|
44
60
|
* once the line is complete.
|
|
45
61
|
*/
|
|
46
62
|
private applyProgress;
|
|
63
|
+
/**
|
|
64
|
+
* Watch the anchors for the moment a hidden one becomes laid out, then redraw.
|
|
65
|
+
* IntersectionObserver fires when a previously `display:none` element gains a
|
|
66
|
+
* box — a transition ResizeObserver does not reliably report. Armed lazily and
|
|
67
|
+
* idempotently; torn down by the next successful render(). Guarded so it no-ops
|
|
68
|
+
* in environments without IntersectionObserver (older engines, some SSR/jsdom).
|
|
69
|
+
*/
|
|
70
|
+
private armReveal;
|
|
71
|
+
private teardownReveal;
|
|
72
|
+
private bind;
|
|
73
|
+
private onScroll;
|
|
74
|
+
private update;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A coordinated set of arrows that draw in a staggered sequence off one shared
|
|
79
|
+
* scroll trigger (or manual `setProgress`). Owns its arrows; `destroy()` tears
|
|
80
|
+
* them all down.
|
|
81
|
+
*/
|
|
82
|
+
declare class ScrollArrowGroup {
|
|
83
|
+
private opts;
|
|
84
|
+
private arrows;
|
|
85
|
+
private windows;
|
|
86
|
+
private elements;
|
|
87
|
+
private target;
|
|
88
|
+
private progress;
|
|
89
|
+
private rafId;
|
|
90
|
+
private destroyed;
|
|
91
|
+
/** Render every arrow static + fully drawn when reduced motion is honored. */
|
|
92
|
+
private reducedMotion;
|
|
93
|
+
/** When false every arrow is hidden and the group does no scroll work. */
|
|
94
|
+
private enabled;
|
|
95
|
+
constructor(options: ScrollArrowGroupOptions);
|
|
96
|
+
/** Manually set group progress (0..1). Only meaningful when scroll is false. */
|
|
97
|
+
setProgress(p: number): void;
|
|
98
|
+
/** Recompute geometry for every arrow (call after layout changes). */
|
|
99
|
+
refresh(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Suspend or restore the whole group without tearing it down. Hides every
|
|
102
|
+
* arrow and stops scroll work when off; restores and recomputes when on.
|
|
103
|
+
* Idempotent. Wire to `matchMedia` for breakpoint-aware diagrams.
|
|
104
|
+
*/
|
|
105
|
+
setEnabled(on: boolean): void;
|
|
106
|
+
destroy(): void;
|
|
47
107
|
private bind;
|
|
48
108
|
private onScroll;
|
|
49
109
|
private update;
|
|
110
|
+
/** Push each arrow to its sliced local progress for the current group value. */
|
|
111
|
+
private distribute;
|
|
112
|
+
/** Synthetic rect spanning every endpoint, used as the default trigger. */
|
|
113
|
+
private groupRect;
|
|
50
114
|
}
|
|
51
115
|
|
|
52
116
|
declare function easeInOutCubic(t: number): number;
|
|
53
117
|
|
|
54
118
|
/** Convenience factory. `const a = scrollArrow({ start, end })`. */
|
|
55
119
|
declare function scrollArrow(options: ScrollArrowOptions): ScrollArrow;
|
|
120
|
+
/** Convenience factory. `const g = scrollArrowGroup({ arrows: [...] })`. */
|
|
121
|
+
declare function scrollArrowGroup(options: ScrollArrowGroupOptions): ScrollArrowGroup;
|
|
56
122
|
|
|
57
|
-
export { ScrollArrow, ScrollArrowOptions, easeInOutCubic, scrollArrow };
|
|
123
|
+
export { ScrollArrow, ScrollArrowGroup, ScrollArrowGroupOptions, ScrollArrowOptions, easeInOutCubic, scrollArrow, scrollArrowGroup };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { ScrollArrow } from './chunk-
|
|
2
|
-
export { ScrollArrow, easeInOutCubic } from './chunk-
|
|
1
|
+
import { ScrollArrow, ScrollArrowGroup } from './chunk-LIT577GH.js';
|
|
2
|
+
export { ScrollArrow, ScrollArrowGroup, easeInOutCubic } from './chunk-LIT577GH.js';
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
function scrollArrow(options) {
|
|
6
6
|
return new ScrollArrow(options);
|
|
7
7
|
}
|
|
8
|
+
function scrollArrowGroup(options) {
|
|
9
|
+
return new ScrollArrowGroup(options);
|
|
10
|
+
}
|
|
8
11
|
|
|
9
|
-
export { scrollArrow };
|
|
12
|
+
export { scrollArrow, scrollArrowGroup };
|
|
10
13
|
//# sourceMappingURL=index.js.map
|
|
11
14
|
//# sourceMappingURL=index.js.map
|