motion 10.2.1 → 10.3.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +1 -0
  3. package/dist/main.cjs.js +2 -0
  4. package/dist/main.es.js +1 -0
  5. package/dist/motion.min.js +1 -1
  6. package/dist/motion.umd.js +426 -280
  7. package/dist/size-animate-dom.js +1 -1
  8. package/dist/size-animate-style.js +1 -1
  9. package/dist/size-react.js +1 -1
  10. package/dist/size-spring.js +1 -1
  11. package/dist/size-timeline-dom.js +1 -1
  12. package/dist/size-webpack-animate.js +1 -1
  13. package/dist/targets/dom/animate-style.cjs.js +135 -134
  14. package/dist/targets/dom/animate-style.es.js +137 -136
  15. package/dist/targets/dom/animate.cjs.js +15 -4
  16. package/dist/targets/dom/animate.es.js +16 -5
  17. package/dist/targets/dom/data.cjs.js +4 -3
  18. package/dist/targets/dom/data.es.js +4 -3
  19. package/dist/targets/dom/style.cjs.js +1 -1
  20. package/dist/targets/dom/style.es.js +2 -2
  21. package/dist/targets/dom/timeline/index.cjs.js +7 -6
  22. package/dist/targets/dom/timeline/index.es.js +8 -7
  23. package/dist/targets/dom/timeline/utils/calc-time.cjs.js +3 -1
  24. package/dist/targets/dom/timeline/utils/calc-time.es.js +3 -1
  25. package/dist/targets/dom/utils/apply.cjs.js +4 -8
  26. package/dist/targets/dom/utils/apply.es.js +3 -7
  27. package/dist/targets/dom/utils/controls.cjs.js +6 -2
  28. package/dist/targets/dom/utils/controls.es.js +6 -2
  29. package/dist/targets/dom/utils/css-var.cjs.js +2 -2
  30. package/dist/targets/dom/utils/css-var.es.js +3 -3
  31. package/dist/targets/dom/utils/easing.cjs.js +4 -2
  32. package/dist/targets/dom/utils/easing.es.js +4 -2
  33. package/dist/targets/dom/utils/feature-detection.cjs.js +4 -4
  34. package/dist/targets/dom/utils/feature-detection.es.js +4 -4
  35. package/dist/targets/dom/utils/get-style-name.cjs.js +13 -0
  36. package/dist/targets/dom/utils/get-style-name.es.js +9 -0
  37. package/dist/targets/dom/utils/keyframes.cjs.js +2 -4
  38. package/dist/targets/dom/utils/keyframes.es.js +2 -4
  39. package/dist/targets/dom/utils/options.cjs.js +1 -1
  40. package/dist/targets/dom/utils/options.es.js +1 -1
  41. package/dist/targets/dom/utils/stop-animation.cjs.js +2 -0
  42. package/dist/targets/dom/utils/stop-animation.es.js +2 -0
  43. package/dist/targets/dom/utils/transforms.cjs.js +10 -7
  44. package/dist/targets/dom/utils/transforms.es.js +10 -7
  45. package/dist/targets/js/{animate-number.cjs.js → NumberAnimation.cjs.js} +40 -29
  46. package/dist/targets/js/{animate-number.es.js → NumberAnimation.es.js} +40 -28
  47. package/dist/targets/js/easing/glide/generator.cjs.js +99 -0
  48. package/dist/targets/js/easing/glide/generator.es.js +95 -0
  49. package/dist/targets/js/easing/glide/index.cjs.js +10 -0
  50. package/dist/targets/js/easing/glide/index.es.js +6 -0
  51. package/dist/targets/js/easing/spring/generator.cjs.js +9 -4
  52. package/dist/targets/js/easing/spring/generator.es.js +9 -5
  53. package/dist/targets/js/easing/spring/index.cjs.js +2 -62
  54. package/dist/targets/js/easing/spring/index.es.js +2 -62
  55. package/dist/targets/js/easing/utils/create-generator-easing.cjs.js +71 -0
  56. package/dist/targets/js/easing/utils/create-generator-easing.es.js +67 -0
  57. package/dist/targets/js/easing/utils/has-reached-target.cjs.js +10 -0
  58. package/dist/targets/js/easing/utils/has-reached-target.es.js +6 -0
  59. package/dist/targets/js/easing/utils/pregenerate-keyframes.cjs.js +13 -10
  60. package/dist/targets/js/easing/utils/pregenerate-keyframes.es.js +13 -10
  61. package/dist/targets/react/hooks/use-animation.cjs.js +5 -2
  62. package/dist/targets/react/hooks/use-animation.es.js +5 -2
  63. package/dist/targets/react/utils/keyframes.cjs.js +5 -3
  64. package/dist/targets/react/utils/keyframes.es.js +6 -4
  65. package/dist/utils/is-number.cjs.js +7 -0
  66. package/dist/utils/is-number.es.js +3 -0
  67. package/dist/utils/stagger.cjs.js +2 -1
  68. package/dist/utils/stagger.es.js +2 -1
  69. package/package.json +4 -10
  70. package/types/index.d.ts +1 -0
  71. package/types/targets/dom/animate-style.d.ts +2 -2
  72. package/types/targets/dom/style.d.ts +1 -1
  73. package/types/targets/dom/types.d.ts +8 -4
  74. package/types/targets/dom/utils/apply.d.ts +3 -2
  75. package/types/targets/dom/utils/controls.d.ts +3 -3
  76. package/types/targets/dom/utils/get-style-name.d.ts +1 -0
  77. package/types/targets/dom/utils/keyframes.d.ts +1 -1
  78. package/types/targets/dom/utils/stop-animation.d.ts +1 -1
  79. package/types/targets/dom/utils/transforms.d.ts +2 -2
  80. package/types/targets/js/{animate-number.d.ts → NumberAnimation.d.ts} +2 -3
  81. package/types/targets/js/easing/glide/generator.d.ts +5 -0
  82. package/types/targets/js/easing/glide/index.d.ts +2 -0
  83. package/types/targets/js/easing/glide/types.d.ts +14 -0
  84. package/types/targets/js/easing/spring/generator.d.ts +1 -0
  85. package/types/targets/js/easing/spring/index.d.ts +1 -2
  86. package/types/targets/js/easing/utils/create-generator-easing.d.ts +3 -0
  87. package/types/targets/js/easing/utils/has-reached-target.d.ts +1 -0
  88. package/types/targets/js/easing/utils/pregenerate-keyframes.d.ts +1 -1
  89. package/types/targets/js/types.d.ts +3 -0
  90. package/types/utils/is-number.d.ts +1 -0
