motion 10.5.0 → 10.6.0-rc.3

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.
@@ -25,9 +25,62 @@
25
25
  index > -1 && arr.splice(index, 1);
26
26
  }
27
27
 
28
+ const clamp = (min, max, v) => Math.min(Math.max(v, min), max);
29
+
30
+ const defaults$1 = {
31
+ duration: 0.3,
32
+ delay: 0,
33
+ endDelay: 0,
34
+ repeat: 0,
35
+ easing: "ease",
36
+ };
37
+
38
+ const isNumber = (value) => typeof value === "number";
39
+ const isEasingGenerator = (easing) => typeof easing === "object" &&
40
+ Boolean(easing.createAnimation);
41
+ const isCubicBezier = (easing) => Array.isArray(easing) && isNumber(easing[0]);
42
+ const isEasingList = (easing) => Array.isArray(easing) && !isNumber(easing[0]);
43
+
44
+ const mix = (min, max, progress) => -progress * min + progress * max + min;
45
+
28
46
  const noop = () => { };
29
47
  const noopReturn = (v) => v;
30
48
 
49
+ const progress = (min, max, value) => max - min === 0 ? 1 : (value - min) / (max - min);
50
+
51
+ function fillOffset(offset, remaining) {
52
+ const min = offset[offset.length - 1];
53
+ for (let i = 1; i <= remaining; i++) {
54
+ const offsetProgress = progress(0, remaining, i);
55
+ offset.push(mix(min, 1, offsetProgress));
56
+ }
57
+ }
58
+ function defaultOffset(length) {
59
+ const offset = [0];
60
+ fillOffset(offset, length - 1);
61
+ return offset;
62
+ }
63
+
64
+ const time = {
65
+ ms: (seconds) => seconds * 1000,
66
+ s: (milliseconds) => milliseconds / 1000,
67
+ };
68
+
69
+ /*
70
+ Convert velocity into velocity per second
71
+
72
+ @param [number]: Unit per frame
73
+ @param [number]: Frame duration in ms
74
+ */
75
+ function velocityPerSecond(velocity, frameDuration) {
76
+ return frameDuration ? velocity * (1000 / frameDuration) : 0;
77
+ }
78
+
79
+ const wrap = (min, max, v) => {
80
+ const rangeSize = max - min;
81
+ return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
82
+ };
83
+
31
84
  /**
32
85
  * A list of all transformable axes. We'll use this list to generated a version
33
86
  * of each axes for each transform.
@@ -117,51 +170,6 @@
117
170
  catch (e) { }
118
171
  }
119
172
 
120
- const ms = (seconds) => seconds * 1000;
121
-
122
- const isNumber = (value) => typeof value === "number";
123
-
124
- const isCubicBezier = (easing) => Array.isArray(easing) && isNumber(easing[0]);
125
- const isEasingList = (easing) => Array.isArray(easing) && !isNumber(easing[0]);
126
- const isCustomEasing = (easing) => typeof easing === "object" &&
127
- Boolean(easing.createAnimation);
128
- const convertEasing = (easing) => isCubicBezier(easing) ? cubicBezierAsString(easing) : easing;
129
- const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
130
-
131
- const testAnimation = (keyframes) => document.createElement("div").animate(keyframes, { duration: 0.001 });
132
- const featureTests = {
133
- cssRegisterProperty: () => typeof CSS !== "undefined" &&
134
- Object.hasOwnProperty.call(CSS, "registerProperty"),
135
- waapi: () => Object.hasOwnProperty.call(Element.prototype, "animate"),
136
- partialKeyframes: () => {
137
- try {
138
- testAnimation({ opacity: [1] });
139
- }
140
- catch (e) {
141
- return false;
142
- }
143
- return true;
144
- },
145
- finished: () => Boolean(testAnimation({ opacity: [0, 1] }).finished),
146
- };
147
- const results = {};
148
- const supports = {};
149
- for (const key in featureTests) {
150
- supports[key] = () => {
151
- if (results[key] === undefined)
152
- results[key] = featureTests[key]();
153
- return results[key];
154
- };
155
- }
156
-
157
- const defaults = {
158
- duration: 0.3,
159
- delay: 0,
160
- endDelay: 0,
161
- repeat: 0,
162
- easing: "ease",
163
- };
164
-
165
173
  /*
166
174
  Bezier function generator
167
175
 
@@ -212,11 +220,11 @@
212
220
  return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
213
221
  }
214
222
 
215
- const clamp = (min, max, v) => Math.min(Math.max(v, min), max);
216
-
217
223
  const steps = (steps, direction = "end") => (progress) => {
218
224
  progress =
219
- direction === "end" ? Math.min(progress, 0.999) : Math.max(progress, 0.001);
225
+ direction === "end"
226
+ ? Math.min(progress, 0.999)
227
+ : Math.max(progress, 0.001);
220
228
  const expanded = progress * steps;
221
229
  const rounded = direction === "end" ? Math.floor(expanded) : Math.ceil(expanded);
222
230
  return clamp(0, 1, rounded / steps);
@@ -249,71 +257,14 @@
249
257
  }
250
258
  return noopReturn;
251
259
  }
252
-
253
- /*
254
- Value in range from progress
255
-
256
- Given a lower limit and an upper limit, we return the value within
257
- that range as expressed by progress (usually a number from 0 to 1)
258
-
259
- So progress = 0.5 would change
260
-
261
- from -------- to
262
-
263
- to
264
-
265
- from ---- to
266
-
267
- E.g. from = 10, to = 20, progress = 0.5 => 15
268
-
269
- @param [number]: Lower limit of range
270
- @param [number]: Upper limit of range
271
- @param [number]: The progress between lower and upper limits expressed 0-1
272
- @return [number]: Value as calculated from progress within range (not limited within range)
273
- */
274
- const mix = (from, to, progress) => -progress * from + progress * to + from;
275
-
276
- /*
277
- Progress within given range
278
-
279
- Given a lower limit and an upper limit, we return the progress
280
- (expressed as a number 0-1) represented by the given value.
281
-
282
- @param [number]: Lower limit
283
- @param [number]: Upper limit
284
- @param [number]: Value to find progress within given range
285
- @return [number]: Progress of value within range as expressed 0-1
286
- */
287
- const progress = (from, to, value) => {
288
- return to - from === 0 ? 1 : (value - from) / (to - from);
289
- };
290
-
291
- const wrap = (min, max, v) => {
292
- const rangeSize = max - min;
293
- return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
294
- };
295
-
296
260
  function getEasingForSegment(easing, i) {
297
261
  return isEasingList(easing)
298
262
  ? easing[wrap(0, easing.length, i)]
299
263
  : easing;
300
264
  }
