@pixodesk/svg-animator-web 1.0.27 → 1.0.28
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/dist/index.cjs +135 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +135 -8
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.prerendered-waapi.umd.js.map +1 -1
- package/dist/index.prerendered.umd.js +129 -8
- package/dist/index.prerendered.umd.js.map +1 -1
- package/dist/index.prerendered.umd.min.js +1 -1
- package/dist/index.umd.js +135 -8
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1207,6 +1207,12 @@ var PxScrollSchema = implementsInterface()(px.object({
|
|
|
1207
1207
|
kind: px.enum(["view", "scroll"]).optional(),
|
|
1208
1208
|
axis: px.enum(["block", "inline", "x", "y"]).optional(),
|
|
1209
1209
|
source: px.enum(["nearest", "root"]).optional(),
|
|
1210
|
+
// Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
|
|
1211
|
+
subject: px.string().optional(),
|
|
1212
|
+
smoothing: px.number().optional(),
|
|
1213
|
+
pin: px.boolean().optional(),
|
|
1214
|
+
pinTop: px.number().optional(),
|
|
1215
|
+
pinDistance: px.number().optional(),
|
|
1210
1216
|
range: PxScrollRangeSchema.optional()
|
|
1211
1217
|
}));
|
|
1212
1218
|
var PxAnimatorConfigSchema = implementsInterface()(px.object({
|
|
@@ -6431,6 +6437,10 @@ function createNativeScrollTimeline(subject, config) {
|
|
|
6431
6437
|
if (!config || !isScrollTimeline(config)) return null;
|
|
6432
6438
|
const scroll = config.scroll || {};
|
|
6433
6439
|
const kind = (_a = scroll.kind) != null ? _a : "view";
|
|
6440
|
+
if (scroll.smoothing) {
|
|
6441
|
+
console.warn('scroll timeline: `smoothing` needs the built-in driver \u2014 ignoring `driver: "native"`');
|
|
6442
|
+
return null;
|
|
6443
|
+
}
|
|
6434
6444
|
const g = globalThis;
|
|
6435
6445
|
const view = kind === "view";
|
|
6436
6446
|
const Ctor = view ? g.ViewTimeline : g.ScrollTimeline;
|
|
@@ -6439,7 +6449,7 @@ function createNativeScrollTimeline(subject, config) {
|
|
|
6439
6449
|
let timeline;
|
|
6440
6450
|
try {
|
|
6441
6451
|
if (view) {
|
|
6442
|
-
timeline = new Ctor({ subject, axis });
|
|
6452
|
+
timeline = new Ctor({ subject: resolveScrollSubject(subject, scroll.subject), axis });
|
|
6443
6453
|
} else {
|
|
6444
6454
|
const source = scroll.source === "root" ? documentScroller() : findNearestScroller(subject, "y") || findNearestScroller(subject, "x") || documentScroller();
|
|
6445
6455
|
timeline = new Ctor({ source, axis });
|
|
@@ -6455,7 +6465,10 @@ function createNativeScrollTimeline(subject, config) {
|
|
|
6455
6465
|
};
|
|
6456
6466
|
}
|
|
6457
6467
|
function findNearestScroller(el, axis) {
|
|
6468
|
+
const body = document.body;
|
|
6469
|
+
const root = document.documentElement;
|
|
6458
6470
|
for (let p = el.parentElement; p; p = p.parentElement) {
|
|
6471
|
+
if (p === body || p === root) return null;
|
|
6459
6472
|
const style = getComputedStyle(p);
|
|
6460
6473
|
const overflow = axis === "y" ? style.overflowY : style.overflowX;
|
|
6461
6474
|
if (overflow === "auto" || overflow === "scroll" || overflow === "hidden" || overflow === "overlay") {
|
|
@@ -6467,11 +6480,42 @@ function findNearestScroller(el, axis) {
|
|
|
6467
6480
|
function documentScroller() {
|
|
6468
6481
|
return document.scrollingElement || document.documentElement;
|
|
6469
6482
|
}
|
|
6483
|
+
var SUBJECT_PARENT = "parent";
|
|
6484
|
+
var SUBJECT_SCROLLER = "scroller";
|
|
6485
|
+
function resolveScrollSubject(svgRoot, subject) {
|
|
6486
|
+
var _a, _b;
|
|
6487
|
+
const spec = subject == null ? void 0 : subject.trim();
|
|
6488
|
+
if (!spec) return svgRoot;
|
|
6489
|
+
if (spec === SUBJECT_PARENT) {
|
|
6490
|
+
let outermostPinned = null;
|
|
6491
|
+
for (let p = svgRoot.parentElement; p && p !== document.body; p = p.parentElement) {
|
|
6492
|
+
const position = getComputedStyle(p).position;
|
|
6493
|
+
if (position === "sticky" || position === "fixed") outermostPinned = p;
|
|
6494
|
+
}
|
|
6495
|
+
return (_b = (_a = outermostPinned == null ? void 0 : outermostPinned.parentElement) != null ? _a : svgRoot.parentElement) != null ? _b : svgRoot;
|
|
6496
|
+
}
|
|
6497
|
+
if (spec === SUBJECT_SCROLLER) {
|
|
6498
|
+
return findNearestScroller(svgRoot, "y") || findNearestScroller(svgRoot, "x") || documentScroller();
|
|
6499
|
+
}
|
|
6500
|
+
let found = null;
|
|
6501
|
+
try {
|
|
6502
|
+
found = document.querySelector(spec);
|
|
6503
|
+
} catch (e) {
|
|
6504
|
+
console.warn('scroll timeline: subject "' + spec + '" is not a valid selector \u2014 measuring the SVG itself');
|
|
6505
|
+
return svgRoot;
|
|
6506
|
+
}
|
|
6507
|
+
if (!found) {
|
|
6508
|
+
console.warn('scroll timeline: subject "' + spec + '" matched no element \u2014 measuring the SVG itself');
|
|
6509
|
+
return svgRoot;
|
|
6510
|
+
}
|
|
6511
|
+
return found;
|
|
6512
|
+
}
|
|
6470
6513
|
function createScrollDriver(subject, config, onProgress) {
|
|
6471
|
-
var _a;
|
|
6514
|
+
var _a, _b;
|
|
6472
6515
|
if (!config || !isScrollTimeline(config)) return null;
|
|
6473
6516
|
const scroll = config.scroll || {};
|
|
6474
6517
|
const kind = (_a = scroll.kind) != null ? _a : "view";
|
|
6518
|
+
const measured = resolveScrollSubject(subject, scroll.subject);
|
|
6475
6519
|
const nearest = findNearestScroller(subject, "y") || findNearestScroller(subject, "x");
|
|
6476
6520
|
const scroller = kind === "scroll" && scroll.source === "root" ? documentScroller() : nearest || documentScroller();
|
|
6477
6521
|
const isRootScroller = scroller === documentScroller();
|
|
@@ -6482,7 +6526,7 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6482
6526
|
const maxOffset = axis === "y" ? scroller.scrollHeight - scroller.clientHeight : scroller.scrollWidth - scroller.clientWidth;
|
|
6483
6527
|
return scrollOffsetProgress(offset, maxOffset, scroll.range);
|
|
6484
6528
|
}
|
|
6485
|
-
const subjectRect =
|
|
6529
|
+
const subjectRect = measured.getBoundingClientRect();
|
|
6486
6530
|
let portStart, portSize;
|
|
6487
6531
|
if (isRootScroller) {
|
|
6488
6532
|
portStart = 0;
|
|
@@ -6496,12 +6540,43 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6496
6540
|
const subjectSize = axis === "y" ? subjectRect.height : subjectRect.width;
|
|
6497
6541
|
return scrollViewProgress(subjectStart, subjectSize, portSize, scroll.range);
|
|
6498
6542
|
};
|
|
6499
|
-
|
|
6543
|
+
const smoothingSec = Math.max(0, (_b = scroll.smoothing) != null ? _b : 0) / 1e3;
|
|
6544
|
+
const SETTLE_EPSILON = 1e-3;
|
|
6500
6545
|
let destroyed = false;
|
|
6546
|
+
let smoothed = null;
|
|
6547
|
+
let smoothRaf = null;
|
|
6548
|
+
let lastFrameMs = 0;
|
|
6549
|
+
const emit = (target) => {
|
|
6550
|
+
if (!smoothingSec) {
|
|
6551
|
+
onProgress(target);
|
|
6552
|
+
return;
|
|
6553
|
+
}
|
|
6554
|
+
if (smoothed === null) {
|
|
6555
|
+
smoothed = target;
|
|
6556
|
+
onProgress(target);
|
|
6557
|
+
return;
|
|
6558
|
+
}
|
|
6559
|
+
if (smoothRaf !== null) return;
|
|
6560
|
+
lastFrameMs = 0;
|
|
6561
|
+
const step = (nowMs) => {
|
|
6562
|
+
smoothRaf = null;
|
|
6563
|
+
if (destroyed) return;
|
|
6564
|
+
const dtSec = lastFrameMs ? Math.min(0.1, (nowMs - lastFrameMs) / 1e3) : 1 / 60;
|
|
6565
|
+
lastFrameMs = nowMs;
|
|
6566
|
+
const goal = compute();
|
|
6567
|
+
const k = 1 - Math.exp(-dtSec / smoothingSec);
|
|
6568
|
+
smoothed = smoothed + (goal - smoothed) * k;
|
|
6569
|
+
if (Math.abs(goal - smoothed) < SETTLE_EPSILON) smoothed = goal;
|
|
6570
|
+
onProgress(smoothed);
|
|
6571
|
+
if (smoothed !== goal) smoothRaf = requestAnimationFrame(step);
|
|
6572
|
+
};
|
|
6573
|
+
smoothRaf = requestAnimationFrame(step);
|
|
6574
|
+
};
|
|
6575
|
+
let rafId = null;
|
|
6501
6576
|
const tick = () => {
|
|
6502
6577
|
rafId = null;
|
|
6503
6578
|
if (destroyed) return;
|
|
6504
|
-
|
|
6579
|
+
emit(compute());
|
|
6505
6580
|
};
|
|
6506
6581
|
const schedule = () => {
|
|
6507
6582
|
if (destroyed || rafId !== null) return;
|
|
@@ -6513,7 +6588,8 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6513
6588
|
let resizeObserver;
|
|
6514
6589
|
if (typeof ResizeObserver !== "undefined") {
|
|
6515
6590
|
resizeObserver = new ResizeObserver(schedule);
|
|
6516
|
-
resizeObserver.observe(
|
|
6591
|
+
resizeObserver.observe(measured);
|
|
6592
|
+
if (measured !== subject) resizeObserver.observe(subject);
|
|
6517
6593
|
if (!isRootScroller) resizeObserver.observe(scroller);
|
|
6518
6594
|
}
|
|
6519
6595
|
const driver = {
|
|
@@ -6527,14 +6603,50 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6527
6603
|
cancelAnimationFrame(rafId);
|
|
6528
6604
|
rafId = null;
|
|
6529
6605
|
}
|
|
6606
|
+
if (smoothRaf !== null) {
|
|
6607
|
+
cancelAnimationFrame(smoothRaf);
|
|
6608
|
+
smoothRaf = null;
|
|
6609
|
+
}
|
|
6530
6610
|
},
|
|
6611
|
+
// `refresh` is a deliberate JUMP (attach, host relayout) — never eased.
|
|
6531
6612
|
refresh: () => {
|
|
6532
|
-
if (!destroyed)
|
|
6613
|
+
if (!destroyed) {
|
|
6614
|
+
smoothed = compute();
|
|
6615
|
+
onProgress(smoothed);
|
|
6616
|
+
}
|
|
6533
6617
|
}
|
|
6534
6618
|
};
|
|
6535
6619
|
driver.refresh();
|
|
6536
6620
|
return driver;
|
|
6537
6621
|
}
|
|
6622
|
+
function applyScrollPin(svgRoot, scroll) {
|
|
6623
|
+
var _a;
|
|
6624
|
+
const styled = svgRoot;
|
|
6625
|
+
if (!(scroll == null ? void 0 : scroll.pin) || !styled.style) return () => {
|
|
6626
|
+
};
|
|
6627
|
+
const style = styled.style;
|
|
6628
|
+
const prevPosition = style.position;
|
|
6629
|
+
const prevTop = style.top;
|
|
6630
|
+
style.position = "sticky";
|
|
6631
|
+
style.top = ((_a = scroll.pinTop) != null ? _a : 0) + "px";
|
|
6632
|
+
let wrapper = null;
|
|
6633
|
+
const parent = svgRoot.parentElement;
|
|
6634
|
+
if (scroll.pinDistance && scroll.pinDistance > 0 && parent) {
|
|
6635
|
+
wrapper = document.createElement("div");
|
|
6636
|
+
wrapper.setAttribute("data-px-pin", "");
|
|
6637
|
+
wrapper.style.height = scroll.pinDistance * 100 + "vh";
|
|
6638
|
+
parent.insertBefore(wrapper, svgRoot);
|
|
6639
|
+
wrapper.appendChild(svgRoot);
|
|
6640
|
+
}
|
|
6641
|
+
return () => {
|
|
6642
|
+
style.position = prevPosition;
|
|
6643
|
+
style.top = prevTop;
|
|
6644
|
+
if (wrapper == null ? void 0 : wrapper.parentElement) {
|
|
6645
|
+
wrapper.parentElement.insertBefore(svgRoot, wrapper);
|
|
6646
|
+
wrapper.remove();
|
|
6647
|
+
}
|
|
6648
|
+
};
|
|
6649
|
+
}
|
|
6538
6650
|
|
|
6539
6651
|
// src/PxAnimatorBind.ts
|
|
6540
6652
|
function finaliseAnimator(animatorConfig, callbacks, make) {
|
|
@@ -6561,7 +6673,10 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
|
|
|
6561
6673
|
if (isScrollTimeline(animatorConfig)) {
|
|
6562
6674
|
return finaliseAnimator(animatorConfig, callbacks, (cb) => {
|
|
6563
6675
|
var _a, _b;
|
|
6676
|
+
let unpin = () => {
|
|
6677
|
+
};
|
|
6564
6678
|
if (animatorConfig.mode !== PxAnimatorMode.frames && ((_a = animatorConfig.scroll) == null ? void 0 : _a.driver) === "native" && rootElement) {
|
|
6679
|
+
unpin = applyScrollPin(rootElement, animatorConfig.scroll);
|
|
6565
6680
|
const native = createNativeScrollTimeline(rootElement, animatorConfig);
|
|
6566
6681
|
if (native) {
|
|
6567
6682
|
const api2 = createWebApiAnimator(
|
|
@@ -6571,12 +6686,23 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
|
|
|
6571
6686
|
animatorConfig.mode === PxAnimatorMode.waapi,
|
|
6572
6687
|
native
|
|
6573
6688
|
);
|
|
6574
|
-
if (api2)
|
|
6689
|
+
if (api2) {
|
|
6690
|
+
const destroyNative = api2.destroy.bind(api2);
|
|
6691
|
+
api2.destroy = () => {
|
|
6692
|
+
unpin();
|
|
6693
|
+
destroyNative();
|
|
6694
|
+
};
|
|
6695
|
+
return api2;
|
|
6696
|
+
}
|
|
6575
6697
|
}
|
|
6698
|
+
unpin();
|
|
6699
|
+
unpin = () => {
|
|
6700
|
+
};
|
|
6576
6701
|
}
|
|
6577
6702
|
const api = (animatorConfig.mode !== PxAnimatorMode.frames ? createWebApiAnimator(doc, cb, rootElement, animatorConfig.mode === PxAnimatorMode.waapi) : null) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
|
|
6578
6703
|
const subject = ((_b = api.getRootElement) == null ? void 0 : _b.call(api)) || rootElement;
|
|
6579
6704
|
if (subject) {
|
|
6705
|
+
unpin = applyScrollPin(subject, animatorConfig.scroll);
|
|
6580
6706
|
const totalMs = scrollTotalDurationMs(animatorConfig);
|
|
6581
6707
|
const driver = createScrollDriver(
|
|
6582
6708
|
subject,
|
|
@@ -6587,6 +6713,7 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
|
|
|
6587
6713
|
const destroy = api.destroy.bind(api);
|
|
6588
6714
|
api.destroy = () => {
|
|
6589
6715
|
driver.destroy();
|
|
6716
|
+
unpin();
|
|
6590
6717
|
destroy();
|
|
6591
6718
|
};
|
|
6592
6719
|
}
|