@@ -7,175 +7,176 @@ var cssVar = require('./utils/css-var.cjs.js');
7
7
  var noop = require('../../utils/noop.cjs.js');
8
8
  var time = require('./utils/time.cjs.js');
9
9
  var transforms = require('./utils/transforms.cjs.js');
10
- var stopAnimation = require('./utils/stop-animation.cjs.js');
11
10
  var easing = require('./utils/easing.cjs.js');
12
11
  var featureDetection = require('./utils/feature-detection.cjs.js');
13
12
  var apply = require('./utils/apply.cjs.js');
14
- var animateNumber = require('../js/animate-number.cjs.js');
13
+ var NumberAnimation = require('../js/NumberAnimation.cjs.js');
15
14
  var keyframes = require('./utils/keyframes.cjs.js');
16
15
  var style = require('./style.cjs.js');
17
16
  var defaults = require('./utils/defaults.cjs.js');
17
+ var getStyleName = require('./utils/get-style-name.cjs.js');
18
+ var isNumber = require('../../utils/is-number.cjs.js');
19
+ var stopAnimation = require('./utils/stop-animation.cjs.js');
18
20
 
19
- function animateStyle(element, name, keyframesDefinition, options = {}) {
21
+ function animateStyle(element, key, keyframesDefinition, options = {}) {
20
22
  let animation;
21
23
  let { duration = defaults.defaults.duration, delay = defaults.defaults.delay, endDelay = defaults.defaults.endDelay, repeat = defaults.defaults.repeat, easing: easing$1 = defaults.defaults.easing, direction, offset, allowWebkitAcceleration = false, } = options;
22
24
  const data$1 = data.getAnimationData(element);
23
25
  let canAnimateNatively = featureDetection.supports.waapi();
24
26
  let render = noop.noop;
25
- const valueIsTransform = transforms.isTransform(name);
27
+ const valueIsTransform = transforms.isTransform(key);
26
28
  /**
27
29
  * If this is an individual transform, we need to map its
28
30
  * key to a CSS variable and update the element's transform style
29
31
  */
30
- if (valueIsTransform) {
31
- if (transforms.transformAlias[name])
32
- name = transforms.transformAlias[name];
33
- transforms.addTransformToElement(element, name);
34
- name = transforms.asTransformCssVar(name);
35
- }
32
+ valueIsTransform && transforms.addTransformToElement(element, key);
33
+ const name = getStyleName.getStyleName(key);
36
34
  /**
37
35
  * Get definition of value, this will be used to convert numerical
38
36
  * keyframes into the default value type.
39
37
  */
40
- const definition = transforms.transformPropertyDefinitions.get(name);
41
- /**
42
- * Replace null values with the previous keyframe value, or read
43
- * it from the DOM if it's the first keyframe.
44
- *
45
- * TODO: This needs to come after the valueIsTransform
46
- * check so it can correctly read the underlying value.
47
- * Should make a test for this.
48
- */
49
- let keyframes$1 = keyframes.hydrateKeyframes(keyframes.keyframesList(keyframesDefinition), element, name);
50
- if (easing.isCustomEasing(easing$1)) {
51
- const custom = easing$1.createAnimation(keyframes$1, () => style.style.get(element, name), valueIsTransform, name, data$1);
52
- easing$1 = custom.easing;
53
- if (custom.keyframes)
54
- keyframes$1 = custom.keyframes;
55
- if (custom.duration)
56
- duration = custom.duration;
57
- }
58
- /**
59
- * If this is a CSS variable we need to register it with the browser
60
- * before it can be animated natively. We also set it with setProperty
61
- * rather than directly onto the element.style object.
62
- */
63
- if (cssVar.isCssVar(name)) {
64
- render = apply.createCssVariableRenderer(element, name);
65
- if (featureDetection.supports.cssRegisterProperty()) {
66
- cssVar.registerCssVariable(name);
67
- }
68
- else {
69
- canAnimateNatively = false;
70
- }
71
- }
72
- else {
73
- render = apply.createStyleRenderer(element, name);
74
- }
38
+ const definition = transforms.transformDefinitions.get(name);
75
39
  /**
76
- * Stop the current animation, if any, after we have the
77
- * opportunity to use its data to generate velocity for
78
- * the subsequent animation.
40
+ * Stop the current animation, if any. Because this will trigger
41
+ * commitStyles (DOM writes) and we might later trigger DOM reads,
42
+ * this is fired now and we return a factory function to create
43
+ * the actual animation that can get called in batch,
79
44
  */
80
- stopCurrentAnimation(data$1, name);
45
+ stopAnimation.stopAnimation(data$1.animations[name]);
81
46
  /**
82
- * If we can animate this value with WAAPI, do so. Currently this only
83
- * feature detects CSS.registerProperty but could check WAAPI too.
47
+ * Batchable factory function containing all DOM reads.
84
48
  */
85
- if (canAnimateNatively) {
49
+ return () => {
50
+ const readInitialValue = () => { var _a, _b; return (_b = (_a = style.style.get(element, name)) !== null && _a !== void 0 ? _a : definition === null || definition === void 0 ? void 0 : definition.initialValue) !== null && _b !== void 0 ? _b : 0; };
86
51
  /**
87
- * Convert numbers to default value types. Currently this only supports
88
- * transforms but it could also support other value types.
52
+ * Replace null values with the previous keyframe value, or read
53
+ * it from the DOM if it's the first keyframe.
89
54
  */
90
- if (definition) {
91
- keyframes$1 = keyframes$1.map((value) => typeof value === "number" ? definition.toDefaultUnit(value) : value);
92
- }
93
- if (!featureDetection.supports.partialKeyframes() && keyframes$1.length === 1) {
94
- keyframes$1.unshift(style.style.get(element, name));
55
+ let keyframes$1 = keyframes.hydrateKeyframes(keyframes.keyframesList(keyframesDefinition), readInitialValue);
56
+ if (easing.isCustomEasing(easing$1)) {
57
+ const custom = easing$1.createAnimation(keyframes$1, readInitialValue, valueIsTransform, name, data$1);
58
+ easing$1 = custom.easing;
59
+ if (custom.keyframes !== undefined)
60
+ keyframes$1 = custom.keyframes;
61
+ if (custom.duration !== undefined)
62
+ duration = custom.duration;
95
63
  }
96
- const animationOptions = {
97
- delay: time.ms(delay),
98
- duration: time.ms(duration),
99
- endDelay: time.ms(endDelay),
100
- easing: !easing.isEasingList(easing$1) ? easing.convertEasing(easing$1) : undefined,
101
- direction,
102
- iterations: repeat + 1,
103
- fill: "both",
104
- };
105
- animation = element.animate({
106
- [name]: keyframes$1,
107
- offset,
108
- easing: easing.isEasingList(easing$1) ? easing$1.map(easing.convertEasing) : undefined,
109
- }, animationOptions);
110
64
  /**
111
- * Polyfill finished Promise in browsers that don't support it
65
+ * If this is a CSS variable we need to register it with the browser
66
+ * before it can be animated natively. We also set it with setProperty
67
+ * rather than directly onto the element.style object.
112
68
  */
113
- if (!animation.finished) {
114
- animation.finished = new Promise((resolve, reject) => {
115
- animation.onfinish = resolve;
116
- animation.oncancel = reject;
117
- });
69
+ if (cssVar.isCssVar(name)) {
70
+ render = apply.cssVariableRenderer(element, name);
71
+ if (featureDetection.supports.cssRegisterProperty()) {
72
+ cssVar.registerCssVariable(name);
73
+ }
74
+ else {
75
+ canAnimateNatively = false;
76
+ }
77
+ }
78
+ else {
79
+ render = apply.styleRenderer(element, name);
118
80
  }
119
- const target = keyframes$1[keyframes$1.length - 1];
120
- animation.finished
121
- .then(() => {
122
- // Apply styles to target
123
- render(target);
124
- // Ensure fill modes don't persist
125
- animation.cancel();
126
- })
127
- .catch(noop.noop);
128
81
  /**
129
- * This forces Webkit to run animations on the main thread by exploiting
130
- * this condition:
131
- * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp?rev=281238#L1099
132
- *
133
- * This fixes Webkit's timing bugs, like accelerated animations falling
134
- * out of sync with main thread animations and massive delays in starting
135
- * accelerated animations in WKWebView.
82
+ * If we can animate this value with WAAPI, do so. Currently this only
83
+ * feature detects CSS.registerProperty but could check WAAPI too.
136
84
  */
137
- if (!allowWebkitAcceleration)
138
- animation.playbackRate = 1.000001;
139
- }
140
- else if (valueIsTransform && keyframes$1.every(isNumber)) {
141
- if (keyframes$1.length === 1) {
142
- keyframes$1.unshift(style.style.get(element, name) || (definition === null || definition === void 0 ? void 0 : definition.initialValue) || 0);
85
+ if (canAnimateNatively) {
86
+ /**
87
+ * Convert numbers to default value types. Currently this only supports
88
+ * transforms but it could also support other value types.
89
+ */
90
+ if (definition) {
91
+ keyframes$1 = keyframes$1.map((value) => isNumber.isNumber(value) ? definition.toDefaultUnit(value) : value);
92
+ }
93
+ /**
94
+ * If this browser doesn't support partial/implicit keyframes we need to
95
+ * explicitly provide one.
96
+ */
97
+ if (!featureDetection.supports.partialKeyframes() && keyframes$1.length === 1) {
98
+ keyframes$1.unshift(readInitialValue());
99
+ }
100
+ const animationOptions = {
101
+ delay: time.ms(delay),
102
+ duration: time.ms(duration),
103
+ endDelay: time.ms(endDelay),
104
+ easing: !easing.isEasingList(easing$1) ? easing.convertEasing(easing$1) : undefined,
105
+ direction,
106
+ iterations: repeat + 1,
107
+ fill: "both",
108
+ };
109
+ animation = element.animate({
110
+ [name]: keyframes$1,
111
+ offset,
112
+ easing: easing.isEasingList(easing$1) ? easing$1.map(easing.convertEasing) : undefined,
113
+ }, animationOptions);
114
+ /**
115
+ * Polyfill finished Promise in browsers that don't support it
116
+ */
117
+ if (!animation.finished) {
118
+ animation.finished = new Promise((resolve, reject) => {
119
+ animation.onfinish = resolve;
120
+ animation.oncancel = reject;
121
+ });
122
+ }
123
+ const target = keyframes$1[keyframes$1.length - 1];
124
+ animation.finished
125
+ .then(() => {
126
+ // Apply styles to target
127
+ render(target);
128
+ // Ensure fill modes don't persist
129
+ animation.cancel();
130
+ })
131
+ .catch(noop.noop);
132
+ /**
133
+ * This forces Webkit to run animations on the main thread by exploiting
134
+ * this condition:
135
+ * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp?rev=281238#L1099
136
+ *
137
+ * This fixes Webkit's timing bugs, like accelerated animations falling
138
+ * out of sync with main thread animations and massive delays in starting
139
+ * accelerated animations in WKWebView.
140
+ */
141
+ if (!allowWebkitAcceleration)
142
+ animation.playbackRate = 1.000001;
143
+ /**
144
+ * If we can't animate the value natively then we can fallback to the numbers-only
145
+ * polyfill for transforms. All keyframes must be numerical.
146
+ */
147
+ }
148
+ else if (valueIsTransform && keyframes$1.every(isNumber.isNumber)) {
149
+ /**
150
+ * If we only have a single keyframe, we need to create an initial keyframe by reading
151
+ * the current value from the DOM.
152
+ */
153
+ if (keyframes$1.length === 1) {
154
+ keyframes$1.unshift(parseFloat(readInitialValue()));
155
+ }
156
+ if (definition) {
157
+ const applyStyle = render;
158
+ render = (v) => applyStyle(definition.toDefaultUnit(v));
159
+ }
160
+ animation = new NumberAnimation.NumberAnimation(render, keyframes$1, Object.assign(Object.assign({}, options), { duration,
161
+ easing: easing$1 }));
162
+ }
163
+ else {
164
+ const target = keyframes$1[keyframes$1.length - 1];
165
+ render(definition && isNumber.isNumber(target)
166
+ ? definition.toDefaultUnit(target)
167
+ : target);
143
168
  }
169
+ data$1.animations[name] = animation;
144
170
  /**
145
- * Transform styles are currently only accepted as numbers of
146
- * their default value type, so here we loop through and map
147
- * them to numbers.
171
+ * When an animation finishes, delete the reference to the previous animation.
148
172
  */
149
- keyframes$1 = keyframes$1.map((value) => typeof value === "string" ? parseFloat(value) : value);
150
- if (definition) {
151
- const applyStyle = render;
152
- render = (v) => applyStyle(definition.toDefaultUnit(v));
153
- }
154
- animation = animateNumber.animateNumber(render, keyframes$1, Object.assign(Object.assign({}, options), { duration,
155
- easing: easing$1 }));
156
- }
157
- else {
158
- const target = keyframes$1[keyframes$1.length - 1];
159
- render(definition && typeof target === "number"
160
- ? definition.toDefaultUnit(target)
161
- : target);
162
- }
163
- data$1.activeAnimations[name] = animation;
164
- /**
165
- * When an animation finishes, delete the reference to the previous animation.
166
- */
167
- animation === null || animation === void 0 ? void 0 : animation.finished.then(() => clearData(data$1, name)).catch(noop.noop);
168
- return animation;
169
- }
170
- function stopCurrentAnimation(data, name) {
171
- if (data.activeAnimations[name]) {
172
- stopAnimation.stopAnimation(data.activeAnimations[name]);
173
- clearData(data, name);
174
- }
175
- }
176
- function clearData(data, name) {
177
- data.activeGenerators[name] = data.activeAnimations[name] = undefined;
173
+ animation === null || animation === void 0 ? void 0 : animation.finished.then(() => {
174
+ data$1.animations[name] = undefined;
175
+ data$1.generators[name] = undefined;
176
+ data$1.prevGeneratorState[name] = undefined;
177
+ }).catch(noop.noop);
178
+ return animation;
179
+ };
178
180
  }
179
- const isNumber = (value) => typeof value === "number";
180
181
 
181
182
  exports.animateStyle = animateStyle;
@@ -2,176 +2,177 @@ import { getAnimationData } from './data.es.js';
2
2
  import { isCssVar, registerCssVariable } from './utils/css-var.es.js';
3
3
  import { noop } from '../../utils/noop.es.js';
4
4
  import { ms } from './utils/time.es.js';
5
- import { isTransform, transformAlias, addTransformToElement, asTransformCssVar, transformPropertyDefinitions } from './utils/transforms.es.js';
6
- import { stopAnimation } from './utils/stop-animation.es.js';
5
+ import { isTransform, addTransformToElement, transformDefinitions } from './utils/transforms.es.js';
7
6
  import { isCustomEasing, isEasingList, convertEasing } from './utils/easing.es.js';
8
7
  import { supports } from './utils/feature-detection.es.js';
9
- import { createCssVariableRenderer, createStyleRenderer } from './utils/apply.es.js';
10
- import { animateNumber } from '../js/animate-number.es.js';
8
+ import { cssVariableRenderer, styleRenderer } from './utils/apply.es.js';
9
+ import { NumberAnimation } from '../js/NumberAnimation.es.js';
11
10
  import { hydrateKeyframes, keyframesList } from './utils/keyframes.es.js';
12
11
  import { style } from './style.es.js';
13
12
  import { defaults } from './utils/defaults.es.js';
13
+ import { getStyleName } from './utils/get-style-name.es.js';
14
+ import { isNumber } from '../../utils/is-number.es.js';
15
+ import { stopAnimation } from './utils/stop-animation.es.js';
14
16
 
15
- function animateStyle(element, name, keyframesDefinition, options = {}) {
17
+ function animateStyle(element, key, keyframesDefinition, options = {}) {
16
18
  let animation;
17
19
  let { duration = defaults.duration, delay = defaults.delay, endDelay = defaults.endDelay, repeat = defaults.repeat, easing = defaults.easing, direction, offset, allowWebkitAcceleration = false, } = options;
18
20
  const data = getAnimationData(element);
19
21
  let canAnimateNatively = supports.waapi();
20
22
  let render = noop;
21
- const valueIsTransform = isTransform(name);
23
+ const valueIsTransform = isTransform(key);
22
24
  /**
23
25
  * If this is an individual transform, we need to map its
24
26
  * key to a CSS variable and update the element's transform style
25
27
  */
26
- if (valueIsTransform) {
27
- if (transformAlias[name])
28
- name = transformAlias[name];
29
- addTransformToElement(element, name);
30
- name = asTransformCssVar(name);
31
- }
28
+ valueIsTransform && addTransformToElement(element, key);
29
+ const name = getStyleName(key);
32
30
  /**
33
31
  * Get definition of value, this will be used to convert numerical
34
32
  * keyframes into the default value type.
35
33
  */
36
- const definition = transformPropertyDefinitions.get(name);
37
- /**
38
- * Replace null values with the previous keyframe value, or read
39
- * it from the DOM if it's the first keyframe.
40
- *
41
- * TODO: This needs to come after the valueIsTransform
42
- * check so it can correctly read the underlying value.
43
- * Should make a test for this.
44
- */
45
- let keyframes = hydrateKeyframes(keyframesList(keyframesDefinition), element, name);
46
- if (isCustomEasing(easing)) {
47
- const custom = easing.createAnimation(keyframes, () => style.get(element, name), valueIsTransform, name, data);
48
- easing = custom.easing;
49
- if (custom.keyframes)
50
- keyframes = custom.keyframes;
51
- if (custom.duration)
52
- duration = custom.duration;
53
- }
54
- /**
55
- * If this is a CSS variable we need to register it with the browser
56
- * before it can be animated natively. We also set it with setProperty
57
- * rather than directly onto the element.style object.
58
- */
59
- if (isCssVar(name)) {
60
- render = createCssVariableRenderer(element, name);
61
- if (supports.cssRegisterProperty()) {
62
- registerCssVariable(name);
63
- }
64
- else {
65
- canAnimateNatively = false;
66
- }
67
- }
68
- else {
69
- render = createStyleRenderer(element, name);
70
- }
34
+ const definition = transformDefinitions.get(name);
71
35
  /**
72
- * Stop the current animation, if any, after we have the
73
- * opportunity to use its data to generate velocity for
74
- * the subsequent animation.
36
+ * Stop the current animation, if any. Because this will trigger
37
+ * commitStyles (DOM writes) and we might later trigger DOM reads,
38
+ * this is fired now and we return a factory function to create
39
+ * the actual animation that can get called in batch,
75
40
  */
76
- stopCurrentAnimation(data, name);
41
+ stopAnimation(data.animations[name]);
77
42
  /**
78
- * If we can animate this value with WAAPI, do so. Currently this only
79
- * feature detects CSS.registerProperty but could check WAAPI too.
43
+ * Batchable factory function containing all DOM reads.
80
44
  */
81
- if (canAnimateNatively) {
45
+ return () => {
46
+ const readInitialValue = () => { var _a, _b; return (_b = (_a = style.get(element, name)) !== null && _a !== void 0 ? _a : definition === null || definition === void 0 ? void 0 : definition.initialValue) !== null && _b !== void 0 ? _b : 0; };
82
47
  /**
83
- * Convert numbers to default value types. Currently this only supports
84
- * transforms but it could also support other value types.
48
+ * Replace null values with the previous keyframe value, or read
49
+ * it from the DOM if it's the first keyframe.
85
50
  */
86
- if (definition) {
87
- keyframes = keyframes.map((value) => typeof value === "number" ? definition.toDefaultUnit(value) : value);
88
- }
89
- if (!supports.partialKeyframes() && keyframes.length === 1) {
90
- keyframes.unshift(style.get(element, name));
51
+ let keyframes = hydrateKeyframes(keyframesList(keyframesDefinition), readInitialValue);
52
+ if (isCustomEasing(easing)) {
53
+ const custom = easing.createAnimation(keyframes, readInitialValue, valueIsTransform, name, data);
54
+ easing = custom.easing;
55
+ if (custom.keyframes !== undefined)
56
+ keyframes = custom.keyframes;
57
+ if (custom.duration !== undefined)
58
+ duration = custom.duration;
91
59
  }
92
- const animationOptions = {
93
- delay: ms(delay),
94
- duration: ms(duration),
95
- endDelay: ms(endDelay),
96
- easing: !isEasingList(easing) ? convertEasing(easing) : undefined,
97
- direction,
98
- iterations: repeat + 1,
99
- fill: "both",
100
- };
101
- animation = element.animate({
102
- [name]: keyframes,
103
- offset,
104
- easing: isEasingList(easing) ? easing.map(convertEasing) : undefined,
105
- }, animationOptions);
106
60
  /**
107
- * Polyfill finished Promise in browsers that don't support it
61
+ * If this is a CSS variable we need to register it with the browser
62
+ * before it can be animated natively. We also set it with setProperty
63
+ * rather than directly onto the element.style object.
108
64
  */
109
- if (!animation.finished) {
110
- animation.finished = new Promise((resolve, reject) => {
111
- animation.onfinish = resolve;
112
- animation.oncancel = reject;
113
- });
65
+ if (isCssVar(name)) {
66
+ render = cssVariableRenderer(element, name);
67
+ if (supports.cssRegisterProperty()) {
68
+ registerCssVariable(name);
69
+ }
70
+ else {
71
+ canAnimateNatively = false;
72
+ }
73
+ }
74
+ else {
75
+ render = styleRenderer(element, name);
114
76
  }
115
- const target = keyframes[keyframes.length - 1];
116
- animation.finished
117
- .then(() => {
118
- // Apply styles to target
119
- render(target);
120
- // Ensure fill modes don't persist
121
- animation.cancel();
122
- })
123
- .catch(noop);
124
77
  /**
125
- * This forces Webkit to run animations on the main thread by exploiting
126
- * this condition:
127
- * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp?rev=281238#L1099
128
- *
129
- * This fixes Webkit's timing bugs, like accelerated animations falling
130
- * out of sync with main thread animations and massive delays in starting
131
- * accelerated animations in WKWebView.
78
+ * If we can animate this value with WAAPI, do so. Currently this only
79
+ * feature detects CSS.registerProperty but could check WAAPI too.
132
80
  */
133
- if (!allowWebkitAcceleration)
134
- animation.playbackRate = 1.000001;
135
- }
136
- else if (valueIsTransform && keyframes.every(isNumber)) {
137
- if (keyframes.length === 1) {
138
- keyframes.unshift(style.get(element, name) || (definition === null || definition === void 0 ? void 0 : definition.initialValue) || 0);
81
+ if (canAnimateNatively) {
82
+ /**
83
+ * Convert numbers to default value types. Currently this only supports
84
+ * transforms but it could also support other value types.
85
+ */
86
+ if (definition) {
87
+ keyframes = keyframes.map((value) => isNumber(value) ? definition.toDefaultUnit(value) : value);
88
+ }
89
+ /**
90
+ * If this browser doesn't support partial/implicit keyframes we need to
91
+ * explicitly provide one.
92
+ */
93
+ if (!supports.partialKeyframes() && keyframes.length === 1) {
94
+ keyframes.unshift(readInitialValue());
95
+ }
96
+ const animationOptions = {
97
+ delay: ms(delay),
98
+ duration: ms(duration),
99
+ endDelay: ms(endDelay),
100
+ easing: !isEasingList(easing) ? convertEasing(easing) : undefined,
101
+ direction,
102
+ iterations: repeat + 1,
103
+ fill: "both",
104
+ };
105
+ animation = element.animate({
106
+ [name]: keyframes,
107
+ offset,
108
+ easing: isEasingList(easing) ? easing.map(convertEasing) : undefined,
109
+ }, animationOptions);
110
+ /**
111
+ * Polyfill finished Promise in browsers that don't support it
112
+ */
113
+ if (!animation.finished) {
114
+ animation.finished = new Promise((resolve, reject) => {
115
+ animation.onfinish = resolve;
116
+ animation.oncancel = reject;
117
+ });
118
+ }
119
+ const target = keyframes[keyframes.length - 1];
120
+ animation.finished
121
+ .then(() => {
122
+ // Apply styles to target
123
+ render(target);
124
+ // Ensure fill modes don't persist
125
+ animation.cancel();
126
+ })
127
+ .catch(noop);
128
+ /**
129
+ * This forces Webkit to run animations on the main thread by exploiting
130
+ * this condition:
131
+ * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp?rev=281238#L1099
132
+ *
133
+ * This fixes Webkit's timing bugs, like accelerated animations falling
134
+ * out of sync with main thread animations and massive delays in starting
135
+ * accelerated animations in WKWebView.
136
+ */
137
+ if (!allowWebkitAcceleration)
138
+ animation.playbackRate = 1.000001;
139
+ /**
140
+ * If we can't animate the value natively then we can fallback to the numbers-only
141
+ * polyfill for transforms. All keyframes must be numerical.
142
+ */
143
+ }
144
+ else if (valueIsTransform && keyframes.every(isNumber)) {
145
+ /**
146
+ * If we only have a single keyframe, we need to create an initial keyframe by reading
147
+ * the current value from the DOM.
148
+ */
149
+ if (keyframes.length === 1) {
150
+ keyframes.unshift(parseFloat(readInitialValue()));
151
+ }
152
+ if (definition) {
153
+ const applyStyle = render;
154
+ render = (v) => applyStyle(definition.toDefaultUnit(v));
155
+ }
156
+ animation = new NumberAnimation(render, keyframes, Object.assign(Object.assign({}, options), { duration,
157
+ easing }));
158
+ }
159
+ else {
160
+ const target = keyframes[keyframes.length - 1];
161
+ render(definition && isNumber(target)
162
+ ? definition.toDefaultUnit(target)
163
+ : target);
139
164
  }
165
+ data.animations[name] = animation;
140
166
  /**
141
- * Transform styles are currently only accepted as numbers of
142
- * their default value type, so here we loop through and map
143
- * them to numbers.
167
+ * When an animation finishes, delete the reference to the previous animation.
144
168
  */
145
- keyframes = keyframes.map((value) => typeof value === "string" ? parseFloat(value) : value);
146
- if (definition) {
147
- const applyStyle = render;
148
- render = (v) => applyStyle(definition.toDefaultUnit(v));
149
- }
150
- animation = animateNumber(render, keyframes, Object.assign(Object.assign({}, options), { duration,
151
- easing }));
152
- }
153
- else {
154
- const target = keyframes[keyframes.length - 1];
155
- render(definition && typeof target === "number"
156
- ? definition.toDefaultUnit(target)
157
- : target);
158
- }
159
- data.activeAnimations[name] = animation;
160
- /**
161
- * When an animation finishes, delete the reference to the previous animation.
162
- */
163
- animation === null || animation === void 0 ? void 0 : animation.finished.then(() => clearData(data, name)).catch(noop);
164
- return animation;
165
- }
166
- function stopCurrentAnimation(data, name) {
167
- if (data.activeAnimations[name]) {
168
- stopAnimation(data.activeAnimations[name]);
169
- clearData(data, name);
170
- }
171
- }
172
- function clearData(data, name) {
173
- data.activeGenerators[name] = data.activeAnimations[name] = undefined;
169
+ animation === null || animation === void 0 ? void 0 : animation.finished.then(() => {
170
+ data.animations[name] = undefined;
171
+ data.generators[name] = undefined;
172
+ data.prevGeneratorState[name] = undefined;
173
+ }).catch(noop);
174
+ return animation;
175
+ };
174
176
  }
175
- const isNumber = (value) => typeof value === "number";
176
177
 
177
178
  export { animateStyle };
@@ -12,19 +12,30 @@ var defaults = require('./utils/defaults.cjs.js');
12
12
  function animate(elements, keyframes, options$1 = {}) {
13
13
  var _a;
14
14
  elements = resolveElements.resolveElements(elements);
15
- const animations = [];
16
15
  const numElements = elements.length;
16
+ /**
17
+ * Create and start new animations
18
+ */
19
+ const animationFactories = [];
17
20
  for (let i = 0; i < numElements; i++) {
18
21
  const element = elements[i];
19
22
  for (const key in keyframes) {
20
23
  const valueOptions = options.getOptions(options$1, key);
21
24
  valueOptions.delay = stagger.resolveOption(valueOptions.delay, i, numElements);
22
25
  const animation = animateStyle.animateStyle(element, key, keyframes[key], valueOptions);
23
- animation && animations.push(animation);
26
+ animationFactories.push(animation);
24
27
  }
25
28
  }
26
- return controls.createAnimationControls(animations,
27
- // TODO: Remove this in case duration is dynamically generated
29
+ return controls.createAnimations(animationFactories,
30
+ /**
31
+ * TODO:
32
+ * If easing is set to spring or glide, duration will be dynamically
33
+ * generated. Ideally we would dynamically generate this from
34
+ * animation.effect.getComputedTiming().duration but this isn't
35
+ * supported in iOS13 or our number polyfill. Perhaps it's possible
36
+ * to Proxy animations returned from animateStyle that has duration
37
+ * as a getter.
38
+ */
28
39
  (_a = options$1.duration) !== null && _a !== void 0 ? _a : defaults.defaults.duration);
29
40
  }
30
41