301
265
 
302
- function fillOffset(offset, remaining) {
303
- const min = offset[offset.length - 1];
304
- for (let i = 1; i <= remaining; i++) {
305
- const offsetProgress = progress(0, remaining, i);
306
- offset.push(mix(min, 1, offsetProgress));
307
- }
308
- }
309
- function defaultOffset(length) {
310
- const offset = [0];
311
- fillOffset(offset, length - 1);
312
- return offset;
313
- }
314
-
315
266
  const clampProgress = (p) => Math.min(1, Math.max(p, 0));
316
- function slowInterpolateNumbers(output, input = defaultOffset(output.length), easing = noopReturn) {
267
+ function interpolate(output, input = defaultOffset(output.length), easing = noopReturn) {
317
268
  const length = output.length;
318
269
  /**
319
270
  * If the input length is lower than the output we
@@ -336,8 +287,8 @@
336
287
  };
337
288
  }
338
289
 
339
- class NumberAnimation {
340
- constructor(output, keyframes = [0, 1], { easing = defaults.easing, duration = defaults.duration, delay = defaults.delay, endDelay = defaults.endDelay, repeat = defaults.repeat, offset, direction = "normal", } = {}) {
290
+ class Animation {
291
+ 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", } = {}) {
341
292
  this.startTime = 0;
342
293
  this.rate = 1;
343
294
  this.t = 0;
@@ -349,13 +300,13 @@
349
300
  });
350
301
  const totalDuration = duration * (repeat + 1);
351
302
  /**
352
- * We don't currently support custom easing (spring, glide etc) in NumberAnimation
303
+ * We don't currently support custom easing (spring, glide etc) in Animation
353
304
  * (although this is completely possible), so this will have been hydrated by
354
305
  * animateStyle.
355
306
  */
356
- if (isCustomEasing(easing))
307
+ if (isEasingGenerator(easing))
357
308
  easing = "ease";
358
- const interpolate = slowInterpolateNumbers(keyframes, offset, isEasingList(easing)
309
+ const interpolate$1 = interpolate(keyframes, offset, isEasingList(easing)
359
310
  ? easing.map(getEasingFunction)
360
311
  : getEasingFunction(easing));
361
312
  this.tick = (timestamp) => {
@@ -363,6 +314,7 @@
363
314
  if (this.pauseTime)
364
315
  timestamp = this.pauseTime;
365
316
  let t = (timestamp - this.startTime) * this.rate;
317
+ console.log(timestamp, this.startTime, t);
366
318
  this.t = t;
367
319
  // Convert to seconds
368
320
  t /= 1000;
@@ -408,7 +360,7 @@
408
360
  (direction === "alternate-reverse" && !iterationIsOdd)) {
409
361
  iterationProgress = 1 - iterationProgress;
410
362
  }
411
- const latest = interpolate(t >= totalDuration ? 1 : Math.min(iterationProgress, 1));
363
+ const latest = interpolate$1(t >= totalDuration ? 1 : Math.min(iterationProgress, 1));
412
364
  output(latest);
413
365
  const isAnimationFinished = this.playState === "finished" || t >= totalDuration + endDelay;
414
366
  if (isAnimationFinished) {
@@ -416,7 +368,7 @@
416
368
  (_a = this.resolve) === null || _a === void 0 ? void 0 : _a.call(this, latest);
417
369
  }
418
370
  else if (this.playState !== "idle") {
419
- requestAnimationFrame(this.tick);
371
+ this.frameRequestId = requestAnimationFrame(this.tick);
420
372
  }
421
373
  };
422
374
  this.play();
@@ -444,8 +396,12 @@
444
396
  cancel() {
445
397
  var _a;
446
398
  this.playState = "idle";
399
+ console.log("cancelling with timestamp ", this.cancelTimestamp);
447
400
  this.tick(this.cancelTimestamp);
448
401
  (_a = this.reject) === null || _a === void 0 ? void 0 : _a.call(this, false);
402
+ if (this.frameRequestId !== undefined) {
403
+ cancelAnimationFrame(this.frameRequestId);
404
+ }
449
405
  }
450
406
  reverse() {
451
407
  this.rate *= -1;
@@ -472,6 +428,35 @@
472
428
  }
473
429
  }
474
430
 
431
+ const convertEasing = (easing) => isCubicBezier(easing) ? cubicBezierAsString(easing) : easing;
432
+ const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
433
+
434
+ const testAnimation = (keyframes) => document.createElement("div").animate(keyframes, { duration: 0.001 });
435
+ const featureTests = {
436
+ cssRegisterProperty: () => typeof CSS !== "undefined" &&
437
+ Object.hasOwnProperty.call(CSS, "registerProperty"),
438
+ waapi: () => Object.hasOwnProperty.call(Element.prototype, "animate"),
439
+ partialKeyframes: () => {
440
+ try {
441
+ testAnimation({ opacity: [1] });
442
+ }
443
+ catch (e) {
444
+ return false;
445
+ }
446
+ return true;
447
+ },
448
+ finished: () => Boolean(testAnimation({ opacity: [0, 1] }).finished),
449
+ };
450
+ const results = {};
451
+ const supports = {};
452
+ for (const key in featureTests) {
453
+ supports[key] = () => {
454
+ if (results[key] === undefined)
455
+ results[key] = featureTests[key]();
456
+ return results[key];
457
+ };
458
+ }
459
+
475
460
  function hydrateKeyframes(keyframes, readInitialValue) {
476
461
  for (let i = 0; i < keyframes.length; i++) {
477
462
  if (keyframes[i] === null) {
@@ -528,7 +513,7 @@
528
513
 
529
514
  function animateStyle(element, key, keyframesDefinition, options = {}) {
530
515
  let animation;
531
- let { duration = defaults.duration, delay = defaults.delay, endDelay = defaults.endDelay, repeat = defaults.repeat, easing = defaults.easing, direction, offset, allowWebkitAcceleration = false, } = options;
516
+ let { duration = defaults$1.duration, delay = defaults$1.delay, endDelay = defaults$1.endDelay, repeat = defaults$1.repeat, easing = defaults$1.easing, direction, offset, allowWebkitAcceleration = false, } = options;
532
517
  const data = getAnimationData(element);
533
518
  let canAnimateNatively = supports.waapi();
534
519
  const valueIsTransform = isTransform(key);
@@ -560,7 +545,7 @@
560
545
  * it from the DOM if it's the first keyframe.
561
546
  */
562
547
  let keyframes = hydrateKeyframes(keyframesList(keyframesDefinition), readInitialValue);
563
- if (isCustomEasing(easing)) {
548
+ if (isEasingGenerator(easing)) {
564
549
  const custom = easing.createAnimation(keyframes, readInitialValue, valueIsTransform, name, data);
565
550
  easing = custom.easing;
566
551
  if (custom.keyframes !== undefined)
@@ -601,9 +586,9 @@
601
586
  keyframes.unshift(readInitialValue());
602
587
  }
603
588
  const animationOptions = {
604
- delay: ms(delay),
605
- duration: ms(duration),
606
- endDelay: ms(endDelay),
589
+ delay: time.ms(delay),
590
+ duration: time.ms(duration),
591
+ endDelay: time.ms(endDelay),
607
592
  easing: !isEasingList(easing) ? convertEasing(easing) : undefined,
608
593
  direction,
609
594
  iterations: repeat + 1,
@@ -661,7 +646,7 @@
661
646
  latest = definition.toDefaultUnit(latest);
662
647
  style.set(element, name, latest);
663
648
  };
664
- animation = new NumberAnimation(render, keyframes, Object.assign(Object.assign({}, options), { duration,
649
+ animation = new Animation(render, keyframes, Object.assign(Object.assign({}, options), { duration,
665
650
  easing }));
666
651
  }
667
652
  else {
@@ -709,7 +694,7 @@
709
694
  }
710
695
 
711
696
  const createAnimation = (factory) => factory();
712
- const createAnimations = (animationFactory, duration) => new Proxy({
697
+ const wrapAnimationWithControls = (animationFactory, duration = defaults$1.duration) => new Proxy({
713
698
  animations: animationFactory.map(createAnimation).filter(Boolean),
714
699
  duration,
715
700
  }, controls);
@@ -744,7 +729,7 @@
744
729
  set: (target, key, value) => {
745
730
  switch (key) {
746
731
  case "currentTime":
747
- value = ms(value);
732
+ value = time.ms(value);
748
733
  case "currentTime":
749
734
  case "playbackRate":
750
735
  for (let i = 0; i < target.animations.length; i++) {
@@ -785,8 +770,7 @@
785
770
  : option;
786
771
  }
787
772
 
788
- function animate(elements, keyframes, options = {}) {
789
- var _a;
773
+ function animate$1(elements, keyframes, options = {}) {
790
774
  elements = resolveElements(elements);
791
775
  const numElements = elements.length;
792
776
  /**
@@ -802,7 +786,7 @@
802
786
  animationFactories.push(animation);
803
787
  }
804
788
  }
805
- return createAnimations(animationFactories,
789
+ return wrapAnimationWithControls(animationFactories,
806
790
  /**
807
791
  * TODO:
808
792
  * If easing is set to spring or glide, duration will be dynamically
@@ -812,7 +796,7 @@
812
796
  * to Proxy animations returned from animateStyle that has duration
813
797
  * as a getter.
814
798
  */
815
- (_a = options.duration) !== null && _a !== void 0 ? _a : defaults.duration);
799
+ options.duration);
816
800
  }
817
801
 
818
802
  /*! *****************************************************************************
@@ -903,7 +887,7 @@
903
887
  }
904
888
 
905
889
  function timeline(definition, options = {}) {
906
- var _a, _b;
890
+ var _a;
907
891
  const animationDefinitions = createAnimationsFromTimeline(definition, options);
908
892
  /**
909
893
  * Create and start animations
@@ -911,9 +895,9 @@
911
895
  const animationFactories = animationDefinitions
912
896
  .map((definition) => animateStyle(...definition))
913
897
  .filter(Boolean);
914
- return createAnimations(animationFactories,
898
+ return wrapAnimationWithControls(animationFactories,
915
899
  // Get the duration from the first animation definition
916
- (_b = (_a = animationDefinitions[0]) === null || _a === void 0 ? void 0 : _a[3].duration) !== null && _b !== void 0 ? _b : defaults.duration);
900
+ (_a = animationDefinitions[0]) === null || _a === void 0 ? void 0 : _a[3].duration);
917
901
  }
918
902
  function createAnimationsFromTimeline(definition, _a = {}) {
919
903
  var { defaultOptions = {} } = _a, timelineOptions = __rest(_a, ["defaultOptions"]);
@@ -956,8 +940,8 @@
956
940
  const valueSequence = getValueSequence(key, elementSequence);
957
941
  let valueKeyframes = keyframesList(keyframes[key]);
958
942
  const valueOptions = getOptions(options, key);
959
- let { duration = defaultOptions.duration || defaults.duration, easing = defaultOptions.easing || defaults.easing, } = valueOptions;
960
- if (isCustomEasing(easing)) {
943
+ let { duration = defaultOptions.duration || defaults$1.duration, easing = defaultOptions.easing || defaults$1.easing, } = valueOptions;
944
+ if (isEasingGenerator(easing)) {
961
945
  const valueIsTransform = isTransform(key);
962
946
  invariant(valueKeyframes.length === 2 || !valueIsTransform, "spring must be provided 2 keyframes within timeline");
963
947
  const custom = easing.createAnimation(valueKeyframes,
@@ -1028,7 +1012,7 @@
1028
1012
  const { at, value, easing } = valueSequence[i];
1029
1013
  keyframes.push(value);
1030
1014
  valueOffset.push(progress(0, totalDuration, at));
1031
- valueEasing.push(easing || defaults.easing);
1015
+ valueEasing.push(easing || defaults$1.easing);
1032
1016
  }
1033
1017
  /**
1034
1018
  * If the first keyframe doesn't land on offset: 0
@@ -1069,34 +1053,34 @@
1069
1053
  return sequences[name];
1070
1054
  }
1071
1055
 
1072
- /*
1073
- Convert velocity into velocity per second
1074
-
1075
- @param [number]: Unit per frame
1076
- @param [number]: Frame duration in ms
1077
- */
1078
- function velocityPerSecond(velocity, frameDuration) {
1079
- return frameDuration ? velocity * (1000 / frameDuration) : 0;
1056
+ const sampleT = 5; // ms
1057
+ function calcGeneratorVelocity(resolveValue, t, current) {
1058
+ const prevT = Math.max(t - sampleT, 0);
1059
+ return velocityPerSecond(current - resolveValue(prevT), 5);
1080
1060
  }
1081
1061
 
1062
+ const defaults = {
1063
+ stiffness: 100.0,
1064
+ damping: 10.0,
1065
+ mass: 1.0,
1066
+ };
1067
+
1068
+ const calcDampingRatio = (stiffness = defaults.stiffness, damping = defaults.damping, mass = defaults.mass) => damping / (2 * Math.sqrt(stiffness * mass));
1069
+ const calcAngularFreq = (undampedFreq, dampingRatio) => undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
1070
+
1082
1071
  function hasReachedTarget(origin, target, current) {
1083
1072
  return ((origin < target && current >= target) ||
1084
1073
  (origin > target && current <= target));
1085
1074
  }
1086
1075
 
1087
- const defaultStiffness = 100.0;
1088
- const defaultDamping = 10.0;
1089
- const defaultMass = 1.0;
1090
- const calcDampingRatio = (stiffness = defaultStiffness, damping = defaultDamping, mass = defaultMass) => damping / (2 * Math.sqrt(stiffness * mass));
1091
- const calcAngularFreq = (undampedFreq, dampingRatio) => undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
1092
- const createSpringGenerator = ({ stiffness = defaultStiffness, damping = defaultDamping, mass = defaultMass, from = 0, to = 1, velocity = 0.0, restSpeed = 2, restDistance = 0.5, } = {}) => {
1093
- velocity = velocity ? velocity / 1000 : 0.0;
1076
+ const spring$1 = ({ stiffness = defaults.stiffness, damping = defaults.damping, mass = defaults.mass, from = 0, to = 1, velocity = 0.0, restSpeed = 2, restDistance = 0.5, } = {}) => {
1077
+ velocity = velocity ? time.s(velocity) : 0.0;
1094
1078
  const state = {
1095
1079
  done: false,
1096
- value: from,
1080
+ hasReachedTarget: false,
1081
+ current: from,
1097
1082
  target: to,
1098
1083
  velocity,
1099
- hasReachedTarget: false,
1100
1084
  };
1101
1085
  const dampingRatio = calcDampingRatio(stiffness, damping, mass);
1102
1086
  const initialDelta = to - from;
@@ -1118,35 +1102,119 @@
1118
1102
  Math.exp(-undampedAngularFreq * t) *
1119
1103
  (initialDelta + (velocity + undampedAngularFreq * initialDelta) * t);
1120
1104
  }
1121
- return {
1122
- next: (t) => {
1123
- state.value = resolveSpring(t);
1124
- state.velocity =
1125
- t === 0 ? velocity : calcVelocity(resolveSpring, t, state.value);
1126
- const isBelowVelocityThreshold = Math.abs(state.velocity) <= restSpeed;
1127
- const isBelowDisplacementThreshold = Math.abs(to - state.value) <= restDistance;
1128
- state.done = isBelowVelocityThreshold && isBelowDisplacementThreshold;
1129
- state.hasReachedTarget = hasReachedTarget(from, to, state.value);
1105
+ return (t) => {
1106
+ state.current = resolveSpring(t);
1107
+ state.velocity =
1108
+ t === 0
1109
+ ? velocity
1110
+ : calcGeneratorVelocity(resolveSpring, t, state.current);
1111
+ const isBelowVelocityThreshold = Math.abs(state.velocity) <= restSpeed;
1112
+ const isBelowDisplacementThreshold = Math.abs(to - state.current) <= restDistance;
1113
+ state.done = isBelowVelocityThreshold && isBelowDisplacementThreshold;
1114
+ state.hasReachedTarget = hasReachedTarget(from, to, state.current);
1115
+ return state;
1116
+ };
1117
+ };
1118
+
1119
+ const glide$1 = ({ from = 0, velocity = 0.0, power = 0.8, decay = 0.325, bounceDamping, bounceStiffness, changeTarget, min, max, restDistance = 0.5, restSpeed, }) => {
1120
+ decay = time.ms(decay);
1121
+ const state = {
1122
+ hasReachedTarget: false,
1123
+ done: false,
1124
+ current: from,
1125
+ target: from,
1126
+ velocity,
1127
+ };
1128
+ const isOutOfBounds = (v) => (min !== undefined && v < min) || (max !== undefined && v > max);
1129
+ const nearestBoundary = (v) => {
1130
+ if (min === undefined)
1131
+ return max;
1132
+ if (max === undefined)
1133
+ return min;
1134
+ return Math.abs(min - v) < Math.abs(max - v) ? min : max;
1135
+ };
1136
+ let amplitude = power * velocity;
1137
+ const ideal = from + amplitude;
1138
+ const target = changeTarget === undefined ? ideal : changeTarget(ideal);
1139
+ state.target = target;
1140
+ /**
1141
+ * If the target has changed we need to re-calculate the amplitude, otherwise
1142
+ * the animation will start from the wrong position.
1143
+ */
1144
+ if (target !== ideal)
1145
+ amplitude = target - from;
1146
+ const calcDelta = (t) => -amplitude * Math.exp(-t / decay);
1147
+ const calcLatest = (t) => target + calcDelta(t);
1148
+ const applyFriction = (t) => {
1149
+ const delta = calcDelta(t);
1150
+ const latest = calcLatest(t);
1151
+ state.done = Math.abs(delta) <= restDistance;
1152
+ state.current = state.done ? target : latest;
1153
+ state.velocity =
1154
+ t === 0 ? velocity : calcGeneratorVelocity(calcLatest, t, state.current);
1155
+ };
1156
+ /**
1157
+ * Ideally this would resolve for t in a stateless way, we could
1158
+ * do that by always precalculating the animation but as we know
1159
+ * this will be done anyway we can assume that spring will
1160
+ * be discovered during that.
1161
+ */
1162
+ let timeReachedBoundary;
1163
+ let spring$1$1;
1164
+ const checkCatchBoundary = (t) => {
1165
+ if (!isOutOfBounds(state.current))
1166
+ return;
1167
+ timeReachedBoundary = t;
1168
+ spring$1$1 = spring$1({
1169
+ from: state.current,
1170
+ to: nearestBoundary(state.current),
1171
+ velocity: state.velocity,
1172
+ damping: bounceDamping,
1173
+ stiffness: bounceStiffness,
1174
+ restDistance,
1175
+ restSpeed,
1176
+ });
1177
+ };
1178
+ checkCatchBoundary(0);
1179
+ return (t) => {
1180
+ /**
1181
+ * We need to resolve the friction to figure out if we need a
1182
+ * spring but we don't want to do this twice per frame. So here
1183
+ * we flag if we updated for this frame and later if we did
1184
+ * we can skip doing it again.
1185
+ */
1186
+ let hasUpdatedFrame = false;
1187
+ if (!spring$1$1 && timeReachedBoundary === undefined) {
1188
+ hasUpdatedFrame = true;
1189
+ applyFriction(t);
1190
+ checkCatchBoundary(t);
1191
+ }
1192
+ /**
1193
+ * If we have a spring and the provided t is beyond the moment the friction
1194
+ * animation crossed the min/max boundary, use the spring.
1195
+ */
1196
+ if (timeReachedBoundary !== undefined && t > timeReachedBoundary) {
1197
+ state.hasReachedTarget = true;
1198
+ return spring$1$1(t - timeReachedBoundary);
1199
+ }
1200
+ else {
1201
+ state.hasReachedTarget = false;
1202
+ !hasUpdatedFrame && applyFriction(t);
1130
1203
  return state;
1131
- },
1204
+ }
1132
1205
  };
1133
1206
  };
1134
- const sampleT = 5; // ms
1135
- function calcVelocity(resolveValue, t, current) {
1136
- const prevT = Math.max(t - sampleT, 0);
1137
- return velocityPerSecond(current - resolveValue(prevT), 5);
1138
- }
1139
1207
 
1140
1208
  const timeStep = 10;
1141
1209
  const maxDuration = 10000;
1142
1210
  function pregenerateKeyframes(generator) {
1143
1211
  let overshootDuration = undefined;
1144
1212
  let timestamp = timeStep;
1145
- let state = generator.next(0);
1146
- const keyframes = [state.value];
1213
+ let state = generator(0);
1214
+ const keyframes = [state.current];
1147
1215
  while (!state.done && timestamp < maxDuration) {
1148
- state = generator.next(timestamp);
1149
- keyframes.push(state.done ? state.target : state.value);
1216
+ state = generator(timestamp);
1217
+ keyframes.push(state.done ? state.target : state.current);
1150
1218
  if (overshootDuration === undefined && state.hasReachedTarget) {
1151
1219
  overshootDuration = timestamp;
1152
1220
  }
@@ -1158,7 +1226,7 @@
1158
1226
  * generate a second keyframe so we have an origin and target.
1159
1227
  */
1160
1228
  if (keyframes.length === 1)
1161
- keyframes.push(state.value);
1229
+ keyframes.push(state.current);
1162
1230
  return {
1163
1231
  keyframes,
1164
1232
  duration: duration / 1000,
@@ -1204,7 +1272,7 @@
1204
1272
  const unresolvedOrigin = numKeyframes === 1 ? null : keyframes[0];
1205
1273
  const origin = unresolvedOrigin === null
1206
1274
  ? prevMotionState
1207
- ? prevMotionState.value
1275
+ ? prevMotionState.current
1208
1276
  : parseFloat(getOrigin())
1209
1277
  : unresolvedOrigin;
1210
1278
  generator = getGenerator(origin, target, velocity, name === null || name === void 0 ? void 0 : name.includes("scale"));
@@ -1220,7 +1288,7 @@
1220
1288
  };
1221
1289
  }
1222
1290
  // TODO Add test for this
1223
- if (generator && data && name) {
1291
+ if (data && name) {
1224
1292
  data.generators[name] = generator;
1225
1293
  }
1226
1294
  return settings;
@@ -1230,466 +1298,26 @@
1230
1298
  }
1231
1299
  const isNumberOrNull = (value) => typeof value !== "string";
1232
1300
 
1233
- const spring = createGeneratorEasing(createSpringGenerator);
1234
-
1235
- const createGlideGenerator = ({ from = 0, velocity = 0.0, power = 0.8, decay = 0.325, bounceDamping, bounceStiffness, changeTarget, min, max, restDistance = 0.5, restSpeed, }) => {
1236
- decay = ms(decay);
1237
- const state = {
1238
- value: from,
1239
- target: from,
1240
- velocity,
1241
- hasReachedTarget: false,
1242
- done: false,
1243
- };
1244
- const isOutOfBounds = (v) => (min !== undefined && v < min) || (max !== undefined && v > max);
1245
- const nearestBoundary = (v) => {
1246
- if (min === undefined)
1247
- return max;
1248
- if (max === undefined)
1249
- return min;
1250
- return Math.abs(min - v) < Math.abs(max - v) ? min : max;
1251
- };
1252
- let amplitude = power * velocity;
1253
- const ideal = from + amplitude;
1254
- const target = changeTarget === undefined ? ideal : changeTarget(ideal);
1255
- state.target = target;
1256
- /**
1257
- * If the target has changed we need to re-calculate the amplitude, otherwise
1258
- * the animation will start from the wrong position.
1259
- */
1260
- if (target !== ideal)
1261
- amplitude = target - from;
1262
- const calcDelta = (t) => -amplitude * Math.exp(-t / decay);
1263
- const calcLatest = (t) => target + calcDelta(t);
1264
- const applyFriction = (t) => {
1265
- const delta = calcDelta(t);
1266
- const latest = calcLatest(t);
1267
- state.done = Math.abs(delta) <= restDistance;
1268
- state.value = state.done ? target : latest;
1269
- state.velocity =
1270
- t === 0 ? velocity : calcVelocity(calcLatest, t, state.value);
1271
- };
1272
- /**
1273
- * Ideally this would resolve for t in a stateless way, we could
1274
- * do that by always precalculating the animation but as we know
1275
- * this will be done anyway we can assume that spring will
1276
- * be discovered during that.
1277
- */
1278
- let timeReachedBoundary;
1279
- let spring;
1280
- const checkCatchBoundary = (t) => {
1281
- if (!isOutOfBounds(state.value))
1282
- return;
1283
- timeReachedBoundary = t;
1284
- spring = createSpringGenerator({
1285
- from: state.value,
1286
- to: nearestBoundary(state.value),
1287
- velocity: state.velocity,
1288
- damping: bounceDamping,
1289
- stiffness: bounceStiffness,
1290
- restDistance,
1291
- restSpeed,
1292
- });
1293
- };
1294
- checkCatchBoundary(0);
1295
- return {
1296
- next: (t) => {
1297
- /**
1298
- * We need to resolve the friction to figure out if we need a
1299
- * spring but we don't want to do this twice per frame. So here
1300
- * we flag if we updated for this frame and later if we did
1301
- * we can skip doing it again.
1302
- */
1303
- let hasUpdatedFrame = false;
1304
- if (!spring && timeReachedBoundary === undefined) {
1305
- hasUpdatedFrame = true;
1306
- applyFriction(t);
1307
- checkCatchBoundary(t);
1308
- }
1309
- /**
1310
- * If we have a spring and the provided t is beyond the moment the friction
1311
- * animation crossed the min/max boundary, use the spring.
1312
- */
1313
- if (timeReachedBoundary !== undefined && t > timeReachedBoundary) {
1314
- state.hasReachedTarget = true;
1315
- return spring.next(t - timeReachedBoundary);
1316
- }
1317
- else {
1318
- state.hasReachedTarget = false;
1319
- !hasUpdatedFrame && applyFriction(t);
1320
- return state;
1321
- }
1322
- },
1323
- };
1324
- };
1301
+ const spring = createGeneratorEasing(spring$1);
1325
1302
 
1326
- const glide = createGeneratorEasing(createGlideGenerator);
1303
+ const glide = createGeneratorEasing(glide$1);
1327
1304
 
1328
- function hasChanged(a, b) {
1329
- if (typeof a !== typeof b)
1330
- return true;
1331
- if (Array.isArray(a) && Array.isArray(b))
1332
- return !shallowCompare(a, b);
1333
- return a !== b;
1334
- }
1335
- function shallowCompare(next, prev) {
1336
- const prevLength = prev.length;
1337
- if (prevLength !== next.length)
1338
- return false;
1339
- for (let i = 0; i < prevLength; i++) {
1340
- if (prev[i] !== next[i])
1341
- return false;
1342
- }
1343
- return true;
1344
- }
1345
-
1346
- function isVariant(definition) {
1347
- return typeof definition === "object";
1348
- }
1349
-
1350
- function resolveVariant(definition, variants) {
1351
- if (isVariant(definition)) {
1352
- return definition;
1353
- }
1354
- else if (definition && variants) {
1355
- return variants[definition];
1356
- }
1357
- }
1358
-
1359
- let scheduled = undefined;
1360
- function processScheduledAnimations() {
1361
- if (!scheduled)
1362
- return;
1363
- const generators = scheduled.sort(compareByDepth).map(fireAnimateUpdates);
1364
- generators.forEach(fireNext);
1365
- generators.forEach(fireNext);
1366
- scheduled = undefined;
1367
- }
1368
- function scheduleAnimation(state) {
1369
- if (!scheduled) {
1370
- scheduled = [state];
1371
- requestAnimationFrame(processScheduledAnimations);
1372
- }
1373
- else {
1374
- addUniqueItem(scheduled, state);
1375
- }
1376
- }
1377
- function unscheduleAnimation(state) {
1378
- scheduled && removeItem(scheduled, state);
1379
- }
1380
- const compareByDepth = (a, b) => a.getDepth() - b.getDepth();
1381
- const fireAnimateUpdates = (state) => state.animateUpdates();
1382
- const fireNext = (iterator) => iterator.next();
1383
-
1384
- const motionEvent = (name, target) => new CustomEvent(name, { detail: { target } });
1385
- function dispatchPointerEvent(element, name, event) {
1386
- element.dispatchEvent(new CustomEvent(name, { detail: { originalEvent: event } }));
1387
- }
1388
- function dispatchViewEvent(element, name, entry) {
1389
- element.dispatchEvent(new CustomEvent(name, { detail: { originalEntry: entry } }));
1390
- }
1391
-
1392
- /**
1393
- * TODO: Support viewport options
1394
- */
1395
- const inView = {
1396
- isActive: (options) => Boolean(options.inView),
1397
- subscribe: (element, { enable, disable }) => {
1398
- let isVisible = false;
1399
- if (typeof IntersectionObserver !== "undefined") {
1400
- const observer = new IntersectionObserver(([entry]) => {
1401
- if (!isVisible && entry.isIntersecting) {
1402
- enable();
1403
- dispatchViewEvent(element, "viewenter", entry);
1404
- }
1405
- else if (isVisible && !entry.isIntersecting) {
1406
- disable();
1407
- dispatchViewEvent(element, "viewleave", entry);
1408
- }
1409
- isVisible = entry.isIntersecting;
1410
- });
1411
- observer.observe(element);
1412
- return () => {
1413
- observer.unobserve(element);
1414
- observer.disconnect();
1415
- };
1416
- }
1417
- else {
1418
- enable();
1419
- return () => { };
1420
- }
1421
- },
1422
- };
1423
-
1424
- const mouseEvent = (element, name, action) => (event) => {
1425
- if (event.pointerType && event.pointerType !== "mouse")
1426
- return;
1427
- action();
1428
- dispatchPointerEvent(element, name, event);
1429
- };
1430
- const hover = {
1431
- isActive: (options) => Boolean(options.hover),
1432
- subscribe: (element, { enable, disable }) => {
1433
- const onEnter = mouseEvent(element, "hoverstart", enable);
1434
- const onLeave = mouseEvent(element, "hoverend", disable);
1435
- element.addEventListener("pointerenter", onEnter);
1436
- element.addEventListener("pointerleave", onLeave);
1437
- return () => {
1438
- element.removeEventListener("pointerenter", onEnter);
1439
- element.removeEventListener("pointerleave", onLeave);
1440
- };
1441
- },
1442
- };
1443
-
1444
- const press = {
1445
- isActive: (options) => Boolean(options.press),
1446
- subscribe: (element, { enable, disable }) => {
1447
- const onPointerUp = (event) => {
1448
- disable();
1449
- dispatchPointerEvent(element, "pressend", event);
1450
- window.removeEventListener("pointerup", onPointerUp);
1451
- };
1452
- const onPointerDown = (event) => {
1453
- enable();
1454
- dispatchPointerEvent(element, "pressstart", event);
1455
- window.addEventListener("pointerup", onPointerUp);
1456
- };
1457
- element.addEventListener("pointerdown", onPointerDown);
1458
- return () => {
1459
- element.removeEventListener("pointerdown", onPointerDown);
1460
- window.removeEventListener("pointerup", onPointerUp);
1461
- };
1462
- },
1463
- };
1464
-
1465
- const gestures = { inView, hover, press };
1466
- /**
1467
- * A list of state types, in priority order. If a value is defined in
1468
- * a righter-most type, it will override any definition in a lefter-most.
1469
- */
1470
- const stateTypes = ["initial", "animate", ...Object.keys(gestures), "exit"];
1471
- /**
1472
- * A global store of all generated motion states. This can be used to lookup
1473
- * a motion state for a given Element.
1474
- */
1475
- const mountedStates = new WeakMap();
1476
- function createMotionState(options = {}, parent) {
1477
- /**
1478
- * The element represented by the motion state. This is an empty reference
1479
- * when we create the state to support SSR and allow for later mounting
1480
- * in view libraries.
1481
- *
1482
- * @ts-ignore
1483
- */
1484
- let element;
1485
- /**
1486
- * Calculate a depth that we can use to order motion states by tree depth.
1487
- */
1488
- let depth = parent ? parent.getDepth() + 1 : 0;
1489
- /**
1490
- * Track which states are currently active.
1491
- */
1492
- const activeStates = { initial: true, animate: true };
1493
- /**
1494
- * A map of functions that, when called, will remove event listeners for
1495
- * a given gesture.
1496
- */
1497
- const gestureSubscriptions = {};
1498
- /**
1499
- * Initialise a context to share through motion states. This
1500
- * will be populated by variant names (if any).
1501
- */
1502
- const context = {};
1503
- for (const name of stateTypes) {
1504
- context[name] =
1505
- typeof options[name] === "string"
1506
- ? options[name]
1507
- : parent === null || parent === void 0 ? void 0 : parent.getContext()[name];
1508
- }
1509
- /**
1510
- * If initial is set to false we use the animate prop as the initial
1511
- * animation state.
1512
- */
1513
- const initialVariantSource = options.initial === false ? "animate" : "initial";
1514
- /**
1515
- * Destructure an initial target out from the resolved initial variant.
1516
- */
1517
- let _a = resolveVariant(options[initialVariantSource] || context[initialVariantSource], options.variants) || {}, target = __rest(_a, ["transition"]);
1518
- /**
1519
- * The base target is a cached map of values that we'll use to animate
1520
- * back to if a value is removed from all active state types. This
1521
- * is usually the initial value as read from the DOM, for instance if
1522
- * it hasn't been defined in initial.
1523
- */
1524
- const baseTarget = Object.assign({}, target);
1525
- /**
1526
- * A generator that will be processed by the global animation scheduler.
1527
- * This yeilds when it switches from reading the DOM to writing to it
1528
- * to prevent layout thrashing.
1529
- */
1530
- function* animateUpdates() {
1531
- var _a, _b;
1532
- const prevTarget = target;
1533
- target = {};
1534
- const resolvedVariants = {};
1535
- const enteringInto = {};
1536
- const animationOptions = {};
1537
- for (const name of stateTypes) {
1538
- if (!activeStates[name])
1539
- continue;
1540
- const variant = resolveVariant(options[name]);
1541
- if (!variant)
1542
- continue;
1543
- resolvedVariants[name] = variant;
1544
- for (const key in variant) {
1545
- if (key === "transition")
1546
- continue;
1547
- target[key] = variant[key];
1548
- animationOptions[key] = getOptions((_b = (_a = variant.transition) !== null && _a !== void 0 ? _a : options.transition) !== null && _b !== void 0 ? _b : {}, key);
1549
- /**
1550
- * Mark which state type this value is animating into.
1551
- */
1552
- enteringInto[key] = name;
1553
- }
1554
- }
1555
- const allTargetKeys = new Set([
1556
- ...Object.keys(target),
1557
- ...Object.keys(prevTarget),
1558
- ]);
1559
- const animationFactories = [];
1560
- allTargetKeys.forEach((key) => {
1561
- var _a;
1562
- if (target[key] === undefined) {
1563
- target[key] = baseTarget[key];
1564
- }
1565
- if (hasChanged(prevTarget[key], target[key])) {
1566
- (_a = baseTarget[key]) !== null && _a !== void 0 ? _a : (baseTarget[key] = style.get(element, key));
1567
- animationFactories.push(animateStyle(element, key, target[key], animationOptions[key]));
1568
- }
1569
- });
1570
- // Wait for all animation states to read from the DOM
1571
- yield;
1572
- const animations = animationFactories
1573
- .map((factory) => factory())
1574
- .filter(Boolean);
1575
- if (!animations.length)
1576
- return;
1577
- const animationTarget = target;
1578
- element.dispatchEvent(motionEvent("motionstart", animationTarget));
1579
- Promise.all(animations.map((animation) => animation.finished))
1580
- .then(() => {
1581
- element.dispatchEvent(motionEvent("motioncomplete", animationTarget));
1582
- })
1583
- .catch(noop);
1584
- }
1585
- const setGesture = (name, isActive) => () => {
1586
- activeStates[name] = isActive;
1587
- scheduleAnimation(state);
1588
- };
1589
- const updateGestureSubscriptions = () => {
1590
- for (const name in gestures) {
1591
- const isGestureActive = gestures[name].isActive(options);
1592
- const remove = gestureSubscriptions[name];
1593
- if (isGestureActive && !remove) {
1594
- gestureSubscriptions[name] = gestures[name].subscribe(element, {
1595
- enable: setGesture(name, true),
1596
- disable: setGesture(name, false),
1597
- });
1598
- }
1599
- else if (!isGestureActive && remove) {
1600
- remove();
1601
- delete gestureSubscriptions[name];
1602
- }
1603
- }
1604
- };
1605
- const state = {
1606
- update: (newOptions) => {
1607
- if (!element)
1608
- return;
1609
- options = newOptions;
1610
- updateGestureSubscriptions();
1611
- scheduleAnimation(state);
1305
+ function animateProgress(target, options) {
1306
+ return wrapAnimationWithControls([
1307
+ () => {
1308
+ const animation = new Animation(target, [0, 1], options);
1309
+ animation.finished.catch(() => { });
1310
+ return animation;
1612
1311
  },
1613
- setActive: (name, isActive) => {
1614
- if (!element)
1615
- return;
1616
- activeStates[name] = isActive;
1617
- scheduleAnimation(state);
1618
- },
1619
- animateUpdates,
1620
- getDepth: () => depth,
1621
- getTarget: () => target,
1622
- getOptions: () => options,
1623
- getContext: () => context,
1624
- mount: (newElement) => {
1625
- invariant(Boolean(newElement), "Animation state must be mounted with valid Element");
1626
- element = newElement;
1627
- mountedStates.set(element, state);
1628
- updateGestureSubscriptions();
1629
- return () => {
1630
- mountedStates.delete(element);
1631
- unscheduleAnimation(state);
1632
- for (const key in gestureSubscriptions) {
1633
- gestureSubscriptions[key]();
1634
- }
1635
- };
1636
- },
1637
- isMounted: () => Boolean(element),
1638
- };
1639
- return state;
1640
- }
1641
-
1642
- function createStyles(keyframes) {
1643
- const initialKeyframes = {};
1644
- const transformKeys = [];
1645
- for (let key in keyframes) {
1646
- const value = keyframes[key];
1647
- if (isTransform(key)) {
1648
- if (transformAlias[key])
1649
- key = transformAlias[key];
1650
- transformKeys.push(key);
1651
- key = asTransformCssVar(key);
1652
- }
1653
- let initialKeyframe = Array.isArray(value) ? value[0] : value;
1654
- /**
1655
- * If this is a number and we have a default value type, convert the number
1656
- * to this type.
1657
- */
1658
- const definition = transformDefinitions.get(key);
1659
- if (definition) {
1660
- initialKeyframe = isNumber(value)
1661
- ? definition.toDefaultUnit(value)
1662
- : value;
1663
- }
1664
- initialKeyframes[key] = initialKeyframe;
1665
- }
1666
- if (transformKeys.length) {
1667
- initialKeyframes.transform = buildTransformTemplate(transformKeys);
1668
- }
1669
- return initialKeyframes;
1312
+ ], options === null || options === void 0 ? void 0 : options.duration);
1670
1313
  }
1671
-
1672
- const camelLetterToPipeLetter = (letter) => `-${letter.toLowerCase()}`;
1673
- const camelToPipeCase = (str) => str.replace(/[A-Z]/g, camelLetterToPipeLetter);
1674
- function createStyleString(target = {}) {
1675
- const styles = createStyles(target);
1676
- let style = "";
1677
- for (const key in styles) {
1678
- style += key.startsWith("--") ? key : camelToPipeCase(key);
1679
- style += `: ${styles[key]}; `;
1680
- }
1681
- return style;
1314
+ function animate(target, keyframesOrOptions, options) {
1315
+ const animationFunction = typeof target === "function" ? animateProgress : animate$1;
1316
+ return animationFunction(target, keyframesOrOptions, options);
1682
1317
  }
1683
1318
 
1684
1319
  exports.animate = animate;
1685
- exports.animateStyle = animateStyle;
1686
- exports.createMotionState = createMotionState;
1687
- exports.createStyleString = createStyleString;
1688
- exports.createStyles = createStyles;
1689
- exports.getAnimationData = getAnimationData;
1690
- exports.getStyleName = getStyleName;
1691
1320
  exports.glide = glide;
1692
- exports.mountedStates = mountedStates;
1693
1321
  exports.spring = spring;
1694
1322
  exports.stagger = stagger;
1695
1323
  exports.style = style;