@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.cjs
CHANGED
|
@@ -1316,6 +1316,12 @@ var PxScrollSchema = implementsInterface()(px.object({
|
|
|
1316
1316
|
kind: px.enum(["view", "scroll"]).optional(),
|
|
1317
1317
|
axis: px.enum(["block", "inline", "x", "y"]).optional(),
|
|
1318
1318
|
source: px.enum(["nearest", "root"]).optional(),
|
|
1319
|
+
// Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
|
|
1320
|
+
subject: px.string().optional(),
|
|
1321
|
+
smoothing: px.number().optional(),
|
|
1322
|
+
pin: px.boolean().optional(),
|
|
1323
|
+
pinTop: px.number().optional(),
|
|
1324
|
+
pinDistance: px.number().optional(),
|
|
1319
1325
|
range: PxScrollRangeSchema.optional()
|
|
1320
1326
|
}));
|
|
1321
1327
|
var PxAnimatorConfigSchema = implementsInterface()(px.object({
|
|
@@ -6540,6 +6546,10 @@ function createNativeScrollTimeline(subject, config) {
|
|
|
6540
6546
|
if (!config || !isScrollTimeline(config)) return null;
|
|
6541
6547
|
const scroll = config.scroll || {};
|
|
6542
6548
|
const kind = (_a = scroll.kind) != null ? _a : "view";
|
|
6549
|
+
if (scroll.smoothing) {
|
|
6550
|
+
console.warn('scroll timeline: `smoothing` needs the built-in driver \u2014 ignoring `driver: "native"`');
|
|
6551
|
+
return null;
|
|
6552
|
+
}
|
|
6543
6553
|
const g = globalThis;
|
|
6544
6554
|
const view = kind === "view";
|
|
6545
6555
|
const Ctor = view ? g.ViewTimeline : g.ScrollTimeline;
|
|
@@ -6548,7 +6558,7 @@ function createNativeScrollTimeline(subject, config) {
|
|
|
6548
6558
|
let timeline;
|
|
6549
6559
|
try {
|
|
6550
6560
|
if (view) {
|
|
6551
|
-
timeline = new Ctor({ subject, axis });
|
|
6561
|
+
timeline = new Ctor({ subject: resolveScrollSubject(subject, scroll.subject), axis });
|
|
6552
6562
|
} else {
|
|
6553
6563
|
const source = scroll.source === "root" ? documentScroller() : findNearestScroller(subject, "y") || findNearestScroller(subject, "x") || documentScroller();
|
|
6554
6564
|
timeline = new Ctor({ source, axis });
|
|
@@ -6564,7 +6574,10 @@ function createNativeScrollTimeline(subject, config) {
|
|
|
6564
6574
|
};
|
|
6565
6575
|
}
|
|
6566
6576
|
function findNearestScroller(el, axis) {
|
|
6577
|
+
const body = document.body;
|
|
6578
|
+
const root = document.documentElement;
|
|
6567
6579
|
for (let p = el.parentElement; p; p = p.parentElement) {
|
|
6580
|
+
if (p === body || p === root) return null;
|
|
6568
6581
|
const style = getComputedStyle(p);
|
|
6569
6582
|
const overflow = axis === "y" ? style.overflowY : style.overflowX;
|
|
6570
6583
|
if (overflow === "auto" || overflow === "scroll" || overflow === "hidden" || overflow === "overlay") {
|
|
@@ -6576,11 +6589,42 @@ function findNearestScroller(el, axis) {
|
|
|
6576
6589
|
function documentScroller() {
|
|
6577
6590
|
return document.scrollingElement || document.documentElement;
|
|
6578
6591
|
}
|
|
6592
|
+
var SUBJECT_PARENT = "parent";
|
|
6593
|
+
var SUBJECT_SCROLLER = "scroller";
|
|
6594
|
+
function resolveScrollSubject(svgRoot, subject) {
|
|
6595
|
+
var _a, _b;
|
|
6596
|
+
const spec = subject == null ? void 0 : subject.trim();
|
|
6597
|
+
if (!spec) return svgRoot;
|
|
6598
|
+
if (spec === SUBJECT_PARENT) {
|
|
6599
|
+
let outermostPinned = null;
|
|
6600
|
+
for (let p = svgRoot.parentElement; p && p !== document.body; p = p.parentElement) {
|
|
6601
|
+
const position = getComputedStyle(p).position;
|
|
6602
|
+
if (position === "sticky" || position === "fixed") outermostPinned = p;
|
|
6603
|
+
}
|
|
6604
|
+
return (_b = (_a = outermostPinned == null ? void 0 : outermostPinned.parentElement) != null ? _a : svgRoot.parentElement) != null ? _b : svgRoot;
|
|
6605
|
+
}
|
|
6606
|
+
if (spec === SUBJECT_SCROLLER) {
|
|
6607
|
+
return findNearestScroller(svgRoot, "y") || findNearestScroller(svgRoot, "x") || documentScroller();
|
|
6608
|
+
}
|
|
6609
|
+
let found = null;
|
|
6610
|
+
try {
|
|
6611
|
+
found = document.querySelector(spec);
|
|
6612
|
+
} catch (e) {
|
|
6613
|
+
console.warn('scroll timeline: subject "' + spec + '" is not a valid selector \u2014 measuring the SVG itself');
|
|
6614
|
+
return svgRoot;
|
|
6615
|
+
}
|
|
6616
|
+
if (!found) {
|
|
6617
|
+
console.warn('scroll timeline: subject "' + spec + '" matched no element \u2014 measuring the SVG itself');
|
|
6618
|
+
return svgRoot;
|
|
6619
|
+
}
|
|
6620
|
+
return found;
|
|
6621
|
+
}
|
|
6579
6622
|
function createScrollDriver(subject, config, onProgress) {
|
|
6580
|
-
var _a;
|
|
6623
|
+
var _a, _b;
|
|
6581
6624
|
if (!config || !isScrollTimeline(config)) return null;
|
|
6582
6625
|
const scroll = config.scroll || {};
|
|
6583
6626
|
const kind = (_a = scroll.kind) != null ? _a : "view";
|
|
6627
|
+
const measured = resolveScrollSubject(subject, scroll.subject);
|
|
6584
6628
|
const nearest = findNearestScroller(subject, "y") || findNearestScroller(subject, "x");
|
|
6585
6629
|
const scroller = kind === "scroll" && scroll.source === "root" ? documentScroller() : nearest || documentScroller();
|
|
6586
6630
|
const isRootScroller = scroller === documentScroller();
|
|
@@ -6591,7 +6635,7 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6591
6635
|
const maxOffset = axis === "y" ? scroller.scrollHeight - scroller.clientHeight : scroller.scrollWidth - scroller.clientWidth;
|
|
6592
6636
|
return scrollOffsetProgress(offset, maxOffset, scroll.range);
|
|
6593
6637
|
}
|
|
6594
|
-
const subjectRect =
|
|
6638
|
+
const subjectRect = measured.getBoundingClientRect();
|
|
6595
6639
|
let portStart, portSize;
|
|
6596
6640
|
if (isRootScroller) {
|
|
6597
6641
|
portStart = 0;
|
|
@@ -6605,12 +6649,43 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6605
6649
|
const subjectSize = axis === "y" ? subjectRect.height : subjectRect.width;
|
|
6606
6650
|
return scrollViewProgress(subjectStart, subjectSize, portSize, scroll.range);
|
|
6607
6651
|
};
|
|
6608
|
-
|
|
6652
|
+
const smoothingSec = Math.max(0, (_b = scroll.smoothing) != null ? _b : 0) / 1e3;
|
|
6653
|
+
const SETTLE_EPSILON = 1e-3;
|
|
6609
6654
|
let destroyed = false;
|
|
6655
|
+
let smoothed = null;
|
|
6656
|
+
let smoothRaf = null;
|
|
6657
|
+
let lastFrameMs = 0;
|
|
6658
|
+
const emit = (target) => {
|
|
6659
|
+
if (!smoothingSec) {
|
|
6660
|
+
onProgress(target);
|
|
6661
|
+
return;
|
|
6662
|
+
}
|
|
6663
|
+
if (smoothed === null) {
|
|
6664
|
+
smoothed = target;
|
|
6665
|
+
onProgress(target);
|
|
6666
|
+
return;
|
|
6667
|
+
}
|
|
6668
|
+
if (smoothRaf !== null) return;
|
|
6669
|
+
lastFrameMs = 0;
|
|
6670
|
+
const step = (nowMs) => {
|
|
6671
|
+
smoothRaf = null;
|
|
6672
|
+
if (destroyed) return;
|
|
6673
|
+
const dtSec = lastFrameMs ? Math.min(0.1, (nowMs - lastFrameMs) / 1e3) : 1 / 60;
|
|
6674
|
+
lastFrameMs = nowMs;
|
|
6675
|
+
const goal = compute();
|
|
6676
|
+
const k = 1 - Math.exp(-dtSec / smoothingSec);
|
|
6677
|
+
smoothed = smoothed + (goal - smoothed) * k;
|
|
6678
|
+
if (Math.abs(goal - smoothed) < SETTLE_EPSILON) smoothed = goal;
|
|
6679
|
+
onProgress(smoothed);
|
|
6680
|
+
if (smoothed !== goal) smoothRaf = requestAnimationFrame(step);
|
|
6681
|
+
};
|
|
6682
|
+
smoothRaf = requestAnimationFrame(step);
|
|
6683
|
+
};
|
|
6684
|
+
let rafId = null;
|
|
6610
6685
|
const tick = () => {
|
|
6611
6686
|
rafId = null;
|
|
6612
6687
|
if (destroyed) return;
|
|
6613
|
-
|
|
6688
|
+
emit(compute());
|
|
6614
6689
|
};
|
|
6615
6690
|
const schedule = () => {
|
|
6616
6691
|
if (destroyed || rafId !== null) return;
|
|
@@ -6622,7 +6697,8 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6622
6697
|
let resizeObserver;
|
|
6623
6698
|
if (typeof ResizeObserver !== "undefined") {
|
|
6624
6699
|
resizeObserver = new ResizeObserver(schedule);
|
|
6625
|
-
resizeObserver.observe(
|
|
6700
|
+
resizeObserver.observe(measured);
|
|
6701
|
+
if (measured !== subject) resizeObserver.observe(subject);
|
|
6626
6702
|
if (!isRootScroller) resizeObserver.observe(scroller);
|
|
6627
6703
|
}
|
|
6628
6704
|
const driver = {
|
|
@@ -6636,14 +6712,50 @@ function createScrollDriver(subject, config, onProgress) {
|
|
|
6636
6712
|
cancelAnimationFrame(rafId);
|
|
6637
6713
|
rafId = null;
|
|
6638
6714
|
}
|
|
6715
|
+
if (smoothRaf !== null) {
|
|
6716
|
+
cancelAnimationFrame(smoothRaf);
|
|
6717
|
+
smoothRaf = null;
|
|
6718
|
+
}
|
|
6639
6719
|
},
|
|
6720
|
+
// `refresh` is a deliberate JUMP (attach, host relayout) — never eased.
|
|
6640
6721
|
refresh: () => {
|
|
6641
|
-
if (!destroyed)
|
|
6722
|
+
if (!destroyed) {
|
|
6723
|
+
smoothed = compute();
|
|
6724
|
+
onProgress(smoothed);
|
|
6725
|
+
}
|
|
6642
6726
|
}
|
|
6643
6727
|
};
|
|
6644
6728
|
driver.refresh();
|
|
6645
6729
|
return driver;
|
|
6646
6730
|
}
|
|
6731
|
+
function applyScrollPin(svgRoot, scroll) {
|
|
6732
|
+
var _a;
|
|
6733
|
+
const styled = svgRoot;
|
|
6734
|
+
if (!(scroll == null ? void 0 : scroll.pin) || !styled.style) return () => {
|
|
6735
|
+
};
|
|
6736
|
+
const style = styled.style;
|
|
6737
|
+
const prevPosition = style.position;
|
|
6738
|
+
const prevTop = style.top;
|
|
6739
|
+
style.position = "sticky";
|
|
6740
|
+
style.top = ((_a = scroll.pinTop) != null ? _a : 0) + "px";
|
|
6741
|
+
let wrapper = null;
|
|
6742
|
+
const parent = svgRoot.parentElement;
|
|
6743
|
+
if (scroll.pinDistance && scroll.pinDistance > 0 && parent) {
|
|
6744
|
+
wrapper = document.createElement("div");
|
|
6745
|
+
wrapper.setAttribute("data-px-pin", "");
|
|
6746
|
+
wrapper.style.height = scroll.pinDistance * 100 + "vh";
|
|
6747
|
+
parent.insertBefore(wrapper, svgRoot);
|
|
6748
|
+
wrapper.appendChild(svgRoot);
|
|
6749
|
+
}
|
|
6750
|
+
return () => {
|
|
6751
|
+
style.position = prevPosition;
|
|
6752
|
+
style.top = prevTop;
|
|
6753
|
+
if (wrapper == null ? void 0 : wrapper.parentElement) {
|
|
6754
|
+
wrapper.parentElement.insertBefore(svgRoot, wrapper);
|
|
6755
|
+
wrapper.remove();
|
|
6756
|
+
}
|
|
6757
|
+
};
|
|
6758
|
+
}
|
|
6647
6759
|
|
|
6648
6760
|
// src/PxAnimatorBind.ts
|
|
6649
6761
|
function finaliseAnimator(animatorConfig, callbacks, make) {
|
|
@@ -6670,7 +6782,10 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
|
|
|
6670
6782
|
if (isScrollTimeline(animatorConfig)) {
|
|
6671
6783
|
return finaliseAnimator(animatorConfig, callbacks, (cb) => {
|
|
6672
6784
|
var _a, _b;
|
|
6785
|
+
let unpin = () => {
|
|
6786
|
+
};
|
|
6673
6787
|
if (animatorConfig.mode !== PxAnimatorMode.frames && ((_a = animatorConfig.scroll) == null ? void 0 : _a.driver) === "native" && rootElement) {
|
|
6788
|
+
unpin = applyScrollPin(rootElement, animatorConfig.scroll);
|
|
6674
6789
|
const native = createNativeScrollTimeline(rootElement, animatorConfig);
|
|
6675
6790
|
if (native) {
|
|
6676
6791
|
const api2 = createWebApiAnimator(
|
|
@@ -6680,12 +6795,23 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
|
|
|
6680
6795
|
animatorConfig.mode === PxAnimatorMode.waapi,
|
|
6681
6796
|
native
|
|
6682
6797
|
);
|
|
6683
|
-
if (api2)
|
|
6798
|
+
if (api2) {
|
|
6799
|
+
const destroyNative = api2.destroy.bind(api2);
|
|
6800
|
+
api2.destroy = () => {
|
|
6801
|
+
unpin();
|
|
6802
|
+
destroyNative();
|
|
6803
|
+
};
|
|
6804
|
+
return api2;
|
|
6805
|
+
}
|
|
6684
6806
|
}
|
|
6807
|
+
unpin();
|
|
6808
|
+
unpin = () => {
|
|
6809
|
+
};
|
|
6685
6810
|
}
|
|
6686
6811
|
const api = (animatorConfig.mode !== PxAnimatorMode.frames ? createWebApiAnimator(doc, cb, rootElement, animatorConfig.mode === PxAnimatorMode.waapi) : null) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
|
|
6687
6812
|
const subject = ((_b = api.getRootElement) == null ? void 0 : _b.call(api)) || rootElement;
|
|
6688
6813
|
if (subject) {
|
|
6814
|
+
unpin = applyScrollPin(subject, animatorConfig.scroll);
|
|
6689
6815
|
const totalMs = scrollTotalDurationMs(animatorConfig);
|
|
6690
6816
|
const driver = createScrollDriver(
|
|
6691
6817
|
subject,
|
|
@@ -6696,6 +6822,7 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
|
|
|
6696
6822
|
const destroy = api.destroy.bind(api);
|
|
6697
6823
|
api.destroy = () => {
|
|
6698
6824
|
driver.destroy();
|
|
6825
|
+
unpin();
|
|
6699
6826
|
destroy();
|
|
6700
6827
|
};
|
|
6701
6828
|
}
|