motion 10.11.0 → 10.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/animate.cjs.js +5 -5
- package/dist/animate.es.js +6 -6
- package/dist/main.cjs.js +7 -25
- package/dist/main.es.js +2 -2
- package/dist/motion.min.js +1 -1
- package/dist/motion.umd.js +884 -75
- package/dist/react.cjs.js +0 -0
- package/dist/react.es.js +0 -0
- package/dist/size-index.js +1 -1
- package/dist/vue.cjs.js +0 -0
- package/dist/vue.es.js +0 -0
- package/lib/animate.js +6 -6
- package/lib/animate.js.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/react.js +0 -0
- package/lib/react.js.map +0 -0
- package/lib/vue.js +0 -0
- package/lib/vue.js.map +0 -0
- package/package.json +8 -8
- package/types/animate.d.ts +2 -2
- package/types/animate.d.ts.map +1 -1
- package/types/index.d.ts +2 -3
- package/types/index.d.ts.map +1 -1
- package/types/react.d.ts +0 -0
- package/types/react.d.ts.map +0 -0
- package/types/vue.d.ts +0 -0
- package/types/vue.d.ts.map +0 -0
package/dist/motion.umd.js
CHANGED
|
@@ -62,6 +62,17 @@
|
|
|
62
62
|
const isCubicBezier = (easing) => Array.isArray(easing) && isNumber(easing[0]);
|
|
63
63
|
const isEasingList = (easing) => Array.isArray(easing) && !isNumber(easing[0]);
|
|
64
64
|
|
|
65
|
+
const wrap = (min, max, v) => {
|
|
66
|
+
const rangeSize = max - min;
|
|
67
|
+
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
function getEasingForSegment(easing, i) {
|
|
71
|
+
return isEasingList(easing)
|
|
72
|
+
? easing[wrap(0, easing.length, i)]
|
|
73
|
+
: easing;
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
const mix = (min, max, progress) => -progress * min + progress * max + min;
|
|
66
77
|
|
|
67
78
|
const noop = () => { };
|
|
@@ -76,12 +87,35 @@
|
|
|
76
87
|
offset.push(mix(min, 1, offsetProgress));
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
|
-
function defaultOffset(length) {
|
|
90
|
+
function defaultOffset$1(length) {
|
|
80
91
|
const offset = [0];
|
|
81
92
|
fillOffset(offset, length - 1);
|
|
82
93
|
return offset;
|
|
83
94
|
}
|
|
84
95
|
|
|
96
|
+
function interpolate(output, input = defaultOffset$1(output.length), easing = noopReturn) {
|
|
97
|
+
const length = output.length;
|
|
98
|
+
/**
|
|
99
|
+
* If the input length is lower than the output we
|
|
100
|
+
* fill the input to match. This currently assumes the input
|
|
101
|
+
* is an animation progress value so is a good candidate for
|
|
102
|
+
* moving outside the function.
|
|
103
|
+
*/
|
|
104
|
+
const remainder = length - input.length;
|
|
105
|
+
remainder > 0 && fillOffset(input, remainder);
|
|
106
|
+
return (t) => {
|
|
107
|
+
let i = 0;
|
|
108
|
+
for (; i < length - 2; i++) {
|
|
109
|
+
if (t < input[i + 1])
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
let progressInRange = clamp(0, 1, progress(input[i], input[i + 1], t));
|
|
113
|
+
const segmentEasing = getEasingForSegment(easing, i);
|
|
114
|
+
progressInRange = segmentEasing(progressInRange);
|
|
115
|
+
return mix(output[i], output[i + 1], progressInRange);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
85
119
|
const time = {
|
|
86
120
|
ms: (seconds) => seconds * 1000,
|
|
87
121
|
s: (milliseconds) => milliseconds / 1000,
|
|
@@ -97,11 +131,6 @@
|
|
|
97
131
|
return frameDuration ? velocity * (1000 / frameDuration) : 0;
|
|
98
132
|
}
|
|
99
133
|
|
|
100
|
-
const wrap = (min, max, v) => {
|
|
101
|
-
const rangeSize = max - min;
|
|
102
|
-
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
134
|
/**
|
|
106
135
|
* A list of all transformable axes. We'll use this list to generated a version
|
|
107
136
|
* of each axes for each transform.
|
|
@@ -282,67 +311,46 @@
|
|
|
282
311
|
}
|
|
283
312
|
return noopReturn;
|
|
284
313
|
}
|
|
285
|
-
function getEasingForSegment(easing, i) {
|
|
286
|
-
return isEasingList(easing)
|
|
287
|
-
? easing[wrap(0, easing.length, i)]
|
|
288
|
-
: easing;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const clampProgress = (p) => Math.min(1, Math.max(p, 0));
|
|
292
|
-
function interpolate(output, input = defaultOffset(output.length), easing = noopReturn) {
|
|
293
|
-
const length = output.length;
|
|
294
|
-
/**
|
|
295
|
-
* If the input length is lower than the output we
|
|
296
|
-
* fill the input to match. This currently assumes the input
|
|
297
|
-
* is an animation progress value so is a good candidate for
|
|
298
|
-
* moving outside the function.
|
|
299
|
-
*/
|
|
300
|
-
const remainder = length - input.length;
|
|
301
|
-
remainder > 0 && fillOffset(input, remainder);
|
|
302
|
-
return (t) => {
|
|
303
|
-
let i = 0;
|
|
304
|
-
for (; i < length - 2; i++) {
|
|
305
|
-
if (t < input[i + 1])
|
|
306
|
-
break;
|
|
307
|
-
}
|
|
308
|
-
let progressInRange = clampProgress(progress(input[i], input[i + 1], t));
|
|
309
|
-
const segmentEasing = getEasingForSegment(easing, i);
|
|
310
|
-
progressInRange = segmentEasing(progressInRange);
|
|
311
|
-
return mix(output[i], output[i + 1], progressInRange);
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
314
|
|
|
315
315
|
class Animation {
|
|
316
|
-
constructor(output, keyframes = [0, 1], { easing
|
|
316
|
+
constructor(output, keyframes = [0, 1], { easing, duration: initialDuration = defaults$1.duration, delay = defaults$1.delay, endDelay = defaults$1.endDelay, repeat = defaults$1.repeat, offset, direction = "normal", } = {}) {
|
|
317
317
|
this.startTime = null;
|
|
318
318
|
this.rate = 1;
|
|
319
319
|
this.t = 0;
|
|
320
320
|
this.cancelTimestamp = null;
|
|
321
|
+
this.easing = noopReturn;
|
|
322
|
+
this.duration = 0;
|
|
323
|
+
this.totalDuration = 0;
|
|
324
|
+
this.repeat = 0;
|
|
321
325
|
this.playState = "idle";
|
|
322
326
|
this.finished = new Promise((resolve, reject) => {
|
|
323
327
|
this.resolve = resolve;
|
|
324
328
|
this.reject = reject;
|
|
325
329
|
});
|
|
330
|
+
easing = easing || defaults$1.easing;
|
|
326
331
|
if (isEasingGenerator(easing)) {
|
|
327
332
|
const custom = easing.createAnimation(keyframes, () => "0", true);
|
|
328
333
|
easing = custom.easing;
|
|
329
334
|
if (custom.keyframes !== undefined)
|
|
330
335
|
keyframes = custom.keyframes;
|
|
331
336
|
if (custom.duration !== undefined)
|
|
332
|
-
|
|
337
|
+
initialDuration = custom.duration;
|
|
333
338
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const totalDuration = duration * (repeat + 1);
|
|
339
|
+
this.repeat = repeat;
|
|
340
|
+
this.easing = isEasingList(easing) ? noopReturn : getEasingFunction(easing);
|
|
341
|
+
this.updateDuration(initialDuration);
|
|
338
342
|
const interpolate$1 = interpolate(keyframes, offset, isEasingList(easing) ? easing.map(getEasingFunction) : noopReturn);
|
|
339
343
|
this.tick = (timestamp) => {
|
|
340
344
|
var _a;
|
|
341
345
|
// TODO: Temporary fix for OptionsResolver typing
|
|
342
346
|
delay = delay;
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
347
|
+
let t = 0;
|
|
348
|
+
if (this.pauseTime !== undefined) {
|
|
349
|
+
t = this.pauseTime;
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
t = (timestamp - this.startTime) * this.rate;
|
|
353
|
+
}
|
|
346
354
|
this.t = t;
|
|
347
355
|
// Convert to seconds
|
|
348
356
|
t /= 1000;
|
|
@@ -352,14 +360,15 @@
|
|
|
352
360
|
* If this animation has finished, set the current time
|
|
353
361
|
* to the total duration.
|
|
354
362
|
*/
|
|
355
|
-
if (this.playState === "finished")
|
|
356
|
-
t = totalDuration;
|
|
363
|
+
if (this.playState === "finished" && this.pauseTime === undefined) {
|
|
364
|
+
t = this.totalDuration;
|
|
365
|
+
}
|
|
357
366
|
/**
|
|
358
367
|
* Get the current progress (0-1) of the animation. If t is >
|
|
359
368
|
* than duration we'll get values like 2.5 (midway through the
|
|
360
369
|
* third iteration)
|
|
361
370
|
*/
|
|
362
|
-
const progress = t / duration;
|
|
371
|
+
const progress = t / this.duration;
|
|
363
372
|
// TODO progress += iterationStart
|
|
364
373
|
/**
|
|
365
374
|
* Get the current iteration (0 indexed). For instance the floor of
|
|
@@ -388,10 +397,11 @@
|
|
|
388
397
|
(direction === "alternate-reverse" && !iterationIsOdd)) {
|
|
389
398
|
iterationProgress = 1 - iterationProgress;
|
|
390
399
|
}
|
|
391
|
-
const p = t >= totalDuration ? 1 : Math.min(iterationProgress, 1);
|
|
392
|
-
const latest = interpolate$1(
|
|
400
|
+
const p = t >= this.totalDuration ? 1 : Math.min(iterationProgress, 1);
|
|
401
|
+
const latest = interpolate$1(this.easing(p));
|
|
393
402
|
output(latest);
|
|
394
|
-
const isAnimationFinished = this.
|
|
403
|
+
const isAnimationFinished = this.pauseTime === undefined &&
|
|
404
|
+
(this.playState === "finished" || t >= this.totalDuration + endDelay);
|
|
395
405
|
if (isAnimationFinished) {
|
|
396
406
|
this.playState = "finished";
|
|
397
407
|
(_a = this.resolve) === null || _a === void 0 ? void 0 : _a.call(this, latest);
|
|
@@ -403,22 +413,21 @@
|
|
|
403
413
|
this.play();
|
|
404
414
|
}
|
|
405
415
|
play() {
|
|
406
|
-
var _a;
|
|
407
416
|
const now = performance.now();
|
|
408
417
|
this.playState = "running";
|
|
409
|
-
if (this.pauseTime) {
|
|
410
|
-
this.startTime = now -
|
|
418
|
+
if (this.pauseTime !== undefined) {
|
|
419
|
+
this.startTime = now - this.pauseTime;
|
|
411
420
|
}
|
|
412
421
|
else if (!this.startTime) {
|
|
413
422
|
this.startTime = now;
|
|
414
423
|
}
|
|
415
424
|
this.cancelTimestamp = this.startTime;
|
|
416
425
|
this.pauseTime = undefined;
|
|
417
|
-
requestAnimationFrame(this.tick);
|
|
426
|
+
this.frameRequestId = requestAnimationFrame(this.tick);
|
|
418
427
|
}
|
|
419
428
|
pause() {
|
|
420
429
|
this.playState = "paused";
|
|
421
|
-
this.pauseTime =
|
|
430
|
+
this.pauseTime = this.t;
|
|
422
431
|
}
|
|
423
432
|
finish() {
|
|
424
433
|
this.playState = "finished";
|
|
@@ -440,11 +449,15 @@
|
|
|
440
449
|
this.rate *= -1;
|
|
441
450
|
}
|
|
442
451
|
commitStyles() { }
|
|
452
|
+
updateDuration(duration) {
|
|
453
|
+
this.duration = duration;
|
|
454
|
+
this.totalDuration = duration * (this.repeat + 1);
|
|
455
|
+
}
|
|
443
456
|
get currentTime() {
|
|
444
457
|
return this.t;
|
|
445
458
|
}
|
|
446
459
|
set currentTime(t) {
|
|
447
|
-
if (this.pauseTime || this.rate === 0) {
|
|
460
|
+
if (this.pauseTime !== undefined || this.rate === 0) {
|
|
448
461
|
this.pauseTime = t;
|
|
449
462
|
}
|
|
450
463
|
else {
|
|
@@ -744,10 +757,13 @@
|
|
|
744
757
|
}
|
|
745
758
|
|
|
746
759
|
const createAnimation = (factory) => factory();
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
760
|
+
const withControls = (animationFactory, options, duration = defaults$1.duration) => {
|
|
761
|
+
return new Proxy({
|
|
762
|
+
animations: animationFactory.map(createAnimation).filter(Boolean),
|
|
763
|
+
duration,
|
|
764
|
+
options,
|
|
765
|
+
}, controls);
|
|
766
|
+
};
|
|
751
767
|
/**
|
|
752
768
|
* TODO:
|
|
753
769
|
* Currently this returns the first animation, ideally it would return
|
|
@@ -761,8 +777,7 @@
|
|
|
761
777
|
case "duration":
|
|
762
778
|
return target.duration;
|
|
763
779
|
case "currentTime":
|
|
764
|
-
|
|
765
|
-
return time ? time / 1000 : 0;
|
|
780
|
+
return time.s((activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation[key]) || 0);
|
|
766
781
|
case "playbackRate":
|
|
767
782
|
case "playState":
|
|
768
783
|
return activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation[key];
|
|
@@ -772,7 +787,17 @@
|
|
|
772
787
|
}
|
|
773
788
|
return target.finished;
|
|
774
789
|
case "stop":
|
|
775
|
-
return () =>
|
|
790
|
+
return () => {
|
|
791
|
+
target.animations.forEach((animation) => stopAnimation(animation));
|
|
792
|
+
};
|
|
793
|
+
case "forEachNative":
|
|
794
|
+
/**
|
|
795
|
+
* This is for internal use only, fire a callback for each
|
|
796
|
+
* underlying animation.
|
|
797
|
+
*/
|
|
798
|
+
return (callback) => {
|
|
799
|
+
target.animations.forEach((animation) => callback(animation, target));
|
|
800
|
+
};
|
|
776
801
|
default:
|
|
777
802
|
return typeof (activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation[key]) === "undefined"
|
|
778
803
|
? undefined
|
|
@@ -839,7 +864,7 @@
|
|
|
839
864
|
animationFactories.push(animation);
|
|
840
865
|
}
|
|
841
866
|
}
|
|
842
|
-
return
|
|
867
|
+
return withControls(animationFactories, options,
|
|
843
868
|
/**
|
|
844
869
|
* TODO:
|
|
845
870
|
* If easing is set to spring or glide, duration will be dynamically
|
|
@@ -948,7 +973,7 @@
|
|
|
948
973
|
const animationFactories = animationDefinitions
|
|
949
974
|
.map((definition) => animateStyle(...definition))
|
|
950
975
|
.filter(Boolean);
|
|
951
|
-
return
|
|
976
|
+
return withControls(animationFactories, options,
|
|
952
977
|
// Get the duration from the first animation definition
|
|
953
978
|
(_a = animationDefinitions[0]) === null || _a === void 0 ? void 0 : _a[3].duration);
|
|
954
979
|
}
|
|
@@ -1025,7 +1050,7 @@
|
|
|
1025
1050
|
/**
|
|
1026
1051
|
*
|
|
1027
1052
|
*/
|
|
1028
|
-
let { offset = defaultOffset(valueKeyframes.length) } = valueOptions;
|
|
1053
|
+
let { offset = defaultOffset$1(valueKeyframes.length) } = valueOptions;
|
|
1029
1054
|
/**
|
|
1030
1055
|
* If there's only one offset of 0, fill in a second with length 1
|
|
1031
1056
|
*
|
|
@@ -1377,7 +1402,7 @@
|
|
|
1377
1402
|
any: 0,
|
|
1378
1403
|
all: 1,
|
|
1379
1404
|
};
|
|
1380
|
-
function inView(
|
|
1405
|
+
function inView$1(elementOrSelector, onStart, { root, margin: rootMargin, amount = "any" } = {}) {
|
|
1381
1406
|
/**
|
|
1382
1407
|
* If this browser doesn't support IntersectionObserver, return a dummy stop function.
|
|
1383
1408
|
* Default triggering of onStart is tricky - it could be used for starting/stopping
|
|
@@ -1387,7 +1412,7 @@
|
|
|
1387
1412
|
if (typeof IntersectionObserver === "undefined") {
|
|
1388
1413
|
return () => { };
|
|
1389
1414
|
}
|
|
1390
|
-
const
|
|
1415
|
+
const elements = resolveElements(elementOrSelector);
|
|
1391
1416
|
const activeIntersections = new WeakMap();
|
|
1392
1417
|
const onIntersectionChange = (entries) => {
|
|
1393
1418
|
entries.forEach((entry) => {
|
|
@@ -1418,32 +1443,816 @@
|
|
|
1418
1443
|
rootMargin,
|
|
1419
1444
|
threshold: typeof amount === "number" ? amount : thresholds[amount],
|
|
1420
1445
|
});
|
|
1421
|
-
|
|
1446
|
+
elements.forEach((element) => observer.observe(element));
|
|
1422
1447
|
return () => observer.disconnect();
|
|
1423
1448
|
}
|
|
1424
1449
|
|
|
1425
|
-
|
|
1426
|
-
|
|
1450
|
+
const resizeHandlers = new WeakMap();
|
|
1451
|
+
let observer;
|
|
1452
|
+
function getElementSize(target, borderBoxSize) {
|
|
1453
|
+
if (borderBoxSize) {
|
|
1454
|
+
const { inlineSize, blockSize } = borderBoxSize[0];
|
|
1455
|
+
return { width: inlineSize, height: blockSize };
|
|
1456
|
+
}
|
|
1457
|
+
else if (target instanceof SVGElement && "getBBox" in target) {
|
|
1458
|
+
return target.getBBox();
|
|
1459
|
+
}
|
|
1460
|
+
else {
|
|
1461
|
+
return {
|
|
1462
|
+
width: target.offsetWidth,
|
|
1463
|
+
height: target.offsetHeight,
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function notifyTarget({ target, contentRect, borderBoxSize, }) {
|
|
1468
|
+
var _a;
|
|
1469
|
+
(_a = resizeHandlers.get(target)) === null || _a === void 0 ? void 0 : _a.forEach((handler) => {
|
|
1470
|
+
handler({
|
|
1471
|
+
target,
|
|
1472
|
+
contentSize: contentRect,
|
|
1473
|
+
get size() {
|
|
1474
|
+
return getElementSize(target, borderBoxSize);
|
|
1475
|
+
},
|
|
1476
|
+
});
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
function notifyAll(entries) {
|
|
1480
|
+
entries.forEach(notifyTarget);
|
|
1481
|
+
}
|
|
1482
|
+
function createResizeObserver() {
|
|
1483
|
+
if (typeof ResizeObserver === "undefined")
|
|
1484
|
+
return;
|
|
1485
|
+
observer = new ResizeObserver(notifyAll);
|
|
1486
|
+
}
|
|
1487
|
+
function resizeElement(target, handler) {
|
|
1488
|
+
if (!observer)
|
|
1489
|
+
createResizeObserver();
|
|
1490
|
+
const elements = resolveElements(target);
|
|
1491
|
+
elements.forEach((element) => {
|
|
1492
|
+
let elementHandlers = resizeHandlers.get(element);
|
|
1493
|
+
if (!elementHandlers) {
|
|
1494
|
+
elementHandlers = new Set();
|
|
1495
|
+
resizeHandlers.set(element, elementHandlers);
|
|
1496
|
+
}
|
|
1497
|
+
elementHandlers.add(handler);
|
|
1498
|
+
observer === null || observer === void 0 ? void 0 : observer.observe(element);
|
|
1499
|
+
});
|
|
1500
|
+
return () => {
|
|
1501
|
+
elements.forEach((element) => {
|
|
1502
|
+
const elementHandlers = resizeHandlers.get(element);
|
|
1503
|
+
elementHandlers === null || elementHandlers === void 0 ? void 0 : elementHandlers.delete(handler);
|
|
1504
|
+
if (!(elementHandlers === null || elementHandlers === void 0 ? void 0 : elementHandlers.size)) {
|
|
1505
|
+
observer === null || observer === void 0 ? void 0 : observer.unobserve(element);
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
const windowCallbacks = new Set();
|
|
1512
|
+
let windowResizeHandler;
|
|
1513
|
+
function createWindowResizeHandler() {
|
|
1514
|
+
windowResizeHandler = () => {
|
|
1515
|
+
const size = {
|
|
1516
|
+
width: window.innerWidth,
|
|
1517
|
+
height: window.innerHeight,
|
|
1518
|
+
};
|
|
1519
|
+
const info = {
|
|
1520
|
+
target: window,
|
|
1521
|
+
size,
|
|
1522
|
+
contentSize: size,
|
|
1523
|
+
};
|
|
1524
|
+
windowCallbacks.forEach((callback) => callback(info));
|
|
1525
|
+
};
|
|
1526
|
+
window.addEventListener("resize", windowResizeHandler);
|
|
1527
|
+
}
|
|
1528
|
+
function resizeWindow(callback) {
|
|
1529
|
+
windowCallbacks.add(callback);
|
|
1530
|
+
if (!windowResizeHandler)
|
|
1531
|
+
createWindowResizeHandler();
|
|
1532
|
+
return () => {
|
|
1533
|
+
windowCallbacks.delete(callback);
|
|
1534
|
+
if (!windowCallbacks.size && windowResizeHandler) {
|
|
1535
|
+
windowResizeHandler = undefined;
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function resize(a, b) {
|
|
1541
|
+
return typeof a === "function" ? resizeWindow(a) : resizeElement(a, b);
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* A time in milliseconds, beyond which we consider the scroll velocity to be 0.
|
|
1546
|
+
*/
|
|
1547
|
+
const maxElapsed = 50;
|
|
1548
|
+
const createAxisInfo = () => ({
|
|
1549
|
+
current: 0,
|
|
1550
|
+
offset: [],
|
|
1551
|
+
progress: 0,
|
|
1552
|
+
scrollLength: 0,
|
|
1553
|
+
targetOffset: 0,
|
|
1554
|
+
targetLength: 0,
|
|
1555
|
+
containerLength: 0,
|
|
1556
|
+
velocity: 0,
|
|
1557
|
+
});
|
|
1558
|
+
const createScrollInfo = () => ({
|
|
1559
|
+
time: 0,
|
|
1560
|
+
x: createAxisInfo(),
|
|
1561
|
+
y: createAxisInfo(),
|
|
1562
|
+
});
|
|
1563
|
+
const keys = {
|
|
1564
|
+
x: {
|
|
1565
|
+
length: "Width",
|
|
1566
|
+
position: "Left",
|
|
1567
|
+
},
|
|
1568
|
+
y: {
|
|
1569
|
+
length: "Height",
|
|
1570
|
+
position: "Top",
|
|
1571
|
+
},
|
|
1572
|
+
};
|
|
1573
|
+
function updateAxisInfo(element, axisName, info, time) {
|
|
1574
|
+
const axis = info[axisName];
|
|
1575
|
+
const { length, position } = keys[axisName];
|
|
1576
|
+
const prev = axis.current;
|
|
1577
|
+
const prevTime = info.time;
|
|
1578
|
+
axis.current = element["scroll" + position];
|
|
1579
|
+
axis.scrollLength = element["scroll" + length] - element["client" + length];
|
|
1580
|
+
axis.offset.length = 0;
|
|
1581
|
+
axis.offset[0] = 0;
|
|
1582
|
+
axis.offset[1] = axis.scrollLength;
|
|
1583
|
+
axis.progress = progress(0, axis.scrollLength, axis.current);
|
|
1584
|
+
const elapsed = time - prevTime;
|
|
1585
|
+
axis.velocity =
|
|
1586
|
+
elapsed > maxElapsed ? 0 : velocityPerSecond(axis.current - prev, elapsed);
|
|
1587
|
+
}
|
|
1588
|
+
function updateScrollInfo(element, info, time) {
|
|
1589
|
+
updateAxisInfo(element, "x", info, time);
|
|
1590
|
+
updateAxisInfo(element, "y", info, time);
|
|
1591
|
+
info.time = time;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
function calcInset(element, container) {
|
|
1595
|
+
let inset = { x: 0, y: 0 };
|
|
1596
|
+
let current = element;
|
|
1597
|
+
while (current && current !== container) {
|
|
1598
|
+
if (current instanceof HTMLElement) {
|
|
1599
|
+
inset.x += current.offsetLeft;
|
|
1600
|
+
inset.y += current.offsetTop;
|
|
1601
|
+
current = current.offsetParent;
|
|
1602
|
+
}
|
|
1603
|
+
else if (current instanceof SVGGraphicsElement && "getBBox" in current) {
|
|
1604
|
+
const { top, left } = current.getBBox();
|
|
1605
|
+
inset.x += left;
|
|
1606
|
+
inset.y += top;
|
|
1607
|
+
/**
|
|
1608
|
+
* Assign the next parent element as the <svg /> tag.
|
|
1609
|
+
*/
|
|
1610
|
+
while (current && current.tagName !== "svg") {
|
|
1611
|
+
current = current.parentNode;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
return inset;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
const ScrollOffset = {
|
|
1619
|
+
Enter: [
|
|
1620
|
+
[0, 1],
|
|
1621
|
+
[1, 1],
|
|
1622
|
+
],
|
|
1623
|
+
Exit: [
|
|
1624
|
+
[0, 0],
|
|
1625
|
+
[1, 0],
|
|
1626
|
+
],
|
|
1627
|
+
Any: [
|
|
1628
|
+
[1, 0],
|
|
1629
|
+
[0, 1],
|
|
1630
|
+
],
|
|
1631
|
+
All: [
|
|
1632
|
+
[0, 0],
|
|
1633
|
+
[1, 1],
|
|
1634
|
+
],
|
|
1635
|
+
};
|
|
1636
|
+
|
|
1637
|
+
const namedEdges = {
|
|
1638
|
+
start: 0,
|
|
1639
|
+
center: 0.5,
|
|
1640
|
+
end: 1,
|
|
1641
|
+
};
|
|
1642
|
+
function resolveEdge(edge, length, inset = 0) {
|
|
1643
|
+
let delta = 0;
|
|
1644
|
+
/**
|
|
1645
|
+
* If we have this edge defined as a preset, replace the definition
|
|
1646
|
+
* with the numerical value.
|
|
1647
|
+
*/
|
|
1648
|
+
if (namedEdges[edge] !== undefined) {
|
|
1649
|
+
edge = namedEdges[edge];
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Handle unit values
|
|
1653
|
+
*/
|
|
1654
|
+
if (isString(edge)) {
|
|
1655
|
+
const asNumber = parseFloat(edge);
|
|
1656
|
+
if (edge.endsWith("px")) {
|
|
1657
|
+
delta = asNumber;
|
|
1658
|
+
}
|
|
1659
|
+
else if (edge.endsWith("%")) {
|
|
1660
|
+
edge = asNumber / 100;
|
|
1661
|
+
}
|
|
1662
|
+
else if (edge.endsWith("vw")) {
|
|
1663
|
+
delta = (asNumber / 100) * document.documentElement.clientWidth;
|
|
1664
|
+
}
|
|
1665
|
+
else if (edge.endsWith("vh")) {
|
|
1666
|
+
delta = (asNumber / 100) * document.documentElement.clientHeight;
|
|
1667
|
+
}
|
|
1668
|
+
else {
|
|
1669
|
+
edge = asNumber;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* If the edge is defined as a number, handle as a progress value.
|
|
1674
|
+
*/
|
|
1675
|
+
if (isNumber(edge)) {
|
|
1676
|
+
delta = length * edge;
|
|
1677
|
+
}
|
|
1678
|
+
return inset + delta;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
const defaultOffset = [0, 0];
|
|
1682
|
+
function resolveOffset(offset, containerLength, targetLength, targetInset) {
|
|
1683
|
+
let offsetDefinition = Array.isArray(offset) ? offset : defaultOffset;
|
|
1684
|
+
let targetPoint = 0;
|
|
1685
|
+
let containerPoint = 0;
|
|
1686
|
+
if (isNumber(offset)) {
|
|
1687
|
+
/**
|
|
1688
|
+
* If we're provided offset: [0, 0.5, 1] then each number x should become
|
|
1689
|
+
* [x, x], so we default to the behaviour of mapping 0 => 0 of both target
|
|
1690
|
+
* and container etc.
|
|
1691
|
+
*/
|
|
1692
|
+
offsetDefinition = [offset, offset];
|
|
1693
|
+
}
|
|
1694
|
+
else if (isString(offset)) {
|
|
1695
|
+
offset = offset.trim();
|
|
1696
|
+
if (offset.includes(" ")) {
|
|
1697
|
+
offsetDefinition = offset.split(" ");
|
|
1698
|
+
}
|
|
1699
|
+
else {
|
|
1700
|
+
/**
|
|
1701
|
+
* If we're provided a definition like "100px" then we want to apply
|
|
1702
|
+
* that only to the top of the target point, leaving the container at 0.
|
|
1703
|
+
* Whereas a named offset like "end" should be applied to both.
|
|
1704
|
+
*/
|
|
1705
|
+
offsetDefinition = [offset, namedEdges[offset] ? offset : `0`];
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
targetPoint = resolveEdge(offsetDefinition[0], targetLength, targetInset);
|
|
1709
|
+
containerPoint = resolveEdge(offsetDefinition[1], containerLength);
|
|
1710
|
+
return targetPoint - containerPoint;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
const point = { x: 0, y: 0 };
|
|
1714
|
+
function resolveOffsets(container, info, options) {
|
|
1715
|
+
let { offset: offsetDefinition = ScrollOffset.All } = options;
|
|
1716
|
+
const { target = container, axis = "y" } = options;
|
|
1717
|
+
const lengthLabel = axis === "y" ? "height" : "width";
|
|
1718
|
+
const inset = target !== container ? calcInset(target, container) : point;
|
|
1719
|
+
/**
|
|
1720
|
+
* Measure the target and container. If they're the same thing then we
|
|
1721
|
+
* use the container's scrollWidth/Height as the target, from there
|
|
1722
|
+
* all other calculations can remain the same.
|
|
1723
|
+
*/
|
|
1724
|
+
const targetSize = target === container
|
|
1725
|
+
? { width: container.scrollWidth, height: container.scrollHeight }
|
|
1726
|
+
: { width: target.clientWidth, height: target.clientHeight };
|
|
1727
|
+
const containerSize = {
|
|
1728
|
+
width: container.clientWidth,
|
|
1729
|
+
height: container.clientHeight,
|
|
1730
|
+
};
|
|
1731
|
+
/**
|
|
1732
|
+
* Reset the length of the resolved offset array rather than creating a new one.
|
|
1733
|
+
* TODO: More reusable data structures for targetSize/containerSize would also be good.
|
|
1734
|
+
*/
|
|
1735
|
+
info[axis].offset.length = 0;
|
|
1736
|
+
/**
|
|
1737
|
+
* Populate the offset array by resolving the user's offset definition into
|
|
1738
|
+
* a list of pixel scroll offets.
|
|
1739
|
+
*/
|
|
1740
|
+
let hasChanged = !info[axis].interpolate;
|
|
1741
|
+
const numOffsets = offsetDefinition.length;
|
|
1742
|
+
for (let i = 0; i < numOffsets; i++) {
|
|
1743
|
+
const offset = resolveOffset(offsetDefinition[i], containerSize[lengthLabel], targetSize[lengthLabel], inset[axis]);
|
|
1744
|
+
if (!hasChanged && offset !== info[axis].interpolatorOffsets[i]) {
|
|
1745
|
+
hasChanged = true;
|
|
1746
|
+
}
|
|
1747
|
+
info[axis].offset[i] = offset;
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* If the pixel scroll offsets have changed, create a new interpolator function
|
|
1751
|
+
* to map scroll value into a progress.
|
|
1752
|
+
*/
|
|
1753
|
+
if (hasChanged) {
|
|
1754
|
+
info[axis].interpolate = interpolate(defaultOffset$1(numOffsets), info[axis].offset);
|
|
1755
|
+
info[axis].interpolatorOffsets = [...info[axis].offset];
|
|
1756
|
+
}
|
|
1757
|
+
info[axis].progress = info[axis].interpolate(info[axis].current);
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
function measure(container, target = container, info) {
|
|
1761
|
+
/**
|
|
1762
|
+
* Find inset of target within scrollable container
|
|
1763
|
+
*/
|
|
1764
|
+
info.x.targetOffset = 0;
|
|
1765
|
+
info.y.targetOffset = 0;
|
|
1766
|
+
if (target !== container) {
|
|
1767
|
+
let node = target;
|
|
1768
|
+
while (node && node != container) {
|
|
1769
|
+
info.x.targetOffset += node.offsetLeft;
|
|
1770
|
+
info.y.targetOffset += node.offsetTop;
|
|
1771
|
+
node = node.offsetParent;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
info.x.targetLength =
|
|
1775
|
+
target === container ? target.scrollWidth : target.clientWidth;
|
|
1776
|
+
info.y.targetLength =
|
|
1777
|
+
target === container ? target.scrollHeight : target.clientHeight;
|
|
1778
|
+
info.x.containerLength = container.clientWidth;
|
|
1779
|
+
info.y.containerLength = container.clientHeight;
|
|
1780
|
+
}
|
|
1781
|
+
function createOnScrollHandler(element, onScroll, info, options = {}) {
|
|
1782
|
+
const axis = options.axis || "y";
|
|
1783
|
+
return {
|
|
1784
|
+
measure: () => measure(element, options.target, info),
|
|
1785
|
+
update: (time) => {
|
|
1786
|
+
updateScrollInfo(element, info, time);
|
|
1787
|
+
if (options.offset || options.target) {
|
|
1788
|
+
resolveOffsets(element, info, options);
|
|
1789
|
+
}
|
|
1790
|
+
},
|
|
1791
|
+
notify: typeof onScroll === "function"
|
|
1792
|
+
? () => onScroll(info)
|
|
1793
|
+
: scrubAnimation(onScroll, info[axis]),
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
function scrubAnimation(controls, axisInfo) {
|
|
1797
|
+
controls.pause();
|
|
1798
|
+
controls.forEachNative((animation, { easing }) => {
|
|
1799
|
+
var _a, _b;
|
|
1800
|
+
if (animation.updateDuration) {
|
|
1801
|
+
if (!easing)
|
|
1802
|
+
animation.easing = noopReturn;
|
|
1803
|
+
animation.updateDuration(1);
|
|
1804
|
+
}
|
|
1805
|
+
else {
|
|
1806
|
+
const timingOptions = { duration: 1000 };
|
|
1807
|
+
if (!easing)
|
|
1808
|
+
timingOptions.easing = "linear";
|
|
1809
|
+
(_b = (_a = animation.effect) === null || _a === void 0 ? void 0 : _a.updateTiming) === null || _b === void 0 ? void 0 : _b.call(_a, timingOptions);
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
return () => {
|
|
1813
|
+
controls.currentTime = axisInfo.progress;
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
const scrollListeners = new WeakMap();
|
|
1818
|
+
const resizeListeners = new WeakMap();
|
|
1819
|
+
const onScrollHandlers = new WeakMap();
|
|
1820
|
+
const getEventTarget = (element) => element === document.documentElement ? window : element;
|
|
1821
|
+
function scroll(onScroll, _a = {}) {
|
|
1822
|
+
var { container = document.documentElement } = _a, options = __rest(_a, ["container"]);
|
|
1823
|
+
let containerHandlers = onScrollHandlers.get(container);
|
|
1824
|
+
/**
|
|
1825
|
+
* Get the onScroll handlers for this container.
|
|
1826
|
+
* If one isn't found, create a new one.
|
|
1827
|
+
*/
|
|
1828
|
+
if (!containerHandlers) {
|
|
1829
|
+
containerHandlers = new Set();
|
|
1830
|
+
onScrollHandlers.set(container, containerHandlers);
|
|
1831
|
+
}
|
|
1832
|
+
/**
|
|
1833
|
+
* Create a new onScroll handler for the provided callback.
|
|
1834
|
+
*/
|
|
1835
|
+
const info = createScrollInfo();
|
|
1836
|
+
const containerHandler = createOnScrollHandler(container, onScroll, info, options);
|
|
1837
|
+
containerHandlers.add(containerHandler);
|
|
1838
|
+
/**
|
|
1839
|
+
* Check if there's a scroll event listener for this container.
|
|
1840
|
+
* If not, create one.
|
|
1841
|
+
*/
|
|
1842
|
+
if (!scrollListeners.has(container)) {
|
|
1843
|
+
const listener = () => {
|
|
1844
|
+
const time = performance.now();
|
|
1845
|
+
for (const handler of containerHandlers)
|
|
1846
|
+
handler.measure();
|
|
1847
|
+
for (const handler of containerHandlers)
|
|
1848
|
+
handler.update(time);
|
|
1849
|
+
for (const handler of containerHandlers)
|
|
1850
|
+
handler.notify();
|
|
1851
|
+
};
|
|
1852
|
+
scrollListeners.set(container, listener);
|
|
1853
|
+
const target = getEventTarget(container);
|
|
1854
|
+
window.addEventListener("resize", listener, { passive: true });
|
|
1855
|
+
if (container !== document.documentElement) {
|
|
1856
|
+
resizeListeners.set(container, resize(container, listener));
|
|
1857
|
+
}
|
|
1858
|
+
target.addEventListener("scroll", listener, { passive: true });
|
|
1859
|
+
}
|
|
1860
|
+
const listener = scrollListeners.get(container);
|
|
1861
|
+
const onLoadProcesss = requestAnimationFrame(listener);
|
|
1862
|
+
return () => {
|
|
1863
|
+
var _a;
|
|
1864
|
+
if (typeof onScroll !== "function")
|
|
1865
|
+
onScroll.stop();
|
|
1866
|
+
cancelAnimationFrame(onLoadProcesss);
|
|
1867
|
+
/**
|
|
1868
|
+
* Check if we even have any handlers for this container.
|
|
1869
|
+
*/
|
|
1870
|
+
const containerHandlers = onScrollHandlers.get(container);
|
|
1871
|
+
if (!containerHandlers)
|
|
1872
|
+
return;
|
|
1873
|
+
containerHandlers.delete(containerHandler);
|
|
1874
|
+
if (containerHandlers.size)
|
|
1875
|
+
return;
|
|
1876
|
+
/**
|
|
1877
|
+
* If no more handlers, remove the scroll listener too.
|
|
1878
|
+
*/
|
|
1879
|
+
const listener = scrollListeners.get(container);
|
|
1880
|
+
scrollListeners.delete(container);
|
|
1881
|
+
if (listener) {
|
|
1882
|
+
getEventTarget(container).removeEventListener("scroll", listener);
|
|
1883
|
+
(_a = resizeListeners.get(container)) === null || _a === void 0 ? void 0 : _a();
|
|
1884
|
+
window.removeEventListener("resize", listener);
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
function hasChanged(a, b) {
|
|
1890
|
+
if (typeof a !== typeof b)
|
|
1891
|
+
return true;
|
|
1892
|
+
if (Array.isArray(a) && Array.isArray(b))
|
|
1893
|
+
return !shallowCompare(a, b);
|
|
1894
|
+
return a !== b;
|
|
1895
|
+
}
|
|
1896
|
+
function shallowCompare(next, prev) {
|
|
1897
|
+
const prevLength = prev.length;
|
|
1898
|
+
if (prevLength !== next.length)
|
|
1899
|
+
return false;
|
|
1900
|
+
for (let i = 0; i < prevLength; i++) {
|
|
1901
|
+
if (prev[i] !== next[i])
|
|
1902
|
+
return false;
|
|
1903
|
+
}
|
|
1904
|
+
return true;
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
function isVariant(definition) {
|
|
1908
|
+
return typeof definition === "object";
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
function resolveVariant(definition, variants) {
|
|
1912
|
+
if (isVariant(definition)) {
|
|
1913
|
+
return definition;
|
|
1914
|
+
}
|
|
1915
|
+
else if (definition && variants) {
|
|
1916
|
+
return variants[definition];
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
let scheduled = undefined;
|
|
1921
|
+
function processScheduledAnimations() {
|
|
1922
|
+
if (!scheduled)
|
|
1923
|
+
return;
|
|
1924
|
+
const generators = scheduled.sort(compareByDepth).map(fireAnimateUpdates);
|
|
1925
|
+
generators.forEach(fireNext);
|
|
1926
|
+
generators.forEach(fireNext);
|
|
1927
|
+
scheduled = undefined;
|
|
1928
|
+
}
|
|
1929
|
+
function scheduleAnimation(state) {
|
|
1930
|
+
if (!scheduled) {
|
|
1931
|
+
scheduled = [state];
|
|
1932
|
+
requestAnimationFrame(processScheduledAnimations);
|
|
1933
|
+
}
|
|
1934
|
+
else {
|
|
1935
|
+
addUniqueItem(scheduled, state);
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
function unscheduleAnimation(state) {
|
|
1939
|
+
scheduled && removeItem(scheduled, state);
|
|
1940
|
+
}
|
|
1941
|
+
const compareByDepth = (a, b) => a.getDepth() - b.getDepth();
|
|
1942
|
+
const fireAnimateUpdates = (state) => state.animateUpdates();
|
|
1943
|
+
const fireNext = (iterator) => iterator.next();
|
|
1944
|
+
|
|
1945
|
+
const motionEvent = (name, target) => new CustomEvent(name, { detail: { target } });
|
|
1946
|
+
function dispatchPointerEvent(element, name, event) {
|
|
1947
|
+
element.dispatchEvent(new CustomEvent(name, { detail: { originalEvent: event } }));
|
|
1948
|
+
}
|
|
1949
|
+
function dispatchViewEvent(element, name, entry) {
|
|
1950
|
+
element.dispatchEvent(new CustomEvent(name, { detail: { originalEntry: entry } }));
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
const inView = {
|
|
1954
|
+
isActive: (options) => Boolean(options.inView),
|
|
1955
|
+
subscribe: (element, { enable, disable }, { inViewOptions = {} }) => {
|
|
1956
|
+
const { once } = inViewOptions, viewOptions = __rest(inViewOptions, ["once"]);
|
|
1957
|
+
return inView$1(element, (enterEntry) => {
|
|
1958
|
+
enable();
|
|
1959
|
+
dispatchViewEvent(element, "viewenter", enterEntry);
|
|
1960
|
+
if (!once) {
|
|
1961
|
+
return (leaveEntry) => {
|
|
1962
|
+
disable();
|
|
1963
|
+
dispatchViewEvent(element, "viewleave", leaveEntry);
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
}, viewOptions);
|
|
1967
|
+
},
|
|
1968
|
+
};
|
|
1969
|
+
|
|
1970
|
+
const mouseEvent = (element, name, action) => (event) => {
|
|
1971
|
+
if (event.pointerType && event.pointerType !== "mouse")
|
|
1972
|
+
return;
|
|
1973
|
+
action();
|
|
1974
|
+
dispatchPointerEvent(element, name, event);
|
|
1975
|
+
};
|
|
1976
|
+
const hover = {
|
|
1977
|
+
isActive: (options) => Boolean(options.hover),
|
|
1978
|
+
subscribe: (element, { enable, disable }) => {
|
|
1979
|
+
const onEnter = mouseEvent(element, "hoverstart", enable);
|
|
1980
|
+
const onLeave = mouseEvent(element, "hoverend", disable);
|
|
1981
|
+
element.addEventListener("pointerenter", onEnter);
|
|
1982
|
+
element.addEventListener("pointerleave", onLeave);
|
|
1983
|
+
return () => {
|
|
1984
|
+
element.removeEventListener("pointerenter", onEnter);
|
|
1985
|
+
element.removeEventListener("pointerleave", onLeave);
|
|
1986
|
+
};
|
|
1987
|
+
},
|
|
1988
|
+
};
|
|
1989
|
+
|
|
1990
|
+
const press = {
|
|
1991
|
+
isActive: (options) => Boolean(options.press),
|
|
1992
|
+
subscribe: (element, { enable, disable }) => {
|
|
1993
|
+
const onPointerUp = (event) => {
|
|
1994
|
+
disable();
|
|
1995
|
+
dispatchPointerEvent(element, "pressend", event);
|
|
1996
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
1997
|
+
};
|
|
1998
|
+
const onPointerDown = (event) => {
|
|
1999
|
+
enable();
|
|
2000
|
+
dispatchPointerEvent(element, "pressstart", event);
|
|
2001
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
2002
|
+
};
|
|
2003
|
+
element.addEventListener("pointerdown", onPointerDown);
|
|
2004
|
+
return () => {
|
|
2005
|
+
element.removeEventListener("pointerdown", onPointerDown);
|
|
2006
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
2007
|
+
};
|
|
2008
|
+
},
|
|
2009
|
+
};
|
|
2010
|
+
|
|
2011
|
+
const gestures = { inView, hover, press };
|
|
2012
|
+
/**
|
|
2013
|
+
* A list of state types, in priority order. If a value is defined in
|
|
2014
|
+
* a righter-most type, it will override any definition in a lefter-most.
|
|
2015
|
+
*/
|
|
2016
|
+
const stateTypes = ["initial", "animate", ...Object.keys(gestures), "exit"];
|
|
2017
|
+
/**
|
|
2018
|
+
* A global store of all generated motion states. This can be used to lookup
|
|
2019
|
+
* a motion state for a given Element.
|
|
2020
|
+
*/
|
|
2021
|
+
const mountedStates = new WeakMap();
|
|
2022
|
+
function createMotionState(options = {}, parent) {
|
|
2023
|
+
/**
|
|
2024
|
+
* The element represented by the motion state. This is an empty reference
|
|
2025
|
+
* when we create the state to support SSR and allow for later mounting
|
|
2026
|
+
* in view libraries.
|
|
2027
|
+
*
|
|
2028
|
+
* @ts-ignore
|
|
2029
|
+
*/
|
|
2030
|
+
let element;
|
|
2031
|
+
/**
|
|
2032
|
+
* Calculate a depth that we can use to order motion states by tree depth.
|
|
2033
|
+
*/
|
|
2034
|
+
let depth = parent ? parent.getDepth() + 1 : 0;
|
|
2035
|
+
/**
|
|
2036
|
+
* Track which states are currently active.
|
|
2037
|
+
*/
|
|
2038
|
+
const activeStates = { initial: true, animate: true };
|
|
2039
|
+
/**
|
|
2040
|
+
* A map of functions that, when called, will remove event listeners for
|
|
2041
|
+
* a given gesture.
|
|
2042
|
+
*/
|
|
2043
|
+
const gestureSubscriptions = {};
|
|
2044
|
+
/**
|
|
2045
|
+
* Initialise a context to share through motion states. This
|
|
2046
|
+
* will be populated by variant names (if any).
|
|
2047
|
+
*/
|
|
2048
|
+
const context = {};
|
|
2049
|
+
for (const name of stateTypes) {
|
|
2050
|
+
context[name] =
|
|
2051
|
+
typeof options[name] === "string"
|
|
2052
|
+
? options[name]
|
|
2053
|
+
: parent === null || parent === void 0 ? void 0 : parent.getContext()[name];
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* If initial is set to false we use the animate prop as the initial
|
|
2057
|
+
* animation state.
|
|
2058
|
+
*/
|
|
2059
|
+
const initialVariantSource = options.initial === false ? "animate" : "initial";
|
|
2060
|
+
/**
|
|
2061
|
+
* Destructure an initial target out from the resolved initial variant.
|
|
2062
|
+
*/
|
|
2063
|
+
let _a = resolveVariant(options[initialVariantSource] || context[initialVariantSource], options.variants) || {}, target = __rest(_a, ["transition"]);
|
|
2064
|
+
/**
|
|
2065
|
+
* The base target is a cached map of values that we'll use to animate
|
|
2066
|
+
* back to if a value is removed from all active state types. This
|
|
2067
|
+
* is usually the initial value as read from the DOM, for instance if
|
|
2068
|
+
* it hasn't been defined in initial.
|
|
2069
|
+
*/
|
|
2070
|
+
const baseTarget = Object.assign({}, target);
|
|
2071
|
+
/**
|
|
2072
|
+
* A generator that will be processed by the global animation scheduler.
|
|
2073
|
+
* This yeilds when it switches from reading the DOM to writing to it
|
|
2074
|
+
* to prevent layout thrashing.
|
|
2075
|
+
*/
|
|
2076
|
+
function* animateUpdates() {
|
|
2077
|
+
var _a, _b;
|
|
2078
|
+
const prevTarget = target;
|
|
2079
|
+
target = {};
|
|
2080
|
+
const animationOptions = {};
|
|
2081
|
+
for (const name of stateTypes) {
|
|
2082
|
+
if (!activeStates[name])
|
|
2083
|
+
continue;
|
|
2084
|
+
const variant = resolveVariant(options[name]);
|
|
2085
|
+
if (!variant)
|
|
2086
|
+
continue;
|
|
2087
|
+
for (const key in variant) {
|
|
2088
|
+
if (key === "transition")
|
|
2089
|
+
continue;
|
|
2090
|
+
target[key] = variant[key];
|
|
2091
|
+
animationOptions[key] = getOptions((_b = (_a = variant.transition) !== null && _a !== void 0 ? _a : options.transition) !== null && _b !== void 0 ? _b : {}, key);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
const allTargetKeys = new Set([
|
|
2095
|
+
...Object.keys(target),
|
|
2096
|
+
...Object.keys(prevTarget),
|
|
2097
|
+
]);
|
|
2098
|
+
const animationFactories = [];
|
|
2099
|
+
allTargetKeys.forEach((key) => {
|
|
2100
|
+
var _a;
|
|
2101
|
+
if (target[key] === undefined) {
|
|
2102
|
+
target[key] = baseTarget[key];
|
|
2103
|
+
}
|
|
2104
|
+
if (hasChanged(prevTarget[key], target[key])) {
|
|
2105
|
+
(_a = baseTarget[key]) !== null && _a !== void 0 ? _a : (baseTarget[key] = style.get(element, key));
|
|
2106
|
+
animationFactories.push(animateStyle(element, key, target[key], animationOptions[key]));
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
// Wait for all animation states to read from the DOM
|
|
2110
|
+
yield;
|
|
2111
|
+
const animations = animationFactories
|
|
2112
|
+
.map((factory) => factory())
|
|
2113
|
+
.filter(Boolean);
|
|
2114
|
+
if (!animations.length)
|
|
2115
|
+
return;
|
|
2116
|
+
const animationTarget = target;
|
|
2117
|
+
element.dispatchEvent(motionEvent("motionstart", animationTarget));
|
|
2118
|
+
Promise.all(animations.map((animation) => animation.finished))
|
|
2119
|
+
.then(() => {
|
|
2120
|
+
element.dispatchEvent(motionEvent("motioncomplete", animationTarget));
|
|
2121
|
+
})
|
|
2122
|
+
.catch(noop);
|
|
2123
|
+
}
|
|
2124
|
+
const setGesture = (name, isActive) => () => {
|
|
2125
|
+
activeStates[name] = isActive;
|
|
2126
|
+
scheduleAnimation(state);
|
|
2127
|
+
};
|
|
2128
|
+
const updateGestureSubscriptions = () => {
|
|
2129
|
+
for (const name in gestures) {
|
|
2130
|
+
const isGestureActive = gestures[name].isActive(options);
|
|
2131
|
+
const remove = gestureSubscriptions[name];
|
|
2132
|
+
if (isGestureActive && !remove) {
|
|
2133
|
+
gestureSubscriptions[name] = gestures[name].subscribe(element, {
|
|
2134
|
+
enable: setGesture(name, true),
|
|
2135
|
+
disable: setGesture(name, false),
|
|
2136
|
+
}, options);
|
|
2137
|
+
}
|
|
2138
|
+
else if (!isGestureActive && remove) {
|
|
2139
|
+
remove();
|
|
2140
|
+
delete gestureSubscriptions[name];
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
};
|
|
2144
|
+
const state = {
|
|
2145
|
+
update: (newOptions) => {
|
|
2146
|
+
if (!element)
|
|
2147
|
+
return;
|
|
2148
|
+
options = newOptions;
|
|
2149
|
+
updateGestureSubscriptions();
|
|
2150
|
+
scheduleAnimation(state);
|
|
2151
|
+
},
|
|
2152
|
+
setActive: (name, isActive) => {
|
|
2153
|
+
if (!element)
|
|
2154
|
+
return;
|
|
2155
|
+
activeStates[name] = isActive;
|
|
2156
|
+
scheduleAnimation(state);
|
|
2157
|
+
},
|
|
2158
|
+
animateUpdates,
|
|
2159
|
+
getDepth: () => depth,
|
|
2160
|
+
getTarget: () => target,
|
|
2161
|
+
getOptions: () => options,
|
|
2162
|
+
getContext: () => context,
|
|
2163
|
+
mount: (newElement) => {
|
|
2164
|
+
invariant(Boolean(newElement), "Animation state must be mounted with valid Element");
|
|
2165
|
+
element = newElement;
|
|
2166
|
+
mountedStates.set(element, state);
|
|
2167
|
+
updateGestureSubscriptions();
|
|
2168
|
+
return () => {
|
|
2169
|
+
mountedStates.delete(element);
|
|
2170
|
+
unscheduleAnimation(state);
|
|
2171
|
+
for (const key in gestureSubscriptions) {
|
|
2172
|
+
gestureSubscriptions[key]();
|
|
2173
|
+
}
|
|
2174
|
+
};
|
|
2175
|
+
},
|
|
2176
|
+
isMounted: () => Boolean(element),
|
|
2177
|
+
};
|
|
2178
|
+
return state;
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
function createStyles(keyframes) {
|
|
2182
|
+
const initialKeyframes = {};
|
|
2183
|
+
const transformKeys = [];
|
|
2184
|
+
for (let key in keyframes) {
|
|
2185
|
+
const value = keyframes[key];
|
|
2186
|
+
if (isTransform(key)) {
|
|
2187
|
+
if (transformAlias[key])
|
|
2188
|
+
key = transformAlias[key];
|
|
2189
|
+
transformKeys.push(key);
|
|
2190
|
+
key = asTransformCssVar(key);
|
|
2191
|
+
}
|
|
2192
|
+
let initialKeyframe = Array.isArray(value) ? value[0] : value;
|
|
2193
|
+
/**
|
|
2194
|
+
* If this is a number and we have a default value type, convert the number
|
|
2195
|
+
* to this type.
|
|
2196
|
+
*/
|
|
2197
|
+
const definition = transformDefinitions.get(key);
|
|
2198
|
+
if (definition) {
|
|
2199
|
+
initialKeyframe = isNumber(value)
|
|
2200
|
+
? definition.toDefaultUnit(value)
|
|
2201
|
+
: value;
|
|
2202
|
+
}
|
|
2203
|
+
initialKeyframes[key] = initialKeyframe;
|
|
2204
|
+
}
|
|
2205
|
+
if (transformKeys.length) {
|
|
2206
|
+
initialKeyframes.transform = buildTransformTemplate(transformKeys);
|
|
2207
|
+
}
|
|
2208
|
+
return initialKeyframes;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
const camelLetterToPipeLetter = (letter) => `-${letter.toLowerCase()}`;
|
|
2212
|
+
const camelToPipeCase = (str) => str.replace(/[A-Z]/g, camelLetterToPipeLetter);
|
|
2213
|
+
function createStyleString(target = {}) {
|
|
2214
|
+
const styles = createStyles(target);
|
|
2215
|
+
let style = "";
|
|
2216
|
+
for (const key in styles) {
|
|
2217
|
+
style += key.startsWith("--") ? key : camelToPipeCase(key);
|
|
2218
|
+
style += `: ${styles[key]}; `;
|
|
2219
|
+
}
|
|
2220
|
+
return style;
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
function animateProgress(target, options = {}) {
|
|
2224
|
+
return withControls([
|
|
1427
2225
|
() => {
|
|
1428
2226
|
const animation = new Animation(target, [0, 1], options);
|
|
1429
2227
|
animation.finished.catch(() => { });
|
|
1430
2228
|
return animation;
|
|
1431
2229
|
},
|
|
1432
|
-
], options
|
|
2230
|
+
], options, options.duration);
|
|
1433
2231
|
}
|
|
1434
2232
|
function animate(target, keyframesOrOptions, options) {
|
|
1435
|
-
const
|
|
1436
|
-
return
|
|
2233
|
+
const factory = typeof target === "function" ? animateProgress : animate$1;
|
|
2234
|
+
return factory(target, keyframesOrOptions, options);
|
|
1437
2235
|
}
|
|
1438
2236
|
|
|
1439
2237
|
exports.MotionValue = MotionValue;
|
|
2238
|
+
exports.ScrollOffset = ScrollOffset;
|
|
1440
2239
|
exports.animate = animate;
|
|
2240
|
+
exports.animateStyle = animateStyle;
|
|
2241
|
+
exports.createMotionState = createMotionState;
|
|
2242
|
+
exports.createStyleString = createStyleString;
|
|
2243
|
+
exports.createStyles = createStyles;
|
|
2244
|
+
exports.getAnimationData = getAnimationData;
|
|
2245
|
+
exports.getStyleName = getStyleName;
|
|
1441
2246
|
exports.glide = glide;
|
|
1442
|
-
exports.inView = inView;
|
|
2247
|
+
exports.inView = inView$1;
|
|
2248
|
+
exports.mountedStates = mountedStates;
|
|
2249
|
+
exports.resize = resize;
|
|
2250
|
+
exports.scroll = scroll;
|
|
1443
2251
|
exports.spring = spring;
|
|
1444
2252
|
exports.stagger = stagger;
|
|
1445
2253
|
exports.style = style;
|
|
1446
2254
|
exports.timeline = timeline;
|
|
2255
|
+
exports.withControls = withControls;
|
|
1447
2256
|
|
|
1448
2257
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1449
2258
|
|