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.
@@ -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 = defaults$1.easing, duration = defaults$1.duration, delay = defaults$1.delay, endDelay = defaults$1.endDelay, repeat = defaults$1.repeat, offset, direction = "normal", } = {}) {
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
- duration = custom.duration;
337
+ initialDuration = custom.duration;
333
338
  }
334
- const animationEasing = isEasingList(easing)
335
- ? noopReturn
336
- : getEasingFunction(easing);
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
- if (this.pauseTime)
344
- timestamp = this.pauseTime;
345
- let t = (timestamp - this.startTime) * this.rate;
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(animationEasing(p));
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.playState === "finished" || t >= totalDuration + endDelay;
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 - (this.pauseTime - ((_a = this.startTime) !== null && _a !== void 0 ? _a : 0));
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 = performance.now();
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 wrapAnimationWithControls = (animationFactory, duration = defaults$1.duration) => new Proxy({
748
- animations: animationFactory.map(createAnimation).filter(Boolean),
749
- duration,
750
- }, controls);
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
- let time = (activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation[key]) || 0;
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 () => target.animations.forEach((animation) => stopAnimation(animation));
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 wrapAnimationWithControls(animationFactories,
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 wrapAnimationWithControls(animationFactories,
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(elements, onStart, { root, margin: rootMargin, amount = "any" } = {}) {
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 resolvedElements = resolveElements(elements);
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
- resolvedElements.forEach((element) => observer.observe(element));
1446
+ elements.forEach((element) => observer.observe(element));
1422
1447
  return () => observer.disconnect();
1423
1448
  }
1424
1449
 
1425
- function animateProgress(target, options) {
1426
- return wrapAnimationWithControls([
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 === null || options === void 0 ? void 0 : options.duration);
2230
+ ], options, options.duration);
1433
2231
  }
1434
2232
  function animate(target, keyframesOrOptions, options) {
1435
- const animationFunction = typeof target === "function" ? animateProgress : animate$1;
1436
- return animationFunction(target, keyframesOrOptions, options);
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