@angular/animations 14.0.0-next.0 → 14.0.0-next.11

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 (50) hide show
  1. package/animations.d.ts +16 -3
  2. package/browser/browser.d.ts +29 -94
  3. package/browser/testing/testing.d.ts +10 -15
  4. package/esm2020/browser/src/dsl/animation.mjs +10 -6
  5. package/esm2020/browser/src/dsl/animation_ast.mjs +1 -1
  6. package/esm2020/browser/src/dsl/animation_ast_builder.mjs +80 -70
  7. package/esm2020/browser/src/dsl/animation_dsl_visitor.mjs +1 -1
  8. package/esm2020/browser/src/dsl/animation_timeline_builder.mjs +79 -88
  9. package/esm2020/browser/src/dsl/animation_timeline_instruction.mjs +1 -1
  10. package/esm2020/browser/src/dsl/animation_transition_expr.mjs +4 -3
  11. package/esm2020/browser/src/dsl/animation_transition_factory.mjs +29 -18
  12. package/esm2020/browser/src/dsl/animation_transition_instruction.mjs +8 -1
  13. package/esm2020/browser/src/dsl/animation_trigger.mjs +9 -9
  14. package/esm2020/browser/src/dsl/style_normalization/animation_style_normalizer.mjs +1 -1
  15. package/esm2020/browser/src/dsl/style_normalization/web_animations_style_normalizer.mjs +35 -10
  16. package/esm2020/browser/src/error_helpers.mjs +135 -0
  17. package/esm2020/browser/src/errors.mjs +9 -0
  18. package/esm2020/browser/src/private_export.mjs +4 -6
  19. package/esm2020/browser/src/render/animation_driver.mjs +8 -5
  20. package/esm2020/browser/src/render/animation_engine_next.mjs +9 -3
  21. package/esm2020/browser/src/render/shared.mjs +39 -33
  22. package/esm2020/browser/src/render/special_cased_styles.mjs +7 -16
  23. package/esm2020/browser/src/render/timeline_animation_engine.mjs +26 -20
  24. package/esm2020/browser/src/render/transition_animation_engine.mjs +82 -88
  25. package/esm2020/browser/src/render/web_animations/animatable_props_set.mjs +214 -0
  26. package/esm2020/browser/src/render/web_animations/web_animations_driver.mjs +21 -29
  27. package/esm2020/browser/src/render/web_animations/web_animations_player.mjs +16 -9
  28. package/esm2020/browser/src/util.mjs +48 -37
  29. package/esm2020/browser/src/warning_helpers.mjs +38 -0
  30. package/esm2020/browser/testing/src/mock_animation_driver.mjs +23 -14
  31. package/esm2020/src/animation_metadata.mjs +10 -2
  32. package/esm2020/src/animations.mjs +1 -1
  33. package/esm2020/src/version.mjs +1 -1
  34. package/fesm2015/animations.mjs +10 -2
  35. package/fesm2015/animations.mjs.map +1 -1
  36. package/fesm2015/browser/testing.mjs +859 -15
  37. package/fesm2015/browser/testing.mjs.map +1 -1
  38. package/fesm2015/browser.mjs +863 -858
  39. package/fesm2015/browser.mjs.map +1 -1
  40. package/fesm2020/animations.mjs +10 -2
  41. package/fesm2020/animations.mjs.map +1 -1
  42. package/fesm2020/browser/testing.mjs +859 -15
  43. package/fesm2020/browser/testing.mjs.map +1 -1
  44. package/fesm2020/browser.mjs +861 -857
  45. package/fesm2020/browser.mjs.map +1 -1
  46. package/package.json +3 -3
  47. package/esm2020/browser/src/render/css_keyframes/css_keyframes_driver.mjs +0 -121
  48. package/esm2020/browser/src/render/css_keyframes/css_keyframes_player.mjs +0 -133
  49. package/esm2020/browser/src/render/css_keyframes/direct_style_player.mjs +0 -51
  50. package/esm2020/browser/src/render/css_keyframes/element_animation_style_handler.mjs +0 -137
@@ -1,12 +1,360 @@
1
1
  /**
2
- * @license Angular v14.0.0-next.0
2
+ * @license Angular v14.0.0-next.11
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
6
6
 
7
7
  import { ɵAnimationGroupPlayer, NoopAnimationPlayer, AUTO_STYLE, ɵPRE_STYLE, sequence, style } from '@angular/animations';
8
8
  import * as i0 from '@angular/core';
9
- import { Injectable } from '@angular/core';
9
+ import { ɵRuntimeError, Injectable } from '@angular/core';
10
+
11
+ /**
12
+ * @license
13
+ * Copyright Google LLC All Rights Reserved.
14
+ *
15
+ * Use of this source code is governed by an MIT-style license that can be
16
+ * found in the LICENSE file at https://angular.io/license
17
+ */
18
+ const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
19
+ const LINE_START = '\n - ';
20
+ function invalidTimingValue(exp) {
21
+ return new ɵRuntimeError(3000 /* INVALID_TIMING_VALUE */, NG_DEV_MODE$1 && `The provided timing value "${exp}" is invalid.`);
22
+ }
23
+ function negativeStepValue() {
24
+ return new ɵRuntimeError(3100 /* NEGATIVE_STEP_VALUE */, NG_DEV_MODE$1 && 'Duration values below 0 are not allowed for this animation step.');
25
+ }
26
+ function negativeDelayValue() {
27
+ return new ɵRuntimeError(3101 /* NEGATIVE_DELAY_VALUE */, NG_DEV_MODE$1 && 'Delay values below 0 are not allowed for this animation step.');
28
+ }
29
+ function invalidStyleParams(varName) {
30
+ return new ɵRuntimeError(3001 /* INVALID_STYLE_PARAMS */, NG_DEV_MODE$1 &&
31
+ `Unable to resolve the local animation param ${varName} in the given list of values`);
32
+ }
33
+ function invalidParamValue(varName) {
34
+ return new ɵRuntimeError(3003 /* INVALID_PARAM_VALUE */, NG_DEV_MODE$1 && `Please provide a value for the animation param ${varName}`);
35
+ }
36
+ function invalidNodeType(nodeType) {
37
+ return new ɵRuntimeError(3004 /* INVALID_NODE_TYPE */, NG_DEV_MODE$1 && `Unable to resolve animation metadata node #${nodeType}`);
38
+ }
39
+ function invalidCssUnitValue(userProvidedProperty, value) {
40
+ return new ɵRuntimeError(3005 /* INVALID_CSS_UNIT_VALUE */, NG_DEV_MODE$1 && `Please provide a CSS unit value for ${userProvidedProperty}:${value}`);
41
+ }
42
+ function invalidTrigger() {
43
+ return new ɵRuntimeError(3006 /* INVALID_TRIGGER */, NG_DEV_MODE$1 &&
44
+ 'animation triggers cannot be prefixed with an `@` sign (e.g. trigger(\'@foo\', [...]))');
45
+ }
46
+ function invalidDefinition() {
47
+ return new ɵRuntimeError(3007 /* INVALID_DEFINITION */, NG_DEV_MODE$1 && 'only state() and transition() definitions can sit inside of a trigger()');
48
+ }
49
+ function invalidState(metadataName, missingSubs) {
50
+ return new ɵRuntimeError(3008 /* INVALID_STATE */, NG_DEV_MODE$1 &&
51
+ `state("${metadataName}", ...) must define default values for all the following style substitutions: ${missingSubs.join(', ')}`);
52
+ }
53
+ function invalidStyleValue(value) {
54
+ return new ɵRuntimeError(3002 /* INVALID_STYLE_VALUE */, NG_DEV_MODE$1 && `The provided style string value ${value} is not allowed.`);
55
+ }
56
+ function invalidProperty(prop) {
57
+ return new ɵRuntimeError(3009 /* INVALID_PROPERTY */, NG_DEV_MODE$1 &&
58
+ `The provided animation property "${prop}" is not a supported CSS property for animations`);
59
+ }
60
+ function invalidParallelAnimation(prop, firstStart, firstEnd, secondStart, secondEnd) {
61
+ return new ɵRuntimeError(3010 /* INVALID_PARALLEL_ANIMATION */, NG_DEV_MODE$1 &&
62
+ `The CSS property "${prop}" that exists between the times of "${firstStart}ms" and "${firstEnd}ms" is also being animated in a parallel animation between the times of "${secondStart}ms" and "${secondEnd}ms"`);
63
+ }
64
+ function invalidKeyframes() {
65
+ return new ɵRuntimeError(3011 /* INVALID_KEYFRAMES */, NG_DEV_MODE$1 && `keyframes() must be placed inside of a call to animate()`);
66
+ }
67
+ function invalidOffset() {
68
+ return new ɵRuntimeError(3012 /* INVALID_OFFSET */, NG_DEV_MODE$1 && `Please ensure that all keyframe offsets are between 0 and 1`);
69
+ }
70
+ function keyframeOffsetsOutOfOrder() {
71
+ return new ɵRuntimeError(3200 /* KEYFRAME_OFFSETS_OUT_OF_ORDER */, NG_DEV_MODE$1 && `Please ensure that all keyframe offsets are in order`);
72
+ }
73
+ function keyframesMissingOffsets() {
74
+ return new ɵRuntimeError(3202 /* KEYFRAMES_MISSING_OFFSETS */, NG_DEV_MODE$1 && `Not all style() steps within the declared keyframes() contain offsets`);
75
+ }
76
+ function invalidStagger() {
77
+ return new ɵRuntimeError(3013 /* INVALID_STAGGER */, NG_DEV_MODE$1 && `stagger() can only be used inside of query()`);
78
+ }
79
+ function invalidQuery(selector) {
80
+ return new ɵRuntimeError(3014 /* INVALID_QUERY */, NG_DEV_MODE$1 &&
81
+ `\`query("${selector}")\` returned zero elements. (Use \`query("${selector}", { optional: true })\` if you wish to allow this.)`);
82
+ }
83
+ function invalidExpression(expr) {
84
+ return new ɵRuntimeError(3015 /* INVALID_EXPRESSION */, NG_DEV_MODE$1 && `The provided transition expression "${expr}" is not supported`);
85
+ }
86
+ function invalidTransitionAlias(alias) {
87
+ return new ɵRuntimeError(3016 /* INVALID_TRANSITION_ALIAS */, NG_DEV_MODE$1 && `The transition alias value "${alias}" is not supported`);
88
+ }
89
+ function validationFailed(errors) {
90
+ return new ɵRuntimeError(3500 /* VALIDATION_FAILED */, NG_DEV_MODE$1 && `animation validation failed:\n${errors.map(err => err.message).join('\n')}`);
91
+ }
92
+ function buildingFailed(errors) {
93
+ return new ɵRuntimeError(3501 /* BUILDING_FAILED */, NG_DEV_MODE$1 && `animation building failed:\n${errors.map(err => err.message).join('\n')}`);
94
+ }
95
+ function triggerBuildFailed(name, errors) {
96
+ return new ɵRuntimeError(3404 /* TRIGGER_BUILD_FAILED */, NG_DEV_MODE$1 &&
97
+ `The animation trigger "${name}" has failed to build due to the following errors:\n - ${errors.map(err => err.message).join('\n - ')}`);
98
+ }
99
+ function animationFailed(errors) {
100
+ return new ɵRuntimeError(3502 /* ANIMATION_FAILED */, NG_DEV_MODE$1 &&
101
+ `Unable to animate due to the following errors:${LINE_START}${errors.map(err => err.message).join(LINE_START)}`);
102
+ }
103
+ function registerFailed(errors) {
104
+ return new ɵRuntimeError(3503 /* REGISTRATION_FAILED */, NG_DEV_MODE$1 &&
105
+ `Unable to build the animation due to the following errors: ${errors.map(err => err.message).join('\n')}`);
106
+ }
107
+ function missingOrDestroyedAnimation() {
108
+ return new ɵRuntimeError(3300 /* MISSING_OR_DESTROYED_ANIMATION */, NG_DEV_MODE$1 && 'The requested animation doesn\'t exist or has already been destroyed');
109
+ }
110
+ function createAnimationFailed(errors) {
111
+ return new ɵRuntimeError(3504 /* CREATE_ANIMATION_FAILED */, NG_DEV_MODE$1 &&
112
+ `Unable to create the animation due to the following errors:${errors.map(err => err.message).join('\n')}`);
113
+ }
114
+ function missingPlayer(id) {
115
+ return new ɵRuntimeError(3301 /* MISSING_PLAYER */, NG_DEV_MODE$1 && `Unable to find the timeline player referenced by ${id}`);
116
+ }
117
+ function missingTrigger(phase, name) {
118
+ return new ɵRuntimeError(3302 /* MISSING_TRIGGER */, NG_DEV_MODE$1 &&
119
+ `Unable to listen on the animation trigger event "${phase}" because the animation trigger "${name}" doesn\'t exist!`);
120
+ }
121
+ function missingEvent(name) {
122
+ return new ɵRuntimeError(3303 /* MISSING_EVENT */, NG_DEV_MODE$1 &&
123
+ `Unable to listen on the animation trigger "${name}" because the provided event is undefined!`);
124
+ }
125
+ function unsupportedTriggerEvent(phase, name) {
126
+ return new ɵRuntimeError(3400 /* UNSUPPORTED_TRIGGER_EVENT */, NG_DEV_MODE$1 &&
127
+ `The provided animation trigger event "${phase}" for the animation trigger "${name}" is not supported!`);
128
+ }
129
+ function unregisteredTrigger(name) {
130
+ return new ɵRuntimeError(3401 /* UNREGISTERED_TRIGGER */, NG_DEV_MODE$1 && `The provided animation trigger "${name}" has not been registered!`);
131
+ }
132
+ function triggerTransitionsFailed(errors) {
133
+ return new ɵRuntimeError(3402 /* TRIGGER_TRANSITIONS_FAILED */, NG_DEV_MODE$1 &&
134
+ `Unable to process animations due to the following failed trigger transitions\n ${errors.map(err => err.message).join('\n')}`);
135
+ }
136
+ function triggerParsingFailed(name, errors) {
137
+ return new ɵRuntimeError(3403 /* TRIGGER_PARSING_FAILED */, NG_DEV_MODE$1 &&
138
+ `Animation parsing for the ${name} trigger have failed:${LINE_START}${errors.map(err => err.message).join(LINE_START)}`);
139
+ }
140
+ function transitionFailed(name, errors) {
141
+ return new ɵRuntimeError(3505 /* TRANSITION_FAILED */, NG_DEV_MODE$1 &&
142
+ `@${name} has failed due to:\n ${errors.map(err => err.message).join('\n- ')}`);
143
+ }
144
+
145
+ /**
146
+ * @license
147
+ * Copyright Google LLC All Rights Reserved.
148
+ *
149
+ * Use of this source code is governed by an MIT-style license that can be
150
+ * found in the LICENSE file at https://angular.io/license
151
+ */
152
+ /**
153
+ * Set of all animatable CSS properties
154
+ *
155
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties
156
+ */
157
+ const ANIMATABLE_PROP_SET = new Set([
158
+ '-moz-outline-radius',
159
+ '-moz-outline-radius-bottomleft',
160
+ '-moz-outline-radius-bottomright',
161
+ '-moz-outline-radius-topleft',
162
+ '-moz-outline-radius-topright',
163
+ '-ms-grid-columns',
164
+ '-ms-grid-rows',
165
+ '-webkit-line-clamp',
166
+ '-webkit-text-fill-color',
167
+ '-webkit-text-stroke',
168
+ '-webkit-text-stroke-color',
169
+ 'accent-color',
170
+ 'all',
171
+ 'backdrop-filter',
172
+ 'background',
173
+ 'background-color',
174
+ 'background-position',
175
+ 'background-size',
176
+ 'block-size',
177
+ 'border',
178
+ 'border-block-end',
179
+ 'border-block-end-color',
180
+ 'border-block-end-width',
181
+ 'border-block-start',
182
+ 'border-block-start-color',
183
+ 'border-block-start-width',
184
+ 'border-bottom',
185
+ 'border-bottom-color',
186
+ 'border-bottom-left-radius',
187
+ 'border-bottom-right-radius',
188
+ 'border-bottom-width',
189
+ 'border-color',
190
+ 'border-end-end-radius',
191
+ 'border-end-start-radius',
192
+ 'border-image-outset',
193
+ 'border-image-slice',
194
+ 'border-image-width',
195
+ 'border-inline-end',
196
+ 'border-inline-end-color',
197
+ 'border-inline-end-width',
198
+ 'border-inline-start',
199
+ 'border-inline-start-color',
200
+ 'border-inline-start-width',
201
+ 'border-left',
202
+ 'border-left-color',
203
+ 'border-left-width',
204
+ 'border-radius',
205
+ 'border-right',
206
+ 'border-right-color',
207
+ 'border-right-width',
208
+ 'border-start-end-radius',
209
+ 'border-start-start-radius',
210
+ 'border-top',
211
+ 'border-top-color',
212
+ 'border-top-left-radius',
213
+ 'border-top-right-radius',
214
+ 'border-top-width',
215
+ 'border-width',
216
+ 'bottom',
217
+ 'box-shadow',
218
+ 'caret-color',
219
+ 'clip',
220
+ 'clip-path',
221
+ 'color',
222
+ 'column-count',
223
+ 'column-gap',
224
+ 'column-rule',
225
+ 'column-rule-color',
226
+ 'column-rule-width',
227
+ 'column-width',
228
+ 'columns',
229
+ 'filter',
230
+ 'flex',
231
+ 'flex-basis',
232
+ 'flex-grow',
233
+ 'flex-shrink',
234
+ 'font',
235
+ 'font-size',
236
+ 'font-size-adjust',
237
+ 'font-stretch',
238
+ 'font-variation-settings',
239
+ 'font-weight',
240
+ 'gap',
241
+ 'grid-column-gap',
242
+ 'grid-gap',
243
+ 'grid-row-gap',
244
+ 'grid-template-columns',
245
+ 'grid-template-rows',
246
+ 'height',
247
+ 'inline-size',
248
+ 'input-security',
249
+ 'inset',
250
+ 'inset-block',
251
+ 'inset-block-end',
252
+ 'inset-block-start',
253
+ 'inset-inline',
254
+ 'inset-inline-end',
255
+ 'inset-inline-start',
256
+ 'left',
257
+ 'letter-spacing',
258
+ 'line-clamp',
259
+ 'line-height',
260
+ 'margin',
261
+ 'margin-block-end',
262
+ 'margin-block-start',
263
+ 'margin-bottom',
264
+ 'margin-inline-end',
265
+ 'margin-inline-start',
266
+ 'margin-left',
267
+ 'margin-right',
268
+ 'margin-top',
269
+ 'mask',
270
+ 'mask-border',
271
+ 'mask-position',
272
+ 'mask-size',
273
+ 'max-block-size',
274
+ 'max-height',
275
+ 'max-inline-size',
276
+ 'max-lines',
277
+ 'max-width',
278
+ 'min-block-size',
279
+ 'min-height',
280
+ 'min-inline-size',
281
+ 'min-width',
282
+ 'object-position',
283
+ 'offset',
284
+ 'offset-anchor',
285
+ 'offset-distance',
286
+ 'offset-path',
287
+ 'offset-position',
288
+ 'offset-rotate',
289
+ 'opacity',
290
+ 'order',
291
+ 'outline',
292
+ 'outline-color',
293
+ 'outline-offset',
294
+ 'outline-width',
295
+ 'padding',
296
+ 'padding-block-end',
297
+ 'padding-block-start',
298
+ 'padding-bottom',
299
+ 'padding-inline-end',
300
+ 'padding-inline-start',
301
+ 'padding-left',
302
+ 'padding-right',
303
+ 'padding-top',
304
+ 'perspective',
305
+ 'perspective-origin',
306
+ 'right',
307
+ 'rotate',
308
+ 'row-gap',
309
+ 'scale',
310
+ 'scroll-margin',
311
+ 'scroll-margin-block',
312
+ 'scroll-margin-block-end',
313
+ 'scroll-margin-block-start',
314
+ 'scroll-margin-bottom',
315
+ 'scroll-margin-inline',
316
+ 'scroll-margin-inline-end',
317
+ 'scroll-margin-inline-start',
318
+ 'scroll-margin-left',
319
+ 'scroll-margin-right',
320
+ 'scroll-margin-top',
321
+ 'scroll-padding',
322
+ 'scroll-padding-block',
323
+ 'scroll-padding-block-end',
324
+ 'scroll-padding-block-start',
325
+ 'scroll-padding-bottom',
326
+ 'scroll-padding-inline',
327
+ 'scroll-padding-inline-end',
328
+ 'scroll-padding-inline-start',
329
+ 'scroll-padding-left',
330
+ 'scroll-padding-right',
331
+ 'scroll-padding-top',
332
+ 'scroll-snap-coordinate',
333
+ 'scroll-snap-destination',
334
+ 'scrollbar-color',
335
+ 'shape-image-threshold',
336
+ 'shape-margin',
337
+ 'shape-outside',
338
+ 'tab-size',
339
+ 'text-decoration',
340
+ 'text-decoration-color',
341
+ 'text-decoration-thickness',
342
+ 'text-emphasis',
343
+ 'text-emphasis-color',
344
+ 'text-indent',
345
+ 'text-shadow',
346
+ 'text-underline-offset',
347
+ 'top',
348
+ 'transform',
349
+ 'transform-origin',
350
+ 'translate',
351
+ 'vertical-align',
352
+ 'visibility',
353
+ 'width',
354
+ 'word-spacing',
355
+ 'z-index',
356
+ 'zoom',
357
+ ]);
10
358
 
11
359
  /**
12
360
  * @license
@@ -36,26 +384,26 @@ function optimizeGroupPlayer(players) {
36
384
  return new ɵAnimationGroupPlayer(players);
37
385
  }
38
386
  }
39
- function normalizeKeyframes(driver, normalizer, element, keyframes, preStyles = {}, postStyles = {}) {
387
+ function normalizeKeyframes$1(driver, normalizer, element, keyframes, preStyles = new Map(), postStyles = new Map()) {
40
388
  const errors = [];
41
389
  const normalizedKeyframes = [];
42
390
  let previousOffset = -1;
43
391
  let previousKeyframe = null;
44
392
  keyframes.forEach(kf => {
45
- const offset = kf['offset'];
393
+ const offset = kf.get('offset');
46
394
  const isSameOffset = offset == previousOffset;
47
- const normalizedKeyframe = (isSameOffset && previousKeyframe) || {};
48
- Object.keys(kf).forEach(prop => {
395
+ const normalizedKeyframe = (isSameOffset && previousKeyframe) || new Map();
396
+ kf.forEach((val, prop) => {
49
397
  let normalizedProp = prop;
50
- let normalizedValue = kf[prop];
398
+ let normalizedValue = val;
51
399
  if (prop !== 'offset') {
52
400
  normalizedProp = normalizer.normalizePropertyName(normalizedProp, errors);
53
401
  switch (normalizedValue) {
54
402
  case ɵPRE_STYLE:
55
- normalizedValue = preStyles[prop];
403
+ normalizedValue = preStyles.get(prop);
56
404
  break;
57
405
  case AUTO_STYLE:
58
- normalizedValue = postStyles[prop];
406
+ normalizedValue = postStyles.get(prop);
59
407
  break;
60
408
  default:
61
409
  normalizedValue =
@@ -63,7 +411,7 @@ function normalizeKeyframes(driver, normalizer, element, keyframes, preStyles =
63
411
  break;
64
412
  }
65
413
  }
66
- normalizedKeyframe[normalizedProp] = normalizedValue;
414
+ normalizedKeyframe.set(normalizedProp, normalizedValue);
67
415
  });
68
416
  if (!isSameOffset) {
69
417
  normalizedKeyframes.push(normalizedKeyframe);
@@ -72,8 +420,7 @@ function normalizeKeyframes(driver, normalizer, element, keyframes, preStyles =
72
420
  previousOffset = offset;
73
421
  });
74
422
  if (errors.length) {
75
- const LINE_START = '\n - ';
76
- throw new Error(`Unable to animate due to the following errors:${LINE_START}${errors.join(LINE_START)}`);
423
+ throw animationFailed(errors);
77
424
  }
78
425
  return normalizedKeyframes;
79
426
  }
@@ -103,32 +450,31 @@ function copyAnimationEvent(e, phaseName, player) {
103
450
  function makeAnimationEvent(element, triggerName, fromState, toState, phaseName = '', totalTime = 0, disabled) {
104
451
  return { element, triggerName, fromState, toState, phaseName, totalTime, disabled: !!disabled };
105
452
  }
106
- function getOrSetAsInMap(map, key, defaultValue) {
107
- let value;
108
- if (map instanceof Map) {
109
- value = map.get(key);
110
- if (!value) {
111
- map.set(key, value = defaultValue);
112
- }
113
- }
114
- else {
115
- value = map[key];
116
- if (!value) {
117
- value = map[key] = defaultValue;
118
- }
453
+ function getOrSetDefaultValue(map, key, defaultValue) {
454
+ let value = map.get(key);
455
+ if (!value) {
456
+ map.set(key, value = defaultValue);
119
457
  }
120
458
  return value;
121
459
  }
122
460
  function parseTimelineCommand(command) {
123
461
  const separatorPos = command.indexOf(':');
124
462
  const id = command.substring(1, separatorPos);
125
- const action = command.substr(separatorPos + 1);
463
+ const action = command.slice(separatorPos + 1);
126
464
  return [id, action];
127
465
  }
128
466
  let _contains = (elm1, elm2) => false;
129
467
  let _query = (element, selector, multi) => {
130
468
  return [];
131
469
  };
470
+ let _documentElement = null;
471
+ function getParentElement(element) {
472
+ const parent = element.parentNode || element.host; // consider host to support shadow DOM
473
+ if (parent === _documentElement) {
474
+ return null;
475
+ }
476
+ return parent;
477
+ }
132
478
  // Define utility methods for browsers and platform-server(domino) where Element
133
479
  // and utility methods exist.
134
480
  const _isNode = isNode();
@@ -137,12 +483,15 @@ if (_isNode || typeof Element !== 'undefined') {
137
483
  _contains = (elm1, elm2) => elm1.contains(elm2);
138
484
  }
139
485
  else {
486
+ // Read the document element in an IIFE that's been marked pure to avoid a top-level property
487
+ // read that may prevent tree-shaking.
488
+ _documentElement = /* @__PURE__ */ (() => document.documentElement)();
140
489
  _contains = (elm1, elm2) => {
141
- while (elm2 && elm2 !== document.documentElement) {
490
+ while (elm2) {
142
491
  if (elm2 === elm1) {
143
492
  return true;
144
493
  }
145
- elm2 = elm2.parentNode || elm2.host; // consider host to support shadow DOM
494
+ elm2 = getParentElement(elm2);
146
495
  }
147
496
  return false;
148
497
  };
@@ -171,12 +520,15 @@ function validateStyleProperty(prop) {
171
520
  if (_CACHED_BODY.style && !containsVendorPrefix(prop)) {
172
521
  result = prop in _CACHED_BODY.style;
173
522
  if (!result && _IS_WEBKIT) {
174
- const camelProp = 'Webkit' + prop.charAt(0).toUpperCase() + prop.substr(1);
523
+ const camelProp = 'Webkit' + prop.charAt(0).toUpperCase() + prop.slice(1);
175
524
  result = camelProp in _CACHED_BODY.style;
176
525
  }
177
526
  }
178
527
  return result;
179
528
  }
529
+ function validateWebAnimatableStyleProperty(prop) {
530
+ return ANIMATABLE_PROP_SET.has(prop);
531
+ }
180
532
  function getBodyNode() {
181
533
  if (typeof document != 'undefined') {
182
534
  return document.body;
@@ -185,13 +537,13 @@ function getBodyNode() {
185
537
  }
186
538
  const containsElement = _contains;
187
539
  const invokeQuery = _query;
188
- function hypenatePropsObject(object) {
189
- const newObj = {};
190
- Object.keys(object).forEach(prop => {
540
+ function hypenatePropsKeys(original) {
541
+ const newMap = new Map();
542
+ original.forEach((val, prop) => {
191
543
  const newProp = prop.replace(/([a-z])([A-Z])/g, '$1-$2');
192
- newObj[newProp] = object[prop];
544
+ newMap.set(newProp, val);
193
545
  });
194
- return newObj;
546
+ return newMap;
195
547
  }
196
548
 
197
549
  /**
@@ -215,6 +567,9 @@ class NoopAnimationDriver {
215
567
  containsElement(elm1, elm2) {
216
568
  return containsElement(elm1, elm2);
217
569
  }
570
+ getParentElement(element) {
571
+ return getParentElement(element);
572
+ }
218
573
  query(element, selector, multi) {
219
574
  return invokeQuery(element, selector, multi);
220
575
  }
@@ -225,9 +580,9 @@ class NoopAnimationDriver {
225
580
  return new NoopAnimationPlayer(duration, delay);
226
581
  }
227
582
  }
228
- NoopAnimationDriver.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.0", ngImport: i0, type: NoopAnimationDriver, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
229
- NoopAnimationDriver.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.0", ngImport: i0, type: NoopAnimationDriver });
230
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.0", ngImport: i0, type: NoopAnimationDriver, decorators: [{
583
+ NoopAnimationDriver.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: NoopAnimationDriver, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
584
+ NoopAnimationDriver.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: NoopAnimationDriver });
585
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: NoopAnimationDriver, decorators: [{
231
586
  type: Injectable
232
587
  }] });
233
588
  /**
@@ -244,7 +599,7 @@ AnimationDriver.NOOP = ( /* @__PURE__ */new NoopAnimationDriver());
244
599
  * Use of this source code is governed by an MIT-style license that can be
245
600
  * found in the LICENSE file at https://angular.io/license
246
601
  */
247
- const ONE_SECOND$1 = 1000;
602
+ const ONE_SECOND = 1000;
248
603
  const SUBSTITUTION_EXPR_START = '{{';
249
604
  const SUBSTITUTION_EXPR_END = '}}';
250
605
  const ENTER_CLASSNAME = 'ng-enter';
@@ -264,7 +619,7 @@ function resolveTimingValue(value) {
264
619
  function _convertTimeValueToMS(value, unit) {
265
620
  switch (unit) {
266
621
  case 's':
267
- return value * ONE_SECOND$1;
622
+ return value * ONE_SECOND;
268
623
  default: // ms or something else
269
624
  return value;
270
625
  }
@@ -282,7 +637,7 @@ function parseTimeExpression(exp, errors, allowNegativeValues) {
282
637
  if (typeof exp === 'string') {
283
638
  const matches = exp.match(regex);
284
639
  if (matches === null) {
285
- errors.push(`The provided timing value "${exp}" is invalid.`);
640
+ errors.push(invalidTimingValue(exp));
286
641
  return { duration: 0, delay: 0, easing: '' };
287
642
  }
288
643
  duration = _convertTimeValueToMS(parseFloat(matches[1]), matches[2]);
@@ -302,15 +657,15 @@ function parseTimeExpression(exp, errors, allowNegativeValues) {
302
657
  let containsErrors = false;
303
658
  let startIndex = errors.length;
304
659
  if (duration < 0) {
305
- errors.push(`Duration values below 0 are not allowed for this animation step.`);
660
+ errors.push(negativeStepValue());
306
661
  containsErrors = true;
307
662
  }
308
663
  if (delay < 0) {
309
- errors.push(`Delay values below 0 are not allowed for this animation step.`);
664
+ errors.push(negativeDelayValue());
310
665
  containsErrors = true;
311
666
  }
312
667
  if (containsErrors) {
313
- errors.splice(startIndex, 0, `The provided timing value "${exp}" is invalid.`);
668
+ errors.splice(startIndex, 0, invalidTimingValue(exp));
314
669
  }
315
670
  }
316
671
  return { duration, delay, easing };
@@ -321,27 +676,41 @@ function copyObj(obj, destination = {}) {
321
676
  });
322
677
  return destination;
323
678
  }
679
+ function convertToMap(obj) {
680
+ const styleMap = new Map();
681
+ Object.keys(obj).forEach(prop => {
682
+ const val = obj[prop];
683
+ styleMap.set(prop, val);
684
+ });
685
+ return styleMap;
686
+ }
687
+ function normalizeKeyframes(keyframes) {
688
+ if (!keyframes.length) {
689
+ return [];
690
+ }
691
+ if (keyframes[0] instanceof Map) {
692
+ return keyframes;
693
+ }
694
+ return keyframes.map(kf => convertToMap(kf));
695
+ }
324
696
  function normalizeStyles(styles) {
325
- const normalizedStyles = {};
697
+ const normalizedStyles = new Map();
326
698
  if (Array.isArray(styles)) {
327
- styles.forEach(data => copyStyles(data, false, normalizedStyles));
699
+ styles.forEach(data => copyStyles(data, normalizedStyles));
328
700
  }
329
701
  else {
330
- copyStyles(styles, false, normalizedStyles);
702
+ copyStyles(styles, normalizedStyles);
331
703
  }
332
704
  return normalizedStyles;
333
705
  }
334
- function copyStyles(styles, readPrototype, destination = {}) {
335
- if (readPrototype) {
336
- // we make use of a for-in loop so that the
337
- // prototypically inherited properties are
338
- // revealed from the backFill map
339
- for (let prop in styles) {
340
- destination[prop] = styles[prop];
706
+ function copyStyles(styles, destination = new Map(), backfill) {
707
+ if (backfill) {
708
+ for (let [prop, val] of backfill) {
709
+ destination.set(prop, val);
341
710
  }
342
711
  }
343
- else {
344
- copyObj(styles, destination);
712
+ for (let [prop, val] of styles) {
713
+ destination.set(prop, val);
345
714
  }
346
715
  return destination;
347
716
  }
@@ -377,12 +746,12 @@ function writeStyleAttribute(element) {
377
746
  }
378
747
  function setStyles(element, styles, formerStyles) {
379
748
  if (element['style']) {
380
- Object.keys(styles).forEach(prop => {
749
+ styles.forEach((val, prop) => {
381
750
  const camelProp = dashCaseToCamelCase(prop);
382
- if (formerStyles && !formerStyles.hasOwnProperty(prop)) {
383
- formerStyles[prop] = element.style[camelProp];
751
+ if (formerStyles && !formerStyles.has(prop)) {
752
+ formerStyles.set(prop, element.style[camelProp]);
384
753
  }
385
- element.style[camelProp] = styles[prop];
754
+ element.style[camelProp] = val;
386
755
  });
387
756
  // On the server set the 'style' attribute since it's not automatically reflected.
388
757
  if (isNode()) {
@@ -392,7 +761,7 @@ function setStyles(element, styles, formerStyles) {
392
761
  }
393
762
  function eraseStyles(element, styles) {
394
763
  if (element['style']) {
395
- Object.keys(styles).forEach(prop => {
764
+ styles.forEach((_, prop) => {
396
765
  const camelProp = dashCaseToCamelCase(prop);
397
766
  element.style[camelProp] = '';
398
767
  });
@@ -416,7 +785,7 @@ function validateStyleParams(value, options, errors) {
416
785
  if (matches.length) {
417
786
  matches.forEach(varName => {
418
787
  if (!params.hasOwnProperty(varName)) {
419
- errors.push(`Unable to resolve the local animation param ${varName} in the given list of values`);
788
+ errors.push(invalidStyleParams(varName));
420
789
  }
421
790
  });
422
791
  }
@@ -438,8 +807,8 @@ function interpolateParams(value, params, errors) {
438
807
  const str = original.replace(PARAM_REGEX, (_, varName) => {
439
808
  let localVal = params[varName];
440
809
  // this means that the value was never overridden by the data passed in by the user
441
- if (!params.hasOwnProperty(varName)) {
442
- errors.push(`Please provide a value for the animation param ${varName}`);
810
+ if (localVal == null) {
811
+ errors.push(invalidParamValue(varName));
443
812
  localVal = '';
444
813
  }
445
814
  return localVal.toString();
@@ -467,23 +836,19 @@ function allowPreviousPlayerStylesMerge(duration, delay) {
467
836
  return duration === 0 || delay === 0;
468
837
  }
469
838
  function balancePreviousStylesIntoKeyframes(element, keyframes, previousStyles) {
470
- const previousStyleProps = Object.keys(previousStyles);
471
- if (previousStyleProps.length && keyframes.length) {
839
+ if (previousStyles.size && keyframes.length) {
472
840
  let startingKeyframe = keyframes[0];
473
841
  let missingStyleProps = [];
474
- previousStyleProps.forEach(prop => {
475
- if (!startingKeyframe.hasOwnProperty(prop)) {
842
+ previousStyles.forEach((val, prop) => {
843
+ if (!startingKeyframe.has(prop)) {
476
844
  missingStyleProps.push(prop);
477
845
  }
478
- startingKeyframe[prop] = previousStyles[prop];
846
+ startingKeyframe.set(prop, val);
479
847
  });
480
848
  if (missingStyleProps.length) {
481
- // tslint:disable-next-line
482
- for (var i = 1; i < keyframes.length; i++) {
849
+ for (let i = 1; i < keyframes.length; i++) {
483
850
  let kf = keyframes[i];
484
- missingStyleProps.forEach(function (prop) {
485
- kf[prop] = computeStyle(element, prop);
486
- });
851
+ missingStyleProps.forEach(prop => kf.set(prop, computeStyle(element, prop)));
487
852
  }
488
853
  }
489
854
  }
@@ -518,13 +883,51 @@ function visitDslNode(visitor, node, context) {
518
883
  case 12 /* Stagger */:
519
884
  return visitor.visitStagger(node, context);
520
885
  default:
521
- throw new Error(`Unable to resolve animation metadata node #${node.type}`);
886
+ throw invalidNodeType(node.type);
522
887
  }
523
888
  }
524
889
  function computeStyle(element, prop) {
525
890
  return window.getComputedStyle(element)[prop];
526
891
  }
527
892
 
893
+ /**
894
+ * @license
895
+ * Copyright Google LLC All Rights Reserved.
896
+ *
897
+ * Use of this source code is governed by an MIT-style license that can be
898
+ * found in the LICENSE file at https://angular.io/license
899
+ */
900
+ const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
901
+ function createListOfWarnings(warnings) {
902
+ const LINE_START = '\n - ';
903
+ return `${LINE_START}${warnings.filter(Boolean).map(warning => warning).join(LINE_START)}`;
904
+ }
905
+ function warnValidation(warnings) {
906
+ NG_DEV_MODE && console.warn(`animation validation warnings:${createListOfWarnings(warnings)}`);
907
+ }
908
+ function warnTriggerBuild(name, warnings) {
909
+ NG_DEV_MODE &&
910
+ console.warn(`The animation trigger "${name}" has built with the following warnings:${createListOfWarnings(warnings)}`);
911
+ }
912
+ function warnRegister(warnings) {
913
+ NG_DEV_MODE &&
914
+ console.warn(`Animation built with the following warnings:${createListOfWarnings(warnings)}`);
915
+ }
916
+ function triggerParsingWarnings(name, warnings) {
917
+ NG_DEV_MODE &&
918
+ console.warn(`Animation parsing for the ${name} trigger presents the following warnings:${createListOfWarnings(warnings)}`);
919
+ }
920
+ function pushUnrecognizedPropertiesWarning(warnings, props) {
921
+ if (ngDevMode && props.length) {
922
+ warnings.push(`The following provided properties are not recognized: ${props.join(', ')}`);
923
+ }
924
+ }
925
+ function pushNonAnimatablePropertiesWarning(warnings, props) {
926
+ if (props.length) {
927
+ warnings.push(`The following provided properties are not animatable: ${props.join(', ')}\n (see: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties)`);
928
+ }
929
+ }
930
+
528
931
  /**
529
932
  * @license
530
933
  * Copyright Google LLC All Rights Reserved.
@@ -554,7 +957,7 @@ function parseInnerTransitionStr(eventStr, expressions, errors) {
554
957
  }
555
958
  const match = eventStr.match(/^(\*|[-\w]+)\s*(<?[=-]>)\s*(\*|[-\w]+)$/);
556
959
  if (match == null || match.length < 4) {
557
- errors.push(`The provided transition expression "${eventStr}" is not supported`);
960
+ errors.push(invalidExpression(eventStr));
558
961
  return expressions;
559
962
  }
560
963
  const fromState = match[1];
@@ -577,7 +980,7 @@ function parseAnimationAlias(alias, errors) {
577
980
  case ':decrement':
578
981
  return (fromState, toState) => parseFloat(toState) < parseFloat(fromState);
579
982
  default:
580
- errors.push(`The transition alias value "${alias}" is not supported`);
983
+ errors.push(invalidTransitionAlias(alias));
581
984
  return '* => *';
582
985
  }
583
986
  }
@@ -648,23 +1051,31 @@ const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g');
648
1051
  *
649
1052
  * Otherwise an error will be thrown.
650
1053
  */
651
- function buildAnimationAst(driver, metadata, errors) {
652
- return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
1054
+ function buildAnimationAst(driver, metadata, errors, warnings) {
1055
+ return new AnimationAstBuilderVisitor(driver).build(metadata, errors, warnings);
653
1056
  }
654
1057
  const ROOT_SELECTOR = '';
655
1058
  class AnimationAstBuilderVisitor {
656
1059
  constructor(_driver) {
657
1060
  this._driver = _driver;
658
1061
  }
659
- build(metadata, errors) {
1062
+ build(metadata, errors, warnings) {
660
1063
  const context = new AnimationAstBuilderContext(errors);
661
1064
  this._resetContextStyleTimingState(context);
662
- return visitDslNode(this, normalizeAnimationEntry(metadata), context);
1065
+ const ast = visitDslNode(this, normalizeAnimationEntry(metadata), context);
1066
+ if (context.unsupportedCSSPropertiesFound.size) {
1067
+ pushUnrecognizedPropertiesWarning(warnings, [...context.unsupportedCSSPropertiesFound.keys()]);
1068
+ }
1069
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
1070
+ context.nonAnimatableCSSPropertiesFound.size) {
1071
+ pushNonAnimatablePropertiesWarning(warnings, [...context.nonAnimatableCSSPropertiesFound.keys()]);
1072
+ }
1073
+ return ast;
663
1074
  }
664
1075
  _resetContextStyleTimingState(context) {
665
1076
  context.currentQuerySelector = ROOT_SELECTOR;
666
- context.collectedStyles = {};
667
- context.collectedStyles[ROOT_SELECTOR] = {};
1077
+ context.collectedStyles = new Map();
1078
+ context.collectedStyles.set(ROOT_SELECTOR, new Map());
668
1079
  context.currentTime = 0;
669
1080
  }
670
1081
  visitTrigger(metadata, context) {
@@ -673,7 +1084,7 @@ class AnimationAstBuilderVisitor {
673
1084
  const states = [];
674
1085
  const transitions = [];
675
1086
  if (metadata.name.charAt(0) == '@') {
676
- context.errors.push('animation triggers cannot be prefixed with an `@` sign (e.g. trigger(\'@foo\', [...]))');
1087
+ context.errors.push(invalidTrigger());
677
1088
  }
678
1089
  metadata.definitions.forEach(def => {
679
1090
  this._resetContextStyleTimingState(context);
@@ -693,7 +1104,7 @@ class AnimationAstBuilderVisitor {
693
1104
  transitions.push(transition);
694
1105
  }
695
1106
  else {
696
- context.errors.push('only state() and transition() definitions can sit inside of a trigger()');
1107
+ context.errors.push(invalidDefinition());
697
1108
  }
698
1109
  });
699
1110
  return {
@@ -712,11 +1123,10 @@ class AnimationAstBuilderVisitor {
712
1123
  if (styleAst.containsDynamicStyles) {
713
1124
  const missingSubs = new Set();
714
1125
  const params = astParams || {};
715
- styleAst.styles.forEach(value => {
716
- if (isObject(value)) {
717
- const stylesObj = value;
718
- Object.keys(stylesObj).forEach(prop => {
719
- extractStyleParams(stylesObj[prop]).forEach(sub => {
1126
+ styleAst.styles.forEach(style => {
1127
+ if (style instanceof Map) {
1128
+ style.forEach(value => {
1129
+ extractStyleParams(value).forEach(sub => {
720
1130
  if (!params.hasOwnProperty(sub)) {
721
1131
  missingSubs.add(sub);
722
1132
  }
@@ -726,8 +1136,7 @@ class AnimationAstBuilderVisitor {
726
1136
  });
727
1137
  if (missingSubs.size) {
728
1138
  const missingSubsArr = iteratorToArray(missingSubs.values());
729
- context.errors.push(`state("${metadata
730
- .name}", ...) must define default values for all the following style substitutions: ${missingSubsArr.join(', ')}`);
1139
+ context.errors.push(invalidState(metadata.name, missingSubsArr));
731
1140
  }
732
1141
  }
733
1142
  return {
@@ -813,37 +1222,30 @@ class AnimationAstBuilderVisitor {
813
1222
  }
814
1223
  _makeStyleAst(metadata, context) {
815
1224
  const styles = [];
816
- if (Array.isArray(metadata.styles)) {
817
- metadata.styles.forEach(styleTuple => {
818
- if (typeof styleTuple == 'string') {
819
- if (styleTuple == AUTO_STYLE) {
820
- styles.push(styleTuple);
821
- }
822
- else {
823
- context.errors.push(`The provided style string value ${styleTuple} is not allowed.`);
824
- }
1225
+ const metadataStyles = Array.isArray(metadata.styles) ? metadata.styles : [metadata.styles];
1226
+ for (let styleTuple of metadataStyles) {
1227
+ if (typeof styleTuple === 'string') {
1228
+ if (styleTuple === AUTO_STYLE) {
1229
+ styles.push(styleTuple);
825
1230
  }
826
1231
  else {
827
- styles.push(styleTuple);
1232
+ context.errors.push(invalidStyleValue(styleTuple));
828
1233
  }
829
- });
830
- }
831
- else {
832
- styles.push(metadata.styles);
1234
+ }
1235
+ else {
1236
+ styles.push(convertToMap(styleTuple));
1237
+ }
833
1238
  }
834
1239
  let containsDynamicStyles = false;
835
1240
  let collectedEasing = null;
836
1241
  styles.forEach(styleData => {
837
- if (isObject(styleData)) {
838
- const styleMap = styleData;
839
- const easing = styleMap['easing'];
840
- if (easing) {
841
- collectedEasing = easing;
842
- delete styleMap['easing'];
1242
+ if (styleData instanceof Map) {
1243
+ if (styleData.has('easing')) {
1244
+ collectedEasing = styleData.get('easing');
1245
+ styleData.delete('easing');
843
1246
  }
844
1247
  if (!containsDynamicStyles) {
845
- for (let prop in styleMap) {
846
- const value = styleMap[prop];
1248
+ for (let value of styleData.values()) {
847
1249
  if (value.toString().indexOf(SUBSTITUTION_EXPR_START) >= 0) {
848
1250
  containsDynamicStyles = true;
849
1251
  break;
@@ -869,21 +1271,32 @@ class AnimationAstBuilderVisitor {
869
1271
  startTime -= timings.duration + timings.delay;
870
1272
  }
871
1273
  ast.styles.forEach(tuple => {
872
- if (typeof tuple == 'string')
1274
+ if (typeof tuple === 'string')
873
1275
  return;
874
- Object.keys(tuple).forEach(prop => {
1276
+ tuple.forEach((value, prop) => {
875
1277
  if (!this._driver.validateStyleProperty(prop)) {
876
- context.errors.push(`The provided animation property "${prop}" is not a supported CSS property for animations`);
1278
+ tuple.delete(prop);
1279
+ context.unsupportedCSSPropertiesFound.add(prop);
877
1280
  return;
878
1281
  }
879
- const collectedStyles = context.collectedStyles[context.currentQuerySelector];
880
- const collectedEntry = collectedStyles[prop];
1282
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
1283
+ this._driver.validateAnimatableStyleProperty) {
1284
+ if (!this._driver.validateAnimatableStyleProperty(prop)) {
1285
+ context.nonAnimatableCSSPropertiesFound.add(prop);
1286
+ // note: non animatable properties are not removed for the tuple just in case they are
1287
+ // categorized as non animatable but can actually be animated
1288
+ return;
1289
+ }
1290
+ }
1291
+ // This is guaranteed to have a defined Map at this querySelector location making it
1292
+ // safe to add the assertion here. It is set as a default empty map in prior methods.
1293
+ const collectedStyles = context.collectedStyles.get(context.currentQuerySelector);
1294
+ const collectedEntry = collectedStyles.get(prop);
881
1295
  let updateCollectedStyle = true;
882
1296
  if (collectedEntry) {
883
1297
  if (startTime != endTime && startTime >= collectedEntry.startTime &&
884
1298
  endTime <= collectedEntry.endTime) {
885
- context.errors.push(`The CSS property "${prop}" that exists between the times of "${collectedEntry.startTime}ms" and "${collectedEntry
886
- .endTime}ms" is also being animated in a parallel animation between the times of "${startTime}ms" and "${endTime}ms"`);
1299
+ context.errors.push(invalidParallelAnimation(prop, collectedEntry.startTime, collectedEntry.endTime, startTime, endTime));
887
1300
  updateCollectedStyle = false;
888
1301
  }
889
1302
  // we always choose the smaller start time value since we
@@ -892,10 +1305,10 @@ class AnimationAstBuilderVisitor {
892
1305
  startTime = collectedEntry.startTime;
893
1306
  }
894
1307
  if (updateCollectedStyle) {
895
- collectedStyles[prop] = { startTime, endTime };
1308
+ collectedStyles.set(prop, { startTime, endTime });
896
1309
  }
897
1310
  if (context.options) {
898
- validateStyleParams(tuple[prop], context.options, context.errors);
1311
+ validateStyleParams(value, context.options, context.errors);
899
1312
  }
900
1313
  });
901
1314
  });
@@ -903,7 +1316,7 @@ class AnimationAstBuilderVisitor {
903
1316
  visitKeyframes(metadata, context) {
904
1317
  const ast = { type: 5 /* Keyframes */, styles: [], options: null };
905
1318
  if (!context.currentAnimateTimings) {
906
- context.errors.push(`keyframes() must be placed inside of a call to animate()`);
1319
+ context.errors.push(invalidKeyframes());
907
1320
  return ast;
908
1321
  }
909
1322
  const MAX_KEYFRAME_OFFSET = 1;
@@ -927,15 +1340,15 @@ class AnimationAstBuilderVisitor {
927
1340
  return style;
928
1341
  });
929
1342
  if (keyframesOutOfRange) {
930
- context.errors.push(`Please ensure that all keyframe offsets are between 0 and 1`);
1343
+ context.errors.push(invalidOffset());
931
1344
  }
932
1345
  if (offsetsOutOfOrder) {
933
- context.errors.push(`Please ensure that all keyframe offsets are in order`);
1346
+ context.errors.push(keyframeOffsetsOutOfOrder());
934
1347
  }
935
1348
  const length = metadata.steps.length;
936
1349
  let generatedOffset = 0;
937
1350
  if (totalKeyframesWithOffsets > 0 && totalKeyframesWithOffsets < length) {
938
- context.errors.push(`Not all style() steps within the declared keyframes() contain offsets`);
1351
+ context.errors.push(keyframesMissingOffsets());
939
1352
  }
940
1353
  else if (totalKeyframesWithOffsets == 0) {
941
1354
  generatedOffset = MAX_KEYFRAME_OFFSET / (length - 1);
@@ -984,7 +1397,7 @@ class AnimationAstBuilderVisitor {
984
1397
  const [selector, includeSelf] = normalizeSelector(metadata.selector);
985
1398
  context.currentQuerySelector =
986
1399
  parentSelector.length ? (parentSelector + ' ' + selector) : selector;
987
- getOrSetAsInMap(context.collectedStyles, context.currentQuerySelector, {});
1400
+ getOrSetDefaultValue(context.collectedStyles, context.currentQuerySelector, new Map());
988
1401
  const animation = visitDslNode(this, normalizeAnimationEntry(metadata.animation), context);
989
1402
  context.currentQuery = null;
990
1403
  context.currentQuerySelector = parentSelector;
@@ -1001,7 +1414,7 @@ class AnimationAstBuilderVisitor {
1001
1414
  }
1002
1415
  visitStagger(metadata, context) {
1003
1416
  if (!context.currentQuery) {
1004
- context.errors.push(`stagger() can only be used inside of query()`);
1417
+ context.errors.push(invalidStagger());
1005
1418
  }
1006
1419
  const timings = metadata.timings === 'full' ?
1007
1420
  { duration: 0, delay: 0, easing: 'full' } :
@@ -1022,7 +1435,7 @@ function normalizeSelector(selector) {
1022
1435
  // Note: the :enter and :leave aren't normalized here since those
1023
1436
  // selectors are filled in at runtime during timeline building
1024
1437
  selector = selector.replace(/@\*/g, NG_TRIGGER_SELECTOR)
1025
- .replace(/@\w+/g, match => NG_TRIGGER_SELECTOR + '-' + match.substr(1))
1438
+ .replace(/@\w+/g, match => NG_TRIGGER_SELECTOR + '-' + match.slice(1))
1026
1439
  .replace(/:animating/g, NG_ANIMATING_SELECTOR);
1027
1440
  return [selector, hasAmpersand];
1028
1441
  }
@@ -1039,8 +1452,10 @@ class AnimationAstBuilderContext {
1039
1452
  this.currentQuerySelector = null;
1040
1453
  this.currentAnimateTimings = null;
1041
1454
  this.currentTime = 0;
1042
- this.collectedStyles = {};
1455
+ this.collectedStyles = new Map();
1043
1456
  this.options = null;
1457
+ this.unsupportedCSSPropertiesFound = new Set();
1458
+ this.nonAnimatableCSSPropertiesFound = new Set();
1044
1459
  }
1045
1460
  }
1046
1461
  function consumeOffset(styles) {
@@ -1049,29 +1464,25 @@ function consumeOffset(styles) {
1049
1464
  let offset = null;
1050
1465
  if (Array.isArray(styles)) {
1051
1466
  styles.forEach(styleTuple => {
1052
- if (isObject(styleTuple) && styleTuple.hasOwnProperty('offset')) {
1467
+ if (styleTuple instanceof Map && styleTuple.has('offset')) {
1053
1468
  const obj = styleTuple;
1054
- offset = parseFloat(obj['offset']);
1055
- delete obj['offset'];
1469
+ offset = parseFloat(obj.get('offset'));
1470
+ obj.delete('offset');
1056
1471
  }
1057
1472
  });
1058
1473
  }
1059
- else if (isObject(styles) && styles.hasOwnProperty('offset')) {
1474
+ else if (styles instanceof Map && styles.has('offset')) {
1060
1475
  const obj = styles;
1061
- offset = parseFloat(obj['offset']);
1062
- delete obj['offset'];
1476
+ offset = parseFloat(obj.get('offset'));
1477
+ obj.delete('offset');
1063
1478
  }
1064
1479
  return offset;
1065
1480
  }
1066
- function isObject(value) {
1067
- return !Array.isArray(value) && typeof value == 'object';
1068
- }
1069
1481
  function constructTimingAst(value, errors) {
1070
- let timings = null;
1071
1482
  if (value.hasOwnProperty('duration')) {
1072
- timings = value;
1483
+ return value;
1073
1484
  }
1074
- else if (typeof value == 'number') {
1485
+ if (typeof value == 'number') {
1075
1486
  const duration = resolveTiming(value, errors).duration;
1076
1487
  return makeTimingAst(duration, 0, '');
1077
1488
  }
@@ -1083,7 +1494,7 @@ function constructTimingAst(value, errors) {
1083
1494
  ast.strValue = strValue;
1084
1495
  return ast;
1085
1496
  }
1086
- timings = timings || resolveTiming(strValue, errors);
1497
+ const timings = resolveTiming(strValue, errors);
1087
1498
  return makeTimingAst(timings.duration, timings.delay, timings.easing);
1088
1499
  }
1089
1500
  function normalizeAnimationOptions(options) {
@@ -1173,7 +1584,7 @@ const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
1173
1584
  * ```
1174
1585
  *
1175
1586
  * For this operation to cover the combination of animation verbs (style, animate, group, etc...) a
1176
- * combination of prototypical inheritance, AST traversal and merge-sort-like algorithms are used.
1587
+ * combination of AST traversal and merge-sort-like algorithms are used.
1177
1588
  *
1178
1589
  * [AST Traversal]
1179
1590
  * Each of the animation verbs, when executed, will return an string-map object representing what
@@ -1219,23 +1630,18 @@ const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
1219
1630
  * from all previous animation steps. Therefore when a keyframe is created it would also be missing
1220
1631
  * from all previous keyframes up until where it is first used. For the timeline keyframe generation
1221
1632
  * to properly fill in the style it will place the previous value (the value from the parent
1222
- * timeline) or a default value of `*` into the backFill object. Given that each of the keyframe
1223
- * styles is an object that prototypically inherits from the backFill object, this means that if a
1224
- * value is added into the backFill then it will automatically propagate any missing values to all
1225
- * keyframes. Therefore the missing `height` value will be properly filled into the already
1226
- * processed keyframes.
1633
+ * timeline) or a default value of `*` into the backFill map. The `copyStyles` method in util.ts
1634
+ * handles propagating that backfill map to the styles object.
1227
1635
  *
1228
1636
  * When a sub-timeline is created it will have its own backFill property. This is done so that
1229
1637
  * styles present within the sub-timeline do not accidentally seep into the previous/future timeline
1230
1638
  * keyframes
1231
1639
  *
1232
- * (For prototypically-inherited contents to be detected a `for(i in obj)` loop must be used.)
1233
- *
1234
1640
  * [Validation]
1235
1641
  * The code in this file is not responsible for validation. That functionality happens with within
1236
1642
  * the `AnimationValidatorVisitor` code.
1237
1643
  */
1238
- function buildAnimationTimelines(driver, rootElement, ast, enterClassName, leaveClassName, startingStyles = {}, finalStyles = {}, options, subInstructions, errors = []) {
1644
+ function buildAnimationTimelines(driver, rootElement, ast, enterClassName, leaveClassName, startingStyles = new Map(), finalStyles = new Map(), options, subInstructions, errors = []) {
1239
1645
  return new AnimationTimelineBuilderVisitor().buildKeyframes(driver, rootElement, ast, enterClassName, leaveClassName, startingStyles, finalStyles, options, subInstructions, errors);
1240
1646
  }
1241
1647
  class AnimationTimelineBuilderVisitor {
@@ -1243,15 +1649,17 @@ class AnimationTimelineBuilderVisitor {
1243
1649
  subInstructions = subInstructions || new ElementInstructionMap();
1244
1650
  const context = new AnimationTimelineContext(driver, rootElement, subInstructions, enterClassName, leaveClassName, errors, []);
1245
1651
  context.options = options;
1652
+ const delay = options.delay ? resolveTimingValue(options.delay) : 0;
1653
+ context.currentTimeline.delayNextStep(delay);
1246
1654
  context.currentTimeline.setStyles([startingStyles], null, context.errors, options);
1247
1655
  visitDslNode(this, ast, context);
1248
1656
  // this checks to see if an actual animation happened
1249
1657
  const timelines = context.timelines.filter(timeline => timeline.containsAnimation());
1250
- if (Object.keys(finalStyles).length) {
1251
- // note: we just want to apply the final styles for the rootElement, so we do not
1252
- // just apply the styles to the last timeline but the last timeline which
1253
- // element is the root one (basically `*`-styles are replaced with the actual
1254
- // state style values only for the root element)
1658
+ // note: we just want to apply the final styles for the rootElement, so we do not
1659
+ // just apply the styles to the last timeline but the last timeline which
1660
+ // element is the root one (basically `*`-styles are replaced with the actual
1661
+ // state style values only for the root element)
1662
+ if (timelines.length && finalStyles.size) {
1255
1663
  let lastRootTimeline;
1256
1664
  for (let i = timelines.length - 1; i >= 0; i--) {
1257
1665
  const timeline = timelines[i];
@@ -1264,8 +1672,9 @@ class AnimationTimelineBuilderVisitor {
1264
1672
  lastRootTimeline.setStyles([finalStyles], null, context.errors, options);
1265
1673
  }
1266
1674
  }
1267
- return timelines.length ? timelines.map(timeline => timeline.buildKeyframes()) :
1268
- [createTimelineInstruction(rootElement, [], [], [], 0, 0, '', false)];
1675
+ return timelines.length ?
1676
+ timelines.map(timeline => timeline.buildKeyframes()) :
1677
+ [createTimelineInstruction(rootElement, [], [], [], 0, delay, '', false)];
1269
1678
  }
1270
1679
  visitTrigger(ast, context) {
1271
1680
  // these values are not visited in this AST
@@ -1401,7 +1810,7 @@ class AnimationTimelineBuilderVisitor {
1401
1810
  const timings = context.currentAnimateTimings;
1402
1811
  // this is a special case for when a style() call
1403
1812
  // directly follows an animate() call (but not inside of an animate() call)
1404
- if (!timings && timeline.getCurrentStyleProperties().length) {
1813
+ if (!timings && timeline.hasCurrentStyleProperties()) {
1405
1814
  timeline.forwardFrame();
1406
1815
  }
1407
1816
  const easing = (timings && timings.easing) || ast.easing;
@@ -1442,7 +1851,7 @@ class AnimationTimelineBuilderVisitor {
1442
1851
  const delay = options.delay ? resolveTimingValue(options.delay) : 0;
1443
1852
  if (delay &&
1444
1853
  (context.previousNode.type === 6 /* Style */ ||
1445
- (startTime == 0 && context.currentTimeline.getCurrentStyleProperties().length))) {
1854
+ (startTime == 0 && context.currentTimeline.hasCurrentStyleProperties()))) {
1446
1855
  context.currentTimeline.snapshotCurrentStyles();
1447
1856
  context.previousNode = DEFAULT_NOOP_PREVIOUS_NODE;
1448
1857
  }
@@ -1624,7 +2033,7 @@ class AnimationTimelineContext {
1624
2033
  results.push(...elements);
1625
2034
  }
1626
2035
  if (!optional && results.length == 0) {
1627
- errors.push(`\`query("${originalSelector}")\` returned zero elements. (Use \`query("${originalSelector}", { optional: true })\` if you wish to allow this.)`);
2036
+ errors.push(invalidQuery(originalSelector));
1628
2037
  }
1629
2038
  return results;
1630
2039
  }
@@ -1636,17 +2045,17 @@ class TimelineBuilder {
1636
2045
  this.startTime = startTime;
1637
2046
  this._elementTimelineStylesLookup = _elementTimelineStylesLookup;
1638
2047
  this.duration = 0;
1639
- this._previousKeyframe = {};
1640
- this._currentKeyframe = {};
2048
+ this._previousKeyframe = new Map();
2049
+ this._currentKeyframe = new Map();
1641
2050
  this._keyframes = new Map();
1642
- this._styleSummary = {};
1643
- this._pendingStyles = {};
1644
- this._backFill = {};
2051
+ this._styleSummary = new Map();
2052
+ this._localTimelineStyles = new Map();
2053
+ this._pendingStyles = new Map();
2054
+ this._backFill = new Map();
1645
2055
  this._currentEmptyStepKeyframe = null;
1646
2056
  if (!this._elementTimelineStylesLookup) {
1647
2057
  this._elementTimelineStylesLookup = new Map();
1648
2058
  }
1649
- this._localTimelineStyles = Object.create(this._backFill, {});
1650
2059
  this._globalTimelineStyles = this._elementTimelineStylesLookup.get(element);
1651
2060
  if (!this._globalTimelineStyles) {
1652
2061
  this._globalTimelineStyles = this._localTimelineStyles;
@@ -1659,13 +2068,13 @@ class TimelineBuilder {
1659
2068
  case 0:
1660
2069
  return false;
1661
2070
  case 1:
1662
- return this.getCurrentStyleProperties().length > 0;
2071
+ return this.hasCurrentStyleProperties();
1663
2072
  default:
1664
2073
  return true;
1665
2074
  }
1666
2075
  }
1667
- getCurrentStyleProperties() {
1668
- return Object.keys(this._currentKeyframe);
2076
+ hasCurrentStyleProperties() {
2077
+ return this._currentKeyframe.size > 0;
1669
2078
  }
1670
2079
  get currentTime() {
1671
2080
  return this.startTime + this.duration;
@@ -1675,7 +2084,7 @@ class TimelineBuilder {
1675
2084
  // and that style() step is the very first style() value in the animation
1676
2085
  // then we need to make a copy of the keyframe [0, copy, 1] so that the delay
1677
2086
  // properly applies the style() values to work with the stagger...
1678
- const hasPreStyleStep = this._keyframes.size == 1 && Object.keys(this._pendingStyles).length;
2087
+ const hasPreStyleStep = this._keyframes.size === 1 && this._pendingStyles.size;
1679
2088
  if (this.duration || hasPreStyleStep) {
1680
2089
  this.forwardTime(this.currentTime + delay);
1681
2090
  if (hasPreStyleStep) {
@@ -1696,7 +2105,7 @@ class TimelineBuilder {
1696
2105
  }
1697
2106
  this._currentKeyframe = this._keyframes.get(this.duration);
1698
2107
  if (!this._currentKeyframe) {
1699
- this._currentKeyframe = Object.create(this._backFill, {});
2108
+ this._currentKeyframe = new Map();
1700
2109
  this._keyframes.set(this.duration, this._currentKeyframe);
1701
2110
  }
1702
2111
  }
@@ -1710,16 +2119,16 @@ class TimelineBuilder {
1710
2119
  this._loadKeyframe();
1711
2120
  }
1712
2121
  _updateStyle(prop, value) {
1713
- this._localTimelineStyles[prop] = value;
1714
- this._globalTimelineStyles[prop] = value;
1715
- this._styleSummary[prop] = { time: this.currentTime, value };
2122
+ this._localTimelineStyles.set(prop, value);
2123
+ this._globalTimelineStyles.set(prop, value);
2124
+ this._styleSummary.set(prop, { time: this.currentTime, value });
1716
2125
  }
1717
2126
  allowOnlyTimelineStyles() {
1718
2127
  return this._currentEmptyStepKeyframe !== this._currentKeyframe;
1719
2128
  }
1720
2129
  applyEmptyStep(easing) {
1721
2130
  if (easing) {
1722
- this._previousKeyframe['easing'] = easing;
2131
+ this._previousKeyframe.set('easing', easing);
1723
2132
  }
1724
2133
  // special case for animate(duration):
1725
2134
  // all missing styles are filled with a `*` value then
@@ -1727,51 +2136,45 @@ class TimelineBuilder {
1727
2136
  // keyframe then they will override the overridden styles
1728
2137
  // We use `_globalTimelineStyles` here because there may be
1729
2138
  // styles in previous keyframes that are not present in this timeline
1730
- Object.keys(this._globalTimelineStyles).forEach(prop => {
1731
- this._backFill[prop] = this._globalTimelineStyles[prop] || AUTO_STYLE;
1732
- this._currentKeyframe[prop] = AUTO_STYLE;
1733
- });
2139
+ for (let [prop, value] of this._globalTimelineStyles) {
2140
+ this._backFill.set(prop, value || AUTO_STYLE);
2141
+ this._currentKeyframe.set(prop, AUTO_STYLE);
2142
+ }
1734
2143
  this._currentEmptyStepKeyframe = this._currentKeyframe;
1735
2144
  }
1736
2145
  setStyles(input, easing, errors, options) {
1737
2146
  if (easing) {
1738
- this._previousKeyframe['easing'] = easing;
2147
+ this._previousKeyframe.set('easing', easing);
1739
2148
  }
1740
2149
  const params = (options && options.params) || {};
1741
2150
  const styles = flattenStyles(input, this._globalTimelineStyles);
1742
- Object.keys(styles).forEach(prop => {
1743
- const val = interpolateParams(styles[prop], params, errors);
1744
- this._pendingStyles[prop] = val;
1745
- if (!this._localTimelineStyles.hasOwnProperty(prop)) {
1746
- this._backFill[prop] = this._globalTimelineStyles.hasOwnProperty(prop) ?
1747
- this._globalTimelineStyles[prop] :
1748
- AUTO_STYLE;
2151
+ for (let [prop, value] of styles) {
2152
+ const val = interpolateParams(value, params, errors);
2153
+ this._pendingStyles.set(prop, val);
2154
+ if (!this._localTimelineStyles.has(prop)) {
2155
+ this._backFill.set(prop, this._globalTimelineStyles.get(prop) || AUTO_STYLE);
1749
2156
  }
1750
2157
  this._updateStyle(prop, val);
1751
- });
2158
+ }
1752
2159
  }
1753
2160
  applyStylesToKeyframe() {
1754
- const styles = this._pendingStyles;
1755
- const props = Object.keys(styles);
1756
- if (props.length == 0)
2161
+ if (this._pendingStyles.size == 0)
1757
2162
  return;
1758
- this._pendingStyles = {};
1759
- props.forEach(prop => {
1760
- const val = styles[prop];
1761
- this._currentKeyframe[prop] = val;
2163
+ this._pendingStyles.forEach((val, prop) => {
2164
+ this._currentKeyframe.set(prop, val);
1762
2165
  });
1763
- Object.keys(this._localTimelineStyles).forEach(prop => {
1764
- if (!this._currentKeyframe.hasOwnProperty(prop)) {
1765
- this._currentKeyframe[prop] = this._localTimelineStyles[prop];
2166
+ this._pendingStyles.clear();
2167
+ this._localTimelineStyles.forEach((val, prop) => {
2168
+ if (!this._currentKeyframe.has(prop)) {
2169
+ this._currentKeyframe.set(prop, val);
1766
2170
  }
1767
2171
  });
1768
2172
  }
1769
2173
  snapshotCurrentStyles() {
1770
- Object.keys(this._localTimelineStyles).forEach(prop => {
1771
- const val = this._localTimelineStyles[prop];
1772
- this._pendingStyles[prop] = val;
2174
+ for (let [prop, val] of this._localTimelineStyles) {
2175
+ this._pendingStyles.set(prop, val);
1773
2176
  this._updateStyle(prop, val);
1774
- });
2177
+ }
1775
2178
  }
1776
2179
  getFinalKeyframe() {
1777
2180
  return this._keyframes.get(this.duration);
@@ -1784,9 +2187,8 @@ class TimelineBuilder {
1784
2187
  return properties;
1785
2188
  }
1786
2189
  mergeTimelineCollectedStyles(timeline) {
1787
- Object.keys(timeline._styleSummary).forEach(prop => {
1788
- const details0 = this._styleSummary[prop];
1789
- const details1 = timeline._styleSummary[prop];
2190
+ timeline._styleSummary.forEach((details1, prop) => {
2191
+ const details0 = this._styleSummary.get(prop);
1790
2192
  if (!details0 || details1.time > details0.time) {
1791
2193
  this._updateStyle(prop, details1.value);
1792
2194
  }
@@ -1799,18 +2201,17 @@ class TimelineBuilder {
1799
2201
  const isEmpty = this._keyframes.size === 1 && this.duration === 0;
1800
2202
  let finalKeyframes = [];
1801
2203
  this._keyframes.forEach((keyframe, time) => {
1802
- const finalKeyframe = copyStyles(keyframe, true);
1803
- Object.keys(finalKeyframe).forEach(prop => {
1804
- const value = finalKeyframe[prop];
1805
- if (value == ɵPRE_STYLE) {
2204
+ const finalKeyframe = copyStyles(keyframe, new Map(), this._backFill);
2205
+ finalKeyframe.forEach((value, prop) => {
2206
+ if (value === ɵPRE_STYLE) {
1806
2207
  preStyleProps.add(prop);
1807
2208
  }
1808
- else if (value == AUTO_STYLE) {
2209
+ else if (value === AUTO_STYLE) {
1809
2210
  postStyleProps.add(prop);
1810
2211
  }
1811
2212
  });
1812
2213
  if (!isEmpty) {
1813
- finalKeyframe['offset'] = time / this.duration;
2214
+ finalKeyframe.set('offset', time / this.duration);
1814
2215
  }
1815
2216
  finalKeyframes.push(finalKeyframe);
1816
2217
  });
@@ -1819,9 +2220,9 @@ class TimelineBuilder {
1819
2220
  // special case for a 0-second animation (which is designed just to place styles onscreen)
1820
2221
  if (isEmpty) {
1821
2222
  const kf0 = finalKeyframes[0];
1822
- const kf1 = copyObj(kf0);
1823
- kf0['offset'] = 0;
1824
- kf1['offset'] = 1;
2223
+ const kf1 = new Map(kf0);
2224
+ kf0.set('offset', 0);
2225
+ kf1.set('offset', 1);
1825
2226
  finalKeyframes = [kf0, kf1];
1826
2227
  }
1827
2228
  return createTimelineInstruction(this.element, finalKeyframes, preProps, postProps, this.duration, this.startTime, this.easing, false);
@@ -1847,11 +2248,11 @@ class SubTimelineBuilder extends TimelineBuilder {
1847
2248
  const totalTime = duration + delay;
1848
2249
  const startingGap = delay / totalTime;
1849
2250
  // the original starting keyframe now starts once the delay is done
1850
- const newFirstKeyframe = copyStyles(keyframes[0], false);
1851
- newFirstKeyframe['offset'] = 0;
2251
+ const newFirstKeyframe = copyStyles(keyframes[0]);
2252
+ newFirstKeyframe.set('offset', 0);
1852
2253
  newKeyframes.push(newFirstKeyframe);
1853
- const oldFirstKeyframe = copyStyles(keyframes[0], false);
1854
- oldFirstKeyframe['offset'] = roundOffset(startingGap);
2254
+ const oldFirstKeyframe = copyStyles(keyframes[0]);
2255
+ oldFirstKeyframe.set('offset', roundOffset(startingGap));
1855
2256
  newKeyframes.push(oldFirstKeyframe);
1856
2257
  /*
1857
2258
  When the keyframe is stretched then it means that the delay before the animation
@@ -1870,10 +2271,10 @@ class SubTimelineBuilder extends TimelineBuilder {
1870
2271
  // offsets between 1 ... n -1 are all warped by the keyframe stretch
1871
2272
  const limit = keyframes.length - 1;
1872
2273
  for (let i = 1; i <= limit; i++) {
1873
- let kf = copyStyles(keyframes[i], false);
1874
- const oldOffset = kf['offset'];
2274
+ let kf = copyStyles(keyframes[i]);
2275
+ const oldOffset = kf.get('offset');
1875
2276
  const timeAtKeyframe = delay + oldOffset * duration;
1876
- kf['offset'] = roundOffset(timeAtKeyframe / totalTime);
2277
+ kf.set('offset', roundOffset(timeAtKeyframe / totalTime));
1877
2278
  newKeyframes.push(kf);
1878
2279
  }
1879
2280
  // the new starting keyframe should be added at the start
@@ -1890,17 +2291,17 @@ function roundOffset(offset, decimalPoints = 3) {
1890
2291
  return Math.round(offset * mult) / mult;
1891
2292
  }
1892
2293
  function flattenStyles(input, allStyles) {
1893
- const styles = {};
2294
+ const styles = new Map();
1894
2295
  let allProperties;
1895
2296
  input.forEach(token => {
1896
2297
  if (token === '*') {
1897
- allProperties = allProperties || Object.keys(allStyles);
1898
- allProperties.forEach(prop => {
1899
- styles[prop] = AUTO_STYLE;
1900
- });
2298
+ allProperties = allProperties || allStyles.keys();
2299
+ for (let prop of allProperties) {
2300
+ styles.set(prop, AUTO_STYLE);
2301
+ }
1901
2302
  }
1902
2303
  else {
1903
- copyStyles(token, false, styles);
2304
+ copyStyles(token, styles);
1904
2305
  }
1905
2306
  });
1906
2307
  return styles;
@@ -1910,10 +2311,13 @@ class Animation {
1910
2311
  constructor(_driver, input) {
1911
2312
  this._driver = _driver;
1912
2313
  const errors = [];
1913
- const ast = buildAnimationAst(_driver, input, errors);
2314
+ const warnings = [];
2315
+ const ast = buildAnimationAst(_driver, input, errors, warnings);
1914
2316
  if (errors.length) {
1915
- const errorMessage = `animation validation failed:\n${errors.join('\n')}`;
1916
- throw new Error(errorMessage);
2317
+ throw validationFailed(errors);
2318
+ }
2319
+ if (warnings.length) {
2320
+ warnValidation(warnings);
1917
2321
  }
1918
2322
  this._animationAst = ast;
1919
2323
  }
@@ -1926,8 +2330,7 @@ class Animation {
1926
2330
  subInstructions = subInstructions || new ElementInstructionMap();
1927
2331
  const result = buildAnimationTimelines(this._driver, element, this._animationAst, ENTER_CLASSNAME, LEAVE_CLASSNAME, start, dest, options, subInstructions, errors);
1928
2332
  if (errors.length) {
1929
- const errorMessage = `animation building failed:\n${errors.join('\n')}`;
1930
- throw new Error(errorMessage);
2333
+ throw buildingFailed(errors);
1931
2334
  }
1932
2335
  return result;
1933
2336
  }
@@ -1964,6 +2367,37 @@ class NoopAnimationStyleNormalizer {
1964
2367
  * Use of this source code is governed by an MIT-style license that can be
1965
2368
  * found in the LICENSE file at https://angular.io/license
1966
2369
  */
2370
+ const DIMENSIONAL_PROP_SET = new Set([
2371
+ 'width',
2372
+ 'height',
2373
+ 'minWidth',
2374
+ 'minHeight',
2375
+ 'maxWidth',
2376
+ 'maxHeight',
2377
+ 'left',
2378
+ 'top',
2379
+ 'bottom',
2380
+ 'right',
2381
+ 'fontSize',
2382
+ 'outlineWidth',
2383
+ 'outlineOffset',
2384
+ 'paddingTop',
2385
+ 'paddingLeft',
2386
+ 'paddingBottom',
2387
+ 'paddingRight',
2388
+ 'marginTop',
2389
+ 'marginLeft',
2390
+ 'marginBottom',
2391
+ 'marginRight',
2392
+ 'borderRadius',
2393
+ 'borderWidth',
2394
+ 'borderTopWidth',
2395
+ 'borderLeftWidth',
2396
+ 'borderRightWidth',
2397
+ 'borderBottomWidth',
2398
+ 'textIndent',
2399
+ 'perspective'
2400
+ ]);
1967
2401
  class WebAnimationsStyleNormalizer extends AnimationStyleNormalizer {
1968
2402
  normalizePropertyName(propertyName, errors) {
1969
2403
  return dashCaseToCamelCase(propertyName);
@@ -1971,28 +2405,28 @@ class WebAnimationsStyleNormalizer extends AnimationStyleNormalizer {
1971
2405
  normalizeStyleValue(userProvidedProperty, normalizedProperty, value, errors) {
1972
2406
  let unit = '';
1973
2407
  const strVal = value.toString().trim();
1974
- if (DIMENSIONAL_PROP_MAP[normalizedProperty] && value !== 0 && value !== '0') {
2408
+ if (DIMENSIONAL_PROP_SET.has(normalizedProperty) && value !== 0 && value !== '0') {
1975
2409
  if (typeof value === 'number') {
1976
2410
  unit = 'px';
1977
2411
  }
1978
2412
  else {
1979
2413
  const valAndSuffixMatch = value.match(/^[+-]?[\d\.]+([a-z]*)$/);
1980
2414
  if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
1981
- errors.push(`Please provide a CSS unit value for ${userProvidedProperty}:${value}`);
2415
+ errors.push(invalidCssUnitValue(userProvidedProperty, value));
1982
2416
  }
1983
2417
  }
1984
2418
  }
1985
2419
  return strVal + unit;
1986
2420
  }
1987
2421
  }
1988
- const DIMENSIONAL_PROP_MAP = (() => makeBooleanMap('width,height,minWidth,minHeight,maxWidth,maxHeight,left,top,bottom,right,fontSize,outlineWidth,outlineOffset,paddingTop,paddingLeft,paddingBottom,paddingRight,marginTop,marginLeft,marginBottom,marginRight,borderRadius,borderWidth,borderTopWidth,borderLeftWidth,borderRightWidth,borderBottomWidth,textIndent,perspective'
1989
- .split(',')))();
1990
- function makeBooleanMap(keys) {
1991
- const map = {};
1992
- keys.forEach(key => map[key] = true);
1993
- return map;
1994
- }
1995
2422
 
2423
+ /**
2424
+ * @license
2425
+ * Copyright Google LLC All Rights Reserved.
2426
+ *
2427
+ * Use of this source code is governed by an MIT-style license that can be
2428
+ * found in the LICENSE file at https://angular.io/license
2429
+ */
1996
2430
  function createTransitionInstruction(element, triggerName, fromState, toState, isRemovalTransition, fromStyles, toStyles, timelines, queriedElements, preStyleProps, postStyleProps, totalTime, errors) {
1997
2431
  return {
1998
2432
  type: 0 /* TransitionAnimation */,
@@ -2023,10 +2457,11 @@ class AnimationTransitionFactory {
2023
2457
  return oneOrMoreTransitionsMatch(this.ast.matchers, currentState, nextState, element, params);
2024
2458
  }
2025
2459
  buildStyles(stateName, params, errors) {
2026
- const backupStateStyler = this._stateStyles['*'];
2027
- const stateStyler = this._stateStyles[stateName];
2028
- const backupStyles = backupStateStyler ? backupStateStyler.buildStyles(params, errors) : {};
2029
- return stateStyler ? stateStyler.buildStyles(params, errors) : backupStyles;
2460
+ let styler = this._stateStyles.get('*');
2461
+ if (stateName !== undefined) {
2462
+ styler = this._stateStyles.get(stateName?.toString()) || styler;
2463
+ }
2464
+ return styler ? styler.buildStyles(params, errors) : new Map();
2030
2465
  }
2031
2466
  build(driver, element, currentState, nextState, enterClassName, leaveClassName, currentOptions, nextOptions, subInstructions, skipAstBuild) {
2032
2467
  const errors = [];
@@ -2039,7 +2474,10 @@ class AnimationTransitionFactory {
2039
2474
  const preStyleMap = new Map();
2040
2475
  const postStyleMap = new Map();
2041
2476
  const isRemoval = nextState === 'void';
2042
- const animationOptions = { params: { ...transitionAnimationParams, ...nextAnimationParams } };
2477
+ const animationOptions = {
2478
+ params: applyParamDefaults(nextAnimationParams, transitionAnimationParams),
2479
+ delay: this.ast.options?.delay,
2480
+ };
2043
2481
  const timelines = skipAstBuild ?
2044
2482
  [] :
2045
2483
  buildAnimationTimelines(driver, element, this.ast.animation, enterClassName, leaveClassName, currentStateStyles, nextStateStyles, animationOptions, subInstructions, errors);
@@ -2052,10 +2490,10 @@ class AnimationTransitionFactory {
2052
2490
  }
2053
2491
  timelines.forEach(tl => {
2054
2492
  const elm = tl.element;
2055
- const preProps = getOrSetAsInMap(preStyleMap, elm, {});
2056
- tl.preStyleProps.forEach(prop => preProps[prop] = true);
2057
- const postProps = getOrSetAsInMap(postStyleMap, elm, {});
2058
- tl.postStyleProps.forEach(prop => postProps[prop] = true);
2493
+ const preProps = getOrSetDefaultValue(preStyleMap, elm, new Set());
2494
+ tl.preStyleProps.forEach(prop => preProps.add(prop));
2495
+ const postProps = getOrSetDefaultValue(postStyleMap, elm, new Set());
2496
+ tl.postStyleProps.forEach(prop => postProps.add(prop));
2059
2497
  if (elm !== element) {
2060
2498
  queriedElements.add(elm);
2061
2499
  }
@@ -2067,6 +2505,15 @@ class AnimationTransitionFactory {
2067
2505
  function oneOrMoreTransitionsMatch(matchFns, currentState, nextState, element, params) {
2068
2506
  return matchFns.some(fn => fn(currentState, nextState, element, params));
2069
2507
  }
2508
+ function applyParamDefaults(userParams, defaults) {
2509
+ const result = copyObj(defaults);
2510
+ for (const key in userParams) {
2511
+ if (userParams.hasOwnProperty(key) && userParams[key] != null) {
2512
+ result[key] = userParams[key];
2513
+ }
2514
+ }
2515
+ return result;
2516
+ }
2070
2517
  class AnimationStateStyles {
2071
2518
  constructor(styles, defaultParams, normalizer) {
2072
2519
  this.styles = styles;
@@ -2074,25 +2521,23 @@ class AnimationStateStyles {
2074
2521
  this.normalizer = normalizer;
2075
2522
  }
2076
2523
  buildStyles(params, errors) {
2077
- const finalStyles = {};
2524
+ const finalStyles = new Map();
2078
2525
  const combinedParams = copyObj(this.defaultParams);
2079
2526
  Object.keys(params).forEach(key => {
2080
2527
  const value = params[key];
2081
- if (value != null) {
2528
+ if (value !== null) {
2082
2529
  combinedParams[key] = value;
2083
2530
  }
2084
2531
  });
2085
2532
  this.styles.styles.forEach(value => {
2086
2533
  if (typeof value !== 'string') {
2087
- const styleObj = value;
2088
- Object.keys(styleObj).forEach(prop => {
2089
- let val = styleObj[prop];
2090
- if (val.length > 1) {
2534
+ value.forEach((val, prop) => {
2535
+ if (val) {
2091
2536
  val = interpolateParams(val, combinedParams, errors);
2092
2537
  }
2093
2538
  const normalizedProp = this.normalizer.normalizePropertyName(prop, errors);
2094
2539
  val = this.normalizer.normalizeStyleValue(prop, normalizedProp, val, errors);
2095
- finalStyles[normalizedProp] = val;
2540
+ finalStyles.set(normalizedProp, val);
2096
2541
  });
2097
2542
  }
2098
2543
  });
@@ -2109,10 +2554,10 @@ class AnimationTrigger {
2109
2554
  this.ast = ast;
2110
2555
  this._normalizer = _normalizer;
2111
2556
  this.transitionFactories = [];
2112
- this.states = {};
2557
+ this.states = new Map();
2113
2558
  ast.states.forEach(ast => {
2114
2559
  const defaultParams = (ast.options && ast.options.params) || {};
2115
- this.states[ast.name] = new AnimationStateStyles(ast.style, defaultParams, _normalizer);
2560
+ this.states.set(ast.name, new AnimationStateStyles(ast.style, defaultParams, _normalizer));
2116
2561
  });
2117
2562
  balanceProperties(this.states, 'true', '1');
2118
2563
  balanceProperties(this.states, 'false', '0');
@@ -2145,14 +2590,14 @@ function createFallbackTransition(triggerName, states, normalizer) {
2145
2590
  };
2146
2591
  return new AnimationTransitionFactory(triggerName, transition, states);
2147
2592
  }
2148
- function balanceProperties(obj, key1, key2) {
2149
- if (obj.hasOwnProperty(key1)) {
2150
- if (!obj.hasOwnProperty(key2)) {
2151
- obj[key2] = obj[key1];
2593
+ function balanceProperties(stateMap, key1, key2) {
2594
+ if (stateMap.has(key1)) {
2595
+ if (!stateMap.has(key2)) {
2596
+ stateMap.set(key2, stateMap.get(key1));
2152
2597
  }
2153
2598
  }
2154
- else if (obj.hasOwnProperty(key2)) {
2155
- obj[key1] = obj[key2];
2599
+ else if (stateMap.has(key2)) {
2600
+ stateMap.set(key1, stateMap.get(key2));
2156
2601
  }
2157
2602
  }
2158
2603
 
@@ -2169,55 +2614,59 @@ class TimelineAnimationEngine {
2169
2614
  this.bodyNode = bodyNode;
2170
2615
  this._driver = _driver;
2171
2616
  this._normalizer = _normalizer;
2172
- this._animations = {};
2173
- this._playersById = {};
2617
+ this._animations = new Map();
2618
+ this._playersById = new Map();
2174
2619
  this.players = [];
2175
2620
  }
2176
2621
  register(id, metadata) {
2177
2622
  const errors = [];
2178
- const ast = buildAnimationAst(this._driver, metadata, errors);
2623
+ const warnings = [];
2624
+ const ast = buildAnimationAst(this._driver, metadata, errors, warnings);
2179
2625
  if (errors.length) {
2180
- throw new Error(`Unable to build the animation due to the following errors: ${errors.join('\n')}`);
2626
+ throw registerFailed(errors);
2181
2627
  }
2182
2628
  else {
2183
- this._animations[id] = ast;
2629
+ if (warnings.length) {
2630
+ warnRegister(warnings);
2631
+ }
2632
+ this._animations.set(id, ast);
2184
2633
  }
2185
2634
  }
2186
2635
  _buildPlayer(i, preStyles, postStyles) {
2187
2636
  const element = i.element;
2188
- const keyframes = normalizeKeyframes(this._driver, this._normalizer, element, i.keyframes, preStyles, postStyles);
2637
+ const keyframes = normalizeKeyframes$1(this._driver, this._normalizer, element, i.keyframes, preStyles, postStyles);
2189
2638
  return this._driver.animate(element, keyframes, i.duration, i.delay, i.easing, [], true);
2190
2639
  }
2191
2640
  create(id, element, options = {}) {
2192
2641
  const errors = [];
2193
- const ast = this._animations[id];
2642
+ const ast = this._animations.get(id);
2194
2643
  let instructions;
2195
2644
  const autoStylesMap = new Map();
2196
2645
  if (ast) {
2197
- instructions = buildAnimationTimelines(this._driver, element, ast, ENTER_CLASSNAME, LEAVE_CLASSNAME, {}, {}, options, EMPTY_INSTRUCTION_MAP, errors);
2646
+ instructions = buildAnimationTimelines(this._driver, element, ast, ENTER_CLASSNAME, LEAVE_CLASSNAME, new Map(), new Map(), options, EMPTY_INSTRUCTION_MAP, errors);
2198
2647
  instructions.forEach(inst => {
2199
- const styles = getOrSetAsInMap(autoStylesMap, inst.element, {});
2200
- inst.postStyleProps.forEach(prop => styles[prop] = null);
2648
+ const styles = getOrSetDefaultValue(autoStylesMap, inst.element, new Map());
2649
+ inst.postStyleProps.forEach(prop => styles.set(prop, null));
2201
2650
  });
2202
2651
  }
2203
2652
  else {
2204
- errors.push('The requested animation doesn\'t exist or has already been destroyed');
2653
+ errors.push(missingOrDestroyedAnimation());
2205
2654
  instructions = [];
2206
2655
  }
2207
2656
  if (errors.length) {
2208
- throw new Error(`Unable to create the animation due to the following errors: ${errors.join('\n')}`);
2657
+ throw createAnimationFailed(errors);
2209
2658
  }
2210
2659
  autoStylesMap.forEach((styles, element) => {
2211
- Object.keys(styles).forEach(prop => {
2212
- styles[prop] = this._driver.computeStyle(element, prop, AUTO_STYLE);
2660
+ styles.forEach((_, prop) => {
2661
+ styles.set(prop, this._driver.computeStyle(element, prop, AUTO_STYLE));
2213
2662
  });
2214
2663
  });
2215
2664
  const players = instructions.map(i => {
2216
2665
  const styles = autoStylesMap.get(i.element);
2217
- return this._buildPlayer(i, {}, styles);
2666
+ return this._buildPlayer(i, new Map(), styles);
2218
2667
  });
2219
2668
  const player = optimizeGroupPlayer(players);
2220
- this._playersById[id] = player;
2669
+ this._playersById.set(id, player);
2221
2670
  player.onDestroy(() => this.destroy(id));
2222
2671
  this.players.push(player);
2223
2672
  return player;
@@ -2225,16 +2674,16 @@ class TimelineAnimationEngine {
2225
2674
  destroy(id) {
2226
2675
  const player = this._getPlayer(id);
2227
2676
  player.destroy();
2228
- delete this._playersById[id];
2677
+ this._playersById.delete(id);
2229
2678
  const index = this.players.indexOf(player);
2230
2679
  if (index >= 0) {
2231
2680
  this.players.splice(index, 1);
2232
2681
  }
2233
2682
  }
2234
2683
  _getPlayer(id) {
2235
- const player = this._playersById[id];
2684
+ const player = this._playersById.get(id);
2236
2685
  if (!player) {
2237
- throw new Error(`Unable to find the timeline player referenced by ${id}`);
2686
+ throw missingPlayer(id);
2238
2687
  }
2239
2688
  return player;
2240
2689
  }
@@ -2354,30 +2803,30 @@ class AnimationTransitionNamespace {
2354
2803
  this.hostElement = hostElement;
2355
2804
  this._engine = _engine;
2356
2805
  this.players = [];
2357
- this._triggers = {};
2806
+ this._triggers = new Map();
2358
2807
  this._queue = [];
2359
2808
  this._elementListeners = new Map();
2360
2809
  this._hostClassName = 'ng-tns-' + id;
2361
2810
  addClass(hostElement, this._hostClassName);
2362
2811
  }
2363
2812
  listen(element, name, phase, callback) {
2364
- if (!this._triggers.hasOwnProperty(name)) {
2365
- throw new Error(`Unable to listen on the animation trigger event "${phase}" because the animation trigger "${name}" doesn\'t exist!`);
2813
+ if (!this._triggers.has(name)) {
2814
+ throw missingTrigger(phase, name);
2366
2815
  }
2367
2816
  if (phase == null || phase.length == 0) {
2368
- throw new Error(`Unable to listen on the animation trigger "${name}" because the provided event is undefined!`);
2817
+ throw missingEvent(name);
2369
2818
  }
2370
2819
  if (!isTriggerEventValid(phase)) {
2371
- throw new Error(`The provided animation trigger event "${phase}" for the animation trigger "${name}" is not supported!`);
2820
+ throw unsupportedTriggerEvent(phase, name);
2372
2821
  }
2373
- const listeners = getOrSetAsInMap(this._elementListeners, element, []);
2822
+ const listeners = getOrSetDefaultValue(this._elementListeners, element, []);
2374
2823
  const data = { name, phase, callback };
2375
2824
  listeners.push(data);
2376
- const triggersWithStates = getOrSetAsInMap(this._engine.statesByElement, element, {});
2377
- if (!triggersWithStates.hasOwnProperty(name)) {
2825
+ const triggersWithStates = getOrSetDefaultValue(this._engine.statesByElement, element, new Map());
2826
+ if (!triggersWithStates.has(name)) {
2378
2827
  addClass(element, NG_TRIGGER_CLASSNAME);
2379
2828
  addClass(element, NG_TRIGGER_CLASSNAME + '-' + name);
2380
- triggersWithStates[name] = DEFAULT_STATE_VALUE;
2829
+ triggersWithStates.set(name, DEFAULT_STATE_VALUE);
2381
2830
  }
2382
2831
  return () => {
2383
2832
  // the event listener is removed AFTER the flush has occurred such
@@ -2388,26 +2837,26 @@ class AnimationTransitionNamespace {
2388
2837
  if (index >= 0) {
2389
2838
  listeners.splice(index, 1);
2390
2839
  }
2391
- if (!this._triggers[name]) {
2392
- delete triggersWithStates[name];
2840
+ if (!this._triggers.has(name)) {
2841
+ triggersWithStates.delete(name);
2393
2842
  }
2394
2843
  });
2395
2844
  };
2396
2845
  }
2397
2846
  register(name, ast) {
2398
- if (this._triggers[name]) {
2847
+ if (this._triggers.has(name)) {
2399
2848
  // throw
2400
2849
  return false;
2401
2850
  }
2402
2851
  else {
2403
- this._triggers[name] = ast;
2852
+ this._triggers.set(name, ast);
2404
2853
  return true;
2405
2854
  }
2406
2855
  }
2407
2856
  _getTrigger(name) {
2408
- const trigger = this._triggers[name];
2857
+ const trigger = this._triggers.get(name);
2409
2858
  if (!trigger) {
2410
- throw new Error(`The provided animation trigger "${name}" has not been registered!`);
2859
+ throw unregisteredTrigger(name);
2411
2860
  }
2412
2861
  return trigger;
2413
2862
  }
@@ -2418,15 +2867,15 @@ class AnimationTransitionNamespace {
2418
2867
  if (!triggersWithStates) {
2419
2868
  addClass(element, NG_TRIGGER_CLASSNAME);
2420
2869
  addClass(element, NG_TRIGGER_CLASSNAME + '-' + triggerName);
2421
- this._engine.statesByElement.set(element, triggersWithStates = {});
2870
+ this._engine.statesByElement.set(element, triggersWithStates = new Map());
2422
2871
  }
2423
- let fromState = triggersWithStates[triggerName];
2872
+ let fromState = triggersWithStates.get(triggerName);
2424
2873
  const toState = new StateValue(value, this.id);
2425
2874
  const isObj = value && value.hasOwnProperty('value');
2426
2875
  if (!isObj && fromState) {
2427
2876
  toState.absorbOptions(fromState.options);
2428
2877
  }
2429
- triggersWithStates[triggerName] = toState;
2878
+ triggersWithStates.set(triggerName, toState);
2430
2879
  if (!fromState) {
2431
2880
  fromState = DEFAULT_STATE_VALUE;
2432
2881
  }
@@ -2456,7 +2905,7 @@ class AnimationTransitionNamespace {
2456
2905
  }
2457
2906
  return;
2458
2907
  }
2459
- const playersOnElement = getOrSetAsInMap(this._engine.playersByElement, element, []);
2908
+ const playersOnElement = getOrSetDefaultValue(this._engine.playersByElement, element, []);
2460
2909
  playersOnElement.forEach(player => {
2461
2910
  // only remove the player if it is queued on the EXACT same trigger/namespace
2462
2911
  // we only also deal with queued players here because if the animation has
@@ -2500,10 +2949,8 @@ class AnimationTransitionNamespace {
2500
2949
  return player;
2501
2950
  }
2502
2951
  deregister(name) {
2503
- delete this._triggers[name];
2504
- this._engine.statesByElement.forEach((stateMap, element) => {
2505
- delete stateMap[name];
2506
- });
2952
+ this._triggers.delete(name);
2953
+ this._engine.statesByElement.forEach(stateMap => stateMap.delete(name));
2507
2954
  this._elementListeners.forEach((listeners, element) => {
2508
2955
  this._elementListeners.set(element, listeners.filter(entry => {
2509
2956
  return entry.name != name;
@@ -2546,11 +2993,11 @@ class AnimationTransitionNamespace {
2546
2993
  const previousTriggersValues = new Map();
2547
2994
  if (triggerStates) {
2548
2995
  const players = [];
2549
- Object.keys(triggerStates).forEach(triggerName => {
2550
- previousTriggersValues.set(triggerName, triggerStates[triggerName].value);
2996
+ triggerStates.forEach((state, triggerName) => {
2997
+ previousTriggersValues.set(triggerName, state.value);
2551
2998
  // this check is here in the event that an element is removed
2552
2999
  // twice (both on the host level and the component level)
2553
- if (this._triggers[triggerName]) {
3000
+ if (this._triggers.has(triggerName)) {
2554
3001
  const player = this.trigger(element, triggerName, VOID_VALUE, defaultToFallback);
2555
3002
  if (player) {
2556
3003
  players.push(player);
@@ -2579,9 +3026,9 @@ class AnimationTransitionNamespace {
2579
3026
  if (visitedTriggers.has(triggerName))
2580
3027
  return;
2581
3028
  visitedTriggers.add(triggerName);
2582
- const trigger = this._triggers[triggerName];
3029
+ const trigger = this._triggers.get(triggerName);
2583
3030
  const transition = trigger.fallbackTransition;
2584
- const fromState = elementStates[triggerName] || DEFAULT_STATE_VALUE;
3031
+ const fromState = elementStates.get(triggerName) || DEFAULT_STATE_VALUE;
2585
3032
  const toState = new StateValue(VOID_VALUE);
2586
3033
  const player = new TransitionAnimationPlayer(this.id, triggerName, element);
2587
3034
  this._engine.totalQueuedPlayers++;
@@ -2763,25 +3210,37 @@ class TransitionAnimationEngine {
2763
3210
  return this._namespaceLookup[namespaceId] = ns;
2764
3211
  }
2765
3212
  _balanceNamespaceList(ns, hostElement) {
2766
- const limit = this._namespaceList.length - 1;
3213
+ const namespaceList = this._namespaceList;
3214
+ const namespacesByHostElement = this.namespacesByHostElement;
3215
+ const limit = namespaceList.length - 1;
2767
3216
  if (limit >= 0) {
2768
3217
  let found = false;
2769
- for (let i = limit; i >= 0; i--) {
2770
- const nextNamespace = this._namespaceList[i];
2771
- if (this.driver.containsElement(nextNamespace.hostElement, hostElement)) {
2772
- this._namespaceList.splice(i + 1, 0, ns);
3218
+ // Find the closest ancestor with an existing namespace so we can then insert `ns` after it,
3219
+ // establishing a top-down ordering of namespaces in `this._namespaceList`.
3220
+ let ancestor = this.driver.getParentElement(hostElement);
3221
+ while (ancestor) {
3222
+ const ancestorNs = namespacesByHostElement.get(ancestor);
3223
+ if (ancestorNs) {
3224
+ // An animation namespace has been registered for this ancestor, so we insert `ns`
3225
+ // right after it to establish top-down ordering of animation namespaces.
3226
+ const index = namespaceList.indexOf(ancestorNs);
3227
+ namespaceList.splice(index + 1, 0, ns);
2773
3228
  found = true;
2774
3229
  break;
2775
3230
  }
3231
+ ancestor = this.driver.getParentElement(ancestor);
2776
3232
  }
2777
3233
  if (!found) {
2778
- this._namespaceList.splice(0, 0, ns);
3234
+ // No namespace exists that is an ancestor of `ns`, so `ns` is inserted at the front to
3235
+ // ensure that any existing descendants are ordered after `ns`, retaining the desired
3236
+ // top-down ordering.
3237
+ namespaceList.unshift(ns);
2779
3238
  }
2780
3239
  }
2781
3240
  else {
2782
- this._namespaceList.push(ns);
3241
+ namespaceList.push(ns);
2783
3242
  }
2784
- this.namespacesByHostElement.set(hostElement, ns);
3243
+ namespacesByHostElement.set(hostElement, ns);
2785
3244
  return ns;
2786
3245
  }
2787
3246
  register(namespaceId, hostElement) {
@@ -2823,11 +3282,9 @@ class TransitionAnimationEngine {
2823
3282
  const namespaces = new Set();
2824
3283
  const elementStates = this.statesByElement.get(element);
2825
3284
  if (elementStates) {
2826
- const keys = Object.keys(elementStates);
2827
- for (let i = 0; i < keys.length; i++) {
2828
- const nsId = elementStates[keys[i]].namespaceId;
2829
- if (nsId) {
2830
- const ns = this._fetchNamespace(nsId);
3285
+ for (let stateValue of elementStates.values()) {
3286
+ if (stateValue.namespaceId) {
3287
+ const ns = this._fetchNamespace(stateValue.namespaceId);
2831
3288
  if (ns) {
2832
3289
  namespaces.add(ns);
2833
3290
  }
@@ -3047,7 +3504,7 @@ class TransitionAnimationEngine {
3047
3504
  }
3048
3505
  }
3049
3506
  reportError(errors) {
3050
- throw new Error(`Unable to process animations due to the following failed trigger transitions\n ${errors.join('\n')}`);
3507
+ throw triggerTransitionsFailed(errors);
3051
3508
  }
3052
3509
  _flushAnimations(cleanupFns, microtaskId) {
3053
3510
  const subTimelines = new ElementInstructionMap();
@@ -3134,8 +3591,10 @@ class TransitionAnimationEngine {
3134
3591
  // we need to restore the previous trigger value since the element has
3135
3592
  // only been moved and hasn't actually left the DOM
3136
3593
  const triggersWithStates = this.statesByElement.get(entry.element);
3137
- if (triggersWithStates && triggersWithStates[entry.triggerName]) {
3138
- triggersWithStates[entry.triggerName].value = previousValue;
3594
+ if (triggersWithStates && triggersWithStates.has(entry.triggerName)) {
3595
+ const state = triggersWithStates.get(entry.triggerName);
3596
+ state.value = previousValue;
3597
+ triggersWithStates.set(entry.triggerName, state);
3139
3598
  }
3140
3599
  }
3141
3600
  player.destroy();
@@ -3185,32 +3644,29 @@ class TransitionAnimationEngine {
3185
3644
  subTimelines.append(element, instruction.timelines);
3186
3645
  const tuple = { instruction, player, element };
3187
3646
  queuedInstructions.push(tuple);
3188
- instruction.queriedElements.forEach(element => getOrSetAsInMap(queriedElements, element, []).push(player));
3647
+ instruction.queriedElements.forEach(element => getOrSetDefaultValue(queriedElements, element, []).push(player));
3189
3648
  instruction.preStyleProps.forEach((stringMap, element) => {
3190
- const props = Object.keys(stringMap);
3191
- if (props.length) {
3649
+ if (stringMap.size) {
3192
3650
  let setVal = allPreStyleElements.get(element);
3193
3651
  if (!setVal) {
3194
3652
  allPreStyleElements.set(element, setVal = new Set());
3195
3653
  }
3196
- props.forEach(prop => setVal.add(prop));
3654
+ stringMap.forEach((_, prop) => setVal.add(prop));
3197
3655
  }
3198
3656
  });
3199
3657
  instruction.postStyleProps.forEach((stringMap, element) => {
3200
- const props = Object.keys(stringMap);
3201
3658
  let setVal = allPostStyleElements.get(element);
3202
3659
  if (!setVal) {
3203
3660
  allPostStyleElements.set(element, setVal = new Set());
3204
3661
  }
3205
- props.forEach(prop => setVal.add(prop));
3662
+ stringMap.forEach((_, prop) => setVal.add(prop));
3206
3663
  });
3207
3664
  });
3208
3665
  }
3209
3666
  if (erroneousTransitions.length) {
3210
3667
  const errors = [];
3211
3668
  erroneousTransitions.forEach(instruction => {
3212
- errors.push(`@${instruction.triggerName} has failed due to:\n`);
3213
- instruction.errors.forEach(error => errors.push(`- ${error}\n`));
3669
+ errors.push(transitionFailed(instruction.triggerName, instruction.errors));
3214
3670
  });
3215
3671
  allPlayers.forEach(player => player.destroy());
3216
3672
  this.reportError(errors);
@@ -3232,7 +3688,7 @@ class TransitionAnimationEngine {
3232
3688
  const element = player.element;
3233
3689
  const previousPlayers = this._getPreviousPlayers(element, false, player.namespaceId, player.triggerName, null);
3234
3690
  previousPlayers.forEach(prevPlayer => {
3235
- getOrSetAsInMap(allPreviousPlayersMap, element, []).push(prevPlayer);
3691
+ getOrSetDefaultValue(allPreviousPlayersMap, element, []).push(prevPlayer);
3236
3692
  prevPlayer.destroy();
3237
3693
  });
3238
3694
  });
@@ -3262,7 +3718,7 @@ class TransitionAnimationEngine {
3262
3718
  replaceNodes.forEach(node => {
3263
3719
  const post = postStylesMap.get(node);
3264
3720
  const pre = preStylesMap.get(node);
3265
- postStylesMap.set(node, { ...post, ...pre });
3721
+ postStylesMap.set(node, new Map([...Array.from(post?.entries() ?? []), ...Array.from(pre?.entries() ?? [])]));
3266
3722
  });
3267
3723
  const rootPlayers = [];
3268
3724
  const subPlayers = [];
@@ -3456,7 +3912,7 @@ class TransitionAnimationEngine {
3456
3912
  for (const timelineInstruction of instruction.timelines) {
3457
3913
  const element = timelineInstruction.element;
3458
3914
  const isQueriedElement = element !== rootElement;
3459
- const players = getOrSetAsInMap(allPreviousPlayersMap, element, []);
3915
+ const players = getOrSetDefaultValue(allPreviousPlayersMap, element, []);
3460
3916
  const previousPlayers = this._getPreviousPlayers(element, isQueriedElement, targetNameSpaceId, targetTriggerName, instruction.toState);
3461
3917
  previousPlayers.forEach(player => {
3462
3918
  const realPlayer = player.getRealPlayer();
@@ -3499,7 +3955,7 @@ class TransitionAnimationEngine {
3499
3955
  });
3500
3956
  const preStyles = preStylesMap.get(element);
3501
3957
  const postStyles = postStylesMap.get(element);
3502
- const keyframes = normalizeKeyframes(this.driver, this._normalizer, element, timelineInstruction.keyframes, preStyles, postStyles);
3958
+ const keyframes = normalizeKeyframes$1(this.driver, this._normalizer, element, timelineInstruction.keyframes, preStyles, postStyles);
3503
3959
  const player = this._buildPlayer(timelineInstruction, keyframes, previousPlayers);
3504
3960
  // this means that this particular player belongs to a sub trigger. It is
3505
3961
  // important that we match this player up with the corresponding (@trigger.listener)
@@ -3514,7 +3970,7 @@ class TransitionAnimationEngine {
3514
3970
  return player;
3515
3971
  });
3516
3972
  allQueriedPlayers.forEach(player => {
3517
- getOrSetAsInMap(this.playersByQueriedElement, player.element, []).push(player);
3973
+ getOrSetDefaultValue(this.playersByQueriedElement, player.element, []).push(player);
3518
3974
  player.onDone(() => deleteOrUnsetInMap(this.playersByQueriedElement, player.element, player));
3519
3975
  });
3520
3976
  allConsumedElements.forEach(element => addClass(element, NG_ANIMATING_CLASSNAME));
@@ -3526,7 +3982,7 @@ class TransitionAnimationEngine {
3526
3982
  // this basically makes all of the callbacks for sub element animations
3527
3983
  // be dependent on the upper players for when they finish
3528
3984
  allSubElements.forEach(element => {
3529
- getOrSetAsInMap(skippedPlayersMap, element, []).push(player);
3985
+ getOrSetDefaultValue(skippedPlayersMap, element, []).push(player);
3530
3986
  });
3531
3987
  return player;
3532
3988
  }
@@ -3546,7 +4002,7 @@ class TransitionAnimationPlayer {
3546
4002
  this.element = element;
3547
4003
  this._player = new NoopAnimationPlayer();
3548
4004
  this._containsRealPlayer = false;
3549
- this._queuedCallbacks = {};
4005
+ this._queuedCallbacks = new Map();
3550
4006
  this.destroyed = false;
3551
4007
  this.markedForDestroy = false;
3552
4008
  this.disabled = false;
@@ -3557,10 +4013,10 @@ class TransitionAnimationPlayer {
3557
4013
  if (this._containsRealPlayer)
3558
4014
  return;
3559
4015
  this._player = player;
3560
- Object.keys(this._queuedCallbacks).forEach(phase => {
3561
- this._queuedCallbacks[phase].forEach(callback => listenOnPlayer(player, phase, undefined, callback));
4016
+ this._queuedCallbacks.forEach((callbacks, phase) => {
4017
+ callbacks.forEach(callback => listenOnPlayer(player, phase, undefined, callback));
3562
4018
  });
3563
- this._queuedCallbacks = {};
4019
+ this._queuedCallbacks.clear();
3564
4020
  this._containsRealPlayer = true;
3565
4021
  this.overrideTotalTime(player.totalTime);
3566
4022
  this.queued = false;
@@ -3580,7 +4036,7 @@ class TransitionAnimationPlayer {
3580
4036
  player.onDestroy(() => this.destroy());
3581
4037
  }
3582
4038
  _queueEvent(name, callback) {
3583
- getOrSetAsInMap(this._queuedCallbacks, name, []).push(callback);
4039
+ getOrSetDefaultValue(this._queuedCallbacks, name, []).push(callback);
3584
4040
  }
3585
4041
  onDone(fn) {
3586
4042
  if (this.queued) {
@@ -3642,29 +4098,14 @@ class TransitionAnimationPlayer {
3642
4098
  }
3643
4099
  }
3644
4100
  function deleteOrUnsetInMap(map, key, value) {
3645
- let currentValues;
3646
- if (map instanceof Map) {
3647
- currentValues = map.get(key);
3648
- if (currentValues) {
3649
- if (currentValues.length) {
3650
- const index = currentValues.indexOf(value);
3651
- currentValues.splice(index, 1);
3652
- }
3653
- if (currentValues.length == 0) {
3654
- map.delete(key);
3655
- }
4101
+ let currentValues = map.get(key);
4102
+ if (currentValues) {
4103
+ if (currentValues.length) {
4104
+ const index = currentValues.indexOf(value);
4105
+ currentValues.splice(index, 1);
3656
4106
  }
3657
- }
3658
- else {
3659
- currentValues = map[key];
3660
- if (currentValues) {
3661
- if (currentValues.length) {
3662
- const index = currentValues.indexOf(value);
3663
- currentValues.splice(index, 1);
3664
- }
3665
- if (currentValues.length == 0) {
3666
- delete map[key];
3667
- }
4107
+ if (currentValues.length == 0) {
4108
+ map.delete(key);
3668
4109
  }
3669
4110
  }
3670
4111
  return currentValues;
@@ -3691,9 +4132,10 @@ function cloakAndComputeStyles(valuesMap, driver, elements, elementPropsMap, def
3691
4132
  elements.forEach(element => cloakVals.push(cloakElement(element)));
3692
4133
  const failedElements = [];
3693
4134
  elementPropsMap.forEach((props, element) => {
3694
- const styles = {};
4135
+ const styles = new Map();
3695
4136
  props.forEach(prop => {
3696
- const value = styles[prop] = driver.computeStyle(element, prop, defaultStyle);
4137
+ const value = driver.computeStyle(element, prop, defaultStyle);
4138
+ styles.set(prop, value);
3697
4139
  // there is no easy way to detect this because a sub element could be removed
3698
4140
  // by a parent animation element being detached.
3699
4141
  if (!value || value.length == 0) {
@@ -3823,9 +4265,13 @@ class AnimationEngine {
3823
4265
  let trigger = this._triggerCache[cacheKey];
3824
4266
  if (!trigger) {
3825
4267
  const errors = [];
3826
- const ast = buildAnimationAst(this._driver, metadata, errors);
4268
+ const warnings = [];
4269
+ const ast = buildAnimationAst(this._driver, metadata, errors, warnings);
3827
4270
  if (errors.length) {
3828
- throw new Error(`The animation trigger "${name}" has failed to build due to the following errors:\n - ${errors.join('\n - ')}`);
4271
+ throw triggerBuildFailed(name, errors);
4272
+ }
4273
+ if (warnings.length) {
4274
+ warnTriggerBuild(name, warnings);
3829
4275
  }
3830
4276
  trigger = buildTrigger(name, ast, this._normalizer);
3831
4277
  this._triggerCache[cacheKey] = trigger;
@@ -3877,13 +4323,6 @@ class AnimationEngine {
3877
4323
  }
3878
4324
  }
3879
4325
 
3880
- /**
3881
- * @license
3882
- * Copyright Google LLC All Rights Reserved.
3883
- *
3884
- * Use of this source code is governed by an MIT-style license that can be
3885
- * found in the LICENSE file at https://angular.io/license
3886
- */
3887
4326
  /**
3888
4327
  * Returns an instance of `SpecialCasedStyles` if and when any special (non animateable) styles are
3889
4328
  * detected.
@@ -3904,7 +4343,7 @@ function packageNonAnimatableStyles(element, styles) {
3904
4343
  endStyles = filterNonAnimatableStyles(styles[styles.length - 1]);
3905
4344
  }
3906
4345
  }
3907
- else if (styles) {
4346
+ else if (styles instanceof Map) {
3908
4347
  startStyles = filterNonAnimatableStyles(styles);
3909
4348
  }
3910
4349
  return (startStyles || endStyles) ? new SpecialCasedStyles(element, startStyles, endStyles) :
@@ -3926,7 +4365,7 @@ class SpecialCasedStyles {
3926
4365
  this._state = 0 /* Pending */;
3927
4366
  let initialStyles = SpecialCasedStyles.initialStylesByElement.get(_element);
3928
4367
  if (!initialStyles) {
3929
- SpecialCasedStyles.initialStylesByElement.set(_element, initialStyles = {});
4368
+ SpecialCasedStyles.initialStylesByElement.set(_element, initialStyles = new Map());
3930
4369
  }
3931
4370
  this._initialStyles = initialStyles;
3932
4371
  }
@@ -3969,453 +4408,18 @@ class SpecialCasedStyles {
3969
4408
  SpecialCasedStyles.initialStylesByElement = ( /* @__PURE__ */new WeakMap());
3970
4409
  function filterNonAnimatableStyles(styles) {
3971
4410
  let result = null;
3972
- const props = Object.keys(styles);
3973
- for (let i = 0; i < props.length; i++) {
3974
- const prop = props[i];
4411
+ styles.forEach((val, prop) => {
3975
4412
  if (isNonAnimatableStyle(prop)) {
3976
- result = result || {};
3977
- result[prop] = styles[prop];
4413
+ result = result || new Map();
4414
+ result.set(prop, val);
3978
4415
  }
3979
- }
4416
+ });
3980
4417
  return result;
3981
4418
  }
3982
4419
  function isNonAnimatableStyle(prop) {
3983
4420
  return prop === 'display' || prop === 'position';
3984
4421
  }
3985
4422
 
3986
- /**
3987
- * @license
3988
- * Copyright Google LLC All Rights Reserved.
3989
- *
3990
- * Use of this source code is governed by an MIT-style license that can be
3991
- * found in the LICENSE file at https://angular.io/license
3992
- */
3993
- const ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
3994
- const ANIMATION_PROP = 'animation';
3995
- const ANIMATIONEND_EVENT = 'animationend';
3996
- const ONE_SECOND = 1000;
3997
- class ElementAnimationStyleHandler {
3998
- constructor(_element, _name, _duration, _delay, _easing, _fillMode, _onDoneFn) {
3999
- this._element = _element;
4000
- this._name = _name;
4001
- this._duration = _duration;
4002
- this._delay = _delay;
4003
- this._easing = _easing;
4004
- this._fillMode = _fillMode;
4005
- this._onDoneFn = _onDoneFn;
4006
- this._finished = false;
4007
- this._destroyed = false;
4008
- this._startTime = 0;
4009
- this._position = 0;
4010
- this._eventFn = (e) => this._handleCallback(e);
4011
- }
4012
- apply() {
4013
- applyKeyframeAnimation(this._element, `${this._duration}ms ${this._easing} ${this._delay}ms 1 normal ${this._fillMode} ${this._name}`);
4014
- addRemoveAnimationEvent(this._element, this._eventFn, false);
4015
- this._startTime = Date.now();
4016
- }
4017
- pause() {
4018
- playPauseAnimation(this._element, this._name, 'paused');
4019
- }
4020
- resume() {
4021
- playPauseAnimation(this._element, this._name, 'running');
4022
- }
4023
- setPosition(position) {
4024
- const index = findIndexForAnimation(this._element, this._name);
4025
- this._position = position * this._duration;
4026
- setAnimationStyle(this._element, 'Delay', `-${this._position}ms`, index);
4027
- }
4028
- getPosition() {
4029
- return this._position;
4030
- }
4031
- _handleCallback(event) {
4032
- const timestamp = event._ngTestManualTimestamp || Date.now();
4033
- const elapsedTime = parseFloat(event.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES)) * ONE_SECOND;
4034
- if (event.animationName == this._name &&
4035
- Math.max(timestamp - this._startTime, 0) >= this._delay && elapsedTime >= this._duration) {
4036
- this.finish();
4037
- }
4038
- }
4039
- finish() {
4040
- if (this._finished)
4041
- return;
4042
- this._finished = true;
4043
- this._onDoneFn();
4044
- addRemoveAnimationEvent(this._element, this._eventFn, true);
4045
- }
4046
- destroy() {
4047
- if (this._destroyed)
4048
- return;
4049
- this._destroyed = true;
4050
- this.finish();
4051
- removeKeyframeAnimation(this._element, this._name);
4052
- }
4053
- }
4054
- function playPauseAnimation(element, name, status) {
4055
- const index = findIndexForAnimation(element, name);
4056
- setAnimationStyle(element, 'PlayState', status, index);
4057
- }
4058
- function applyKeyframeAnimation(element, value) {
4059
- const anim = getAnimationStyle(element, '').trim();
4060
- let index = 0;
4061
- if (anim.length) {
4062
- index = countChars(anim, ',') + 1;
4063
- value = `${anim}, ${value}`;
4064
- }
4065
- setAnimationStyle(element, '', value);
4066
- return index;
4067
- }
4068
- function removeKeyframeAnimation(element, name) {
4069
- const anim = getAnimationStyle(element, '');
4070
- const tokens = anim.split(',');
4071
- const index = findMatchingTokenIndex(tokens, name);
4072
- if (index >= 0) {
4073
- tokens.splice(index, 1);
4074
- const newValue = tokens.join(',');
4075
- setAnimationStyle(element, '', newValue);
4076
- }
4077
- }
4078
- function findIndexForAnimation(element, value) {
4079
- const anim = getAnimationStyle(element, '');
4080
- if (anim.indexOf(',') > 0) {
4081
- const tokens = anim.split(',');
4082
- return findMatchingTokenIndex(tokens, value);
4083
- }
4084
- return findMatchingTokenIndex([anim], value);
4085
- }
4086
- function findMatchingTokenIndex(tokens, searchToken) {
4087
- for (let i = 0; i < tokens.length; i++) {
4088
- if (tokens[i].indexOf(searchToken) >= 0) {
4089
- return i;
4090
- }
4091
- }
4092
- return -1;
4093
- }
4094
- function addRemoveAnimationEvent(element, fn, doRemove) {
4095
- doRemove ? element.removeEventListener(ANIMATIONEND_EVENT, fn) :
4096
- element.addEventListener(ANIMATIONEND_EVENT, fn);
4097
- }
4098
- function setAnimationStyle(element, name, value, index) {
4099
- const prop = ANIMATION_PROP + name;
4100
- if (index != null) {
4101
- const oldValue = element.style[prop];
4102
- if (oldValue.length) {
4103
- const tokens = oldValue.split(',');
4104
- tokens[index] = value;
4105
- value = tokens.join(',');
4106
- }
4107
- }
4108
- element.style[prop] = value;
4109
- }
4110
- function getAnimationStyle(element, name) {
4111
- return element.style[ANIMATION_PROP + name] || '';
4112
- }
4113
- function countChars(value, char) {
4114
- let count = 0;
4115
- for (let i = 0; i < value.length; i++) {
4116
- const c = value.charAt(i);
4117
- if (c === char)
4118
- count++;
4119
- }
4120
- return count;
4121
- }
4122
-
4123
- const DEFAULT_FILL_MODE = 'forwards';
4124
- const DEFAULT_EASING = 'linear';
4125
- class CssKeyframesPlayer {
4126
- constructor(element, keyframes, animationName, _duration, _delay, easing, _finalStyles, _specialStyles) {
4127
- this.element = element;
4128
- this.keyframes = keyframes;
4129
- this.animationName = animationName;
4130
- this._duration = _duration;
4131
- this._delay = _delay;
4132
- this._finalStyles = _finalStyles;
4133
- this._specialStyles = _specialStyles;
4134
- this._onDoneFns = [];
4135
- this._onStartFns = [];
4136
- this._onDestroyFns = [];
4137
- this.currentSnapshot = {};
4138
- this._state = 0;
4139
- this.easing = easing || DEFAULT_EASING;
4140
- this.totalTime = _duration + _delay;
4141
- this._buildStyler();
4142
- }
4143
- onStart(fn) {
4144
- this._onStartFns.push(fn);
4145
- }
4146
- onDone(fn) {
4147
- this._onDoneFns.push(fn);
4148
- }
4149
- onDestroy(fn) {
4150
- this._onDestroyFns.push(fn);
4151
- }
4152
- destroy() {
4153
- this.init();
4154
- if (this._state >= 4 /* DESTROYED */)
4155
- return;
4156
- this._state = 4 /* DESTROYED */;
4157
- this._styler.destroy();
4158
- this._flushStartFns();
4159
- this._flushDoneFns();
4160
- if (this._specialStyles) {
4161
- this._specialStyles.destroy();
4162
- }
4163
- this._onDestroyFns.forEach(fn => fn());
4164
- this._onDestroyFns = [];
4165
- }
4166
- _flushDoneFns() {
4167
- this._onDoneFns.forEach(fn => fn());
4168
- this._onDoneFns = [];
4169
- }
4170
- _flushStartFns() {
4171
- this._onStartFns.forEach(fn => fn());
4172
- this._onStartFns = [];
4173
- }
4174
- finish() {
4175
- this.init();
4176
- if (this._state >= 3 /* FINISHED */)
4177
- return;
4178
- this._state = 3 /* FINISHED */;
4179
- this._styler.finish();
4180
- this._flushStartFns();
4181
- if (this._specialStyles) {
4182
- this._specialStyles.finish();
4183
- }
4184
- this._flushDoneFns();
4185
- }
4186
- setPosition(value) {
4187
- this._styler.setPosition(value);
4188
- }
4189
- getPosition() {
4190
- return this._styler.getPosition();
4191
- }
4192
- hasStarted() {
4193
- return this._state >= 2 /* STARTED */;
4194
- }
4195
- init() {
4196
- if (this._state >= 1 /* INITIALIZED */)
4197
- return;
4198
- this._state = 1 /* INITIALIZED */;
4199
- const elm = this.element;
4200
- this._styler.apply();
4201
- if (this._delay) {
4202
- this._styler.pause();
4203
- }
4204
- }
4205
- play() {
4206
- this.init();
4207
- if (!this.hasStarted()) {
4208
- this._flushStartFns();
4209
- this._state = 2 /* STARTED */;
4210
- if (this._specialStyles) {
4211
- this._specialStyles.start();
4212
- }
4213
- }
4214
- this._styler.resume();
4215
- }
4216
- pause() {
4217
- this.init();
4218
- this._styler.pause();
4219
- }
4220
- restart() {
4221
- this.reset();
4222
- this.play();
4223
- }
4224
- reset() {
4225
- this._state = 0 /* RESET */;
4226
- this._styler.destroy();
4227
- this._buildStyler();
4228
- this._styler.apply();
4229
- }
4230
- _buildStyler() {
4231
- this._styler = new ElementAnimationStyleHandler(this.element, this.animationName, this._duration, this._delay, this.easing, DEFAULT_FILL_MODE, () => this.finish());
4232
- }
4233
- /** @internal */
4234
- triggerCallback(phaseName) {
4235
- const methods = phaseName == 'start' ? this._onStartFns : this._onDoneFns;
4236
- methods.forEach(fn => fn());
4237
- methods.length = 0;
4238
- }
4239
- beforeDestroy() {
4240
- this.init();
4241
- const styles = {};
4242
- if (this.hasStarted()) {
4243
- const finished = this._state >= 3 /* FINISHED */;
4244
- Object.keys(this._finalStyles).forEach(prop => {
4245
- if (prop != 'offset') {
4246
- styles[prop] = finished ? this._finalStyles[prop] : computeStyle(this.element, prop);
4247
- }
4248
- });
4249
- }
4250
- this.currentSnapshot = styles;
4251
- }
4252
- }
4253
-
4254
- /**
4255
- * @license
4256
- * Copyright Google LLC All Rights Reserved.
4257
- *
4258
- * Use of this source code is governed by an MIT-style license that can be
4259
- * found in the LICENSE file at https://angular.io/license
4260
- */
4261
- class DirectStylePlayer extends NoopAnimationPlayer {
4262
- constructor(element, styles) {
4263
- super();
4264
- this.element = element;
4265
- this._startingStyles = {};
4266
- this.__initialized = false;
4267
- this._styles = hypenatePropsObject(styles);
4268
- }
4269
- init() {
4270
- if (this.__initialized || !this._startingStyles)
4271
- return;
4272
- this.__initialized = true;
4273
- Object.keys(this._styles).forEach(prop => {
4274
- this._startingStyles[prop] = this.element.style[prop];
4275
- });
4276
- super.init();
4277
- }
4278
- play() {
4279
- if (!this._startingStyles)
4280
- return;
4281
- this.init();
4282
- Object.keys(this._styles)
4283
- .forEach(prop => this.element.style.setProperty(prop, this._styles[prop]));
4284
- super.play();
4285
- }
4286
- destroy() {
4287
- if (!this._startingStyles)
4288
- return;
4289
- Object.keys(this._startingStyles).forEach(prop => {
4290
- const value = this._startingStyles[prop];
4291
- if (value) {
4292
- this.element.style.setProperty(prop, value);
4293
- }
4294
- else {
4295
- this.element.style.removeProperty(prop);
4296
- }
4297
- });
4298
- this._startingStyles = null;
4299
- super.destroy();
4300
- }
4301
- }
4302
-
4303
- const KEYFRAMES_NAME_PREFIX = 'gen_css_kf_';
4304
- const TAB_SPACE = ' ';
4305
- class CssKeyframesDriver {
4306
- constructor() {
4307
- this._count = 0;
4308
- }
4309
- validateStyleProperty(prop) {
4310
- return validateStyleProperty(prop);
4311
- }
4312
- matchesElement(_element, _selector) {
4313
- // This method is deprecated and no longer in use so we return false.
4314
- return false;
4315
- }
4316
- containsElement(elm1, elm2) {
4317
- return containsElement(elm1, elm2);
4318
- }
4319
- query(element, selector, multi) {
4320
- return invokeQuery(element, selector, multi);
4321
- }
4322
- computeStyle(element, prop, defaultValue) {
4323
- return window.getComputedStyle(element)[prop];
4324
- }
4325
- buildKeyframeElement(element, name, keyframes) {
4326
- keyframes = keyframes.map(kf => hypenatePropsObject(kf));
4327
- let keyframeStr = `@keyframes ${name} {\n`;
4328
- let tab = '';
4329
- keyframes.forEach(kf => {
4330
- tab = TAB_SPACE;
4331
- const offset = parseFloat(kf['offset']);
4332
- keyframeStr += `${tab}${offset * 100}% {\n`;
4333
- tab += TAB_SPACE;
4334
- Object.keys(kf).forEach(prop => {
4335
- const value = kf[prop];
4336
- switch (prop) {
4337
- case 'offset':
4338
- return;
4339
- case 'easing':
4340
- if (value) {
4341
- keyframeStr += `${tab}animation-timing-function: ${value};\n`;
4342
- }
4343
- return;
4344
- default:
4345
- keyframeStr += `${tab}${prop}: ${value};\n`;
4346
- return;
4347
- }
4348
- });
4349
- keyframeStr += `${tab}}\n`;
4350
- });
4351
- keyframeStr += `}\n`;
4352
- const kfElm = document.createElement('style');
4353
- kfElm.textContent = keyframeStr;
4354
- return kfElm;
4355
- }
4356
- animate(element, keyframes, duration, delay, easing, previousPlayers = [], scrubberAccessRequested) {
4357
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && scrubberAccessRequested) {
4358
- notifyFaultyScrubber();
4359
- }
4360
- const previousCssKeyframePlayers = previousPlayers.filter(player => player instanceof CssKeyframesPlayer);
4361
- const previousStyles = {};
4362
- if (allowPreviousPlayerStylesMerge(duration, delay)) {
4363
- previousCssKeyframePlayers.forEach(player => {
4364
- let styles = player.currentSnapshot;
4365
- Object.keys(styles).forEach(prop => previousStyles[prop] = styles[prop]);
4366
- });
4367
- }
4368
- keyframes = balancePreviousStylesIntoKeyframes(element, keyframes, previousStyles);
4369
- const finalStyles = flattenKeyframesIntoStyles(keyframes);
4370
- // if there is no animation then there is no point in applying
4371
- // styles and waiting for an event to get fired. This causes lag.
4372
- // It's better to just directly apply the styles to the element
4373
- // via the direct styling animation player.
4374
- if (duration == 0) {
4375
- return new DirectStylePlayer(element, finalStyles);
4376
- }
4377
- const animationName = `${KEYFRAMES_NAME_PREFIX}${this._count++}`;
4378
- const kfElm = this.buildKeyframeElement(element, animationName, keyframes);
4379
- const nodeToAppendKfElm = findNodeToAppendKeyframeElement(element);
4380
- nodeToAppendKfElm.appendChild(kfElm);
4381
- const specialStyles = packageNonAnimatableStyles(element, keyframes);
4382
- const player = new CssKeyframesPlayer(element, keyframes, animationName, duration, delay, easing, finalStyles, specialStyles);
4383
- player.onDestroy(() => removeElement(kfElm));
4384
- return player;
4385
- }
4386
- }
4387
- function findNodeToAppendKeyframeElement(element) {
4388
- const rootNode = element.getRootNode?.();
4389
- if (typeof ShadowRoot !== 'undefined' && rootNode instanceof ShadowRoot) {
4390
- return rootNode;
4391
- }
4392
- return document.head;
4393
- }
4394
- function flattenKeyframesIntoStyles(keyframes) {
4395
- let flatKeyframes = {};
4396
- if (keyframes) {
4397
- const kfs = Array.isArray(keyframes) ? keyframes : [keyframes];
4398
- kfs.forEach(kf => {
4399
- Object.keys(kf).forEach(prop => {
4400
- if (prop == 'offset' || prop == 'easing')
4401
- return;
4402
- flatKeyframes[prop] = kf[prop];
4403
- });
4404
- });
4405
- }
4406
- return flatKeyframes;
4407
- }
4408
- function removeElement(node) {
4409
- node.parentNode.removeChild(node);
4410
- }
4411
- let warningIssued = false;
4412
- function notifyFaultyScrubber() {
4413
- if (warningIssued)
4414
- return;
4415
- console.warn('@angular/animations: please load the web-animations.js polyfill to allow programmatic access...\n', ' visit https://bit.ly/IWukam to learn more about using the web-animation-js polyfill.');
4416
- warningIssued = true;
4417
- }
4418
-
4419
4423
  class WebAnimationsPlayer {
4420
4424
  constructor(element, keyframes, options, _specialStyles) {
4421
4425
  this.element = element;
@@ -4431,7 +4435,7 @@ class WebAnimationsPlayer {
4431
4435
  this._destroyed = false;
4432
4436
  this.time = 0;
4433
4437
  this.parentPlayer = null;
4434
- this.currentSnapshot = {};
4438
+ this.currentSnapshot = new Map();
4435
4439
  this._duration = options['duration'];
4436
4440
  this._delay = options['delay'] || 0;
4437
4441
  this.time = this._duration + this._delay;
@@ -4454,7 +4458,7 @@ class WebAnimationsPlayer {
4454
4458
  const keyframes = this.keyframes;
4455
4459
  this.domPlayer =
4456
4460
  this._triggerWebAnimation(this.element, keyframes, this.options);
4457
- this._finalKeyframe = keyframes.length ? keyframes[keyframes.length - 1] : {};
4461
+ this._finalKeyframe = keyframes.length ? keyframes[keyframes.length - 1] : new Map();
4458
4462
  this.domPlayer.addEventListener('finish', () => this._onFinish());
4459
4463
  }
4460
4464
  _preparePlayerBeforeStart() {
@@ -4466,11 +4470,18 @@ class WebAnimationsPlayer {
4466
4470
  this.domPlayer.pause();
4467
4471
  }
4468
4472
  }
4473
+ _convertKeyframesToObject(keyframes) {
4474
+ const kfs = [];
4475
+ keyframes.forEach(frame => {
4476
+ kfs.push(Object.fromEntries(frame));
4477
+ });
4478
+ return kfs;
4479
+ }
4469
4480
  /** @internal */
4470
4481
  _triggerWebAnimation(element, keyframes, options) {
4471
4482
  // jscompiler doesn't seem to know animate is a native property because it's not fully
4472
4483
  // supported yet across common browsers (we polyfill it for Edge/Safari) [CL #143630929]
4473
- return element['animate'](keyframes, options);
4484
+ return element['animate'](this._convertKeyframesToObject(keyframes), options);
4474
4485
  }
4475
4486
  onStart(fn) {
4476
4487
  this._onStartFns.push(fn);
@@ -4548,15 +4559,15 @@ class WebAnimationsPlayer {
4548
4559
  return this._delay + this._duration;
4549
4560
  }
4550
4561
  beforeDestroy() {
4551
- const styles = {};
4562
+ const styles = new Map();
4552
4563
  if (this.hasStarted()) {
4553
4564
  // note: this code is invoked only when the `play` function was called prior to this
4554
4565
  // (thus `hasStarted` returns true), this implies that the code that initializes
4555
4566
  // `_finalKeyframe` has also been executed and the non-null assertion can be safely used here
4556
4567
  const finalKeyframe = this._finalKeyframe;
4557
- Object.keys(finalKeyframe).forEach(prop => {
4558
- if (prop != 'offset') {
4559
- styles[prop] = this._finished ? finalKeyframe[prop] : computeStyle(this.element, prop);
4568
+ finalKeyframe.forEach((val, prop) => {
4569
+ if (prop !== 'offset') {
4570
+ styles.set(prop, this._finished ? val : computeStyle(this.element, prop));
4560
4571
  }
4561
4572
  });
4562
4573
  }
@@ -4564,20 +4575,24 @@ class WebAnimationsPlayer {
4564
4575
  }
4565
4576
  /** @internal */
4566
4577
  triggerCallback(phaseName) {
4567
- const methods = phaseName == 'start' ? this._onStartFns : this._onDoneFns;
4578
+ const methods = phaseName === 'start' ? this._onStartFns : this._onDoneFns;
4568
4579
  methods.forEach(fn => fn());
4569
4580
  methods.length = 0;
4570
4581
  }
4571
4582
  }
4572
4583
 
4573
4584
  class WebAnimationsDriver {
4574
- constructor() {
4575
- this._isNativeImpl = /\{\s*\[native\s+code\]\s*\}/.test(getElementAnimateFn().toString());
4576
- this._cssKeyframesDriver = new CssKeyframesDriver();
4577
- }
4578
4585
  validateStyleProperty(prop) {
4579
4586
  return validateStyleProperty(prop);
4580
4587
  }
4588
+ validateAnimatableStyleProperty(prop) {
4589
+ // Perform actual validation in dev mode only, in prod mode this check is a noop.
4590
+ if (ngDevMode) {
4591
+ const cssProp = camelCaseToDashCase(prop);
4592
+ return validateWebAnimatableStyleProperty(cssProp);
4593
+ }
4594
+ return true;
4595
+ }
4581
4596
  matchesElement(_element, _selector) {
4582
4597
  // This method is deprecated and no longer in use so we return false.
4583
4598
  return false;
@@ -4585,20 +4600,16 @@ class WebAnimationsDriver {
4585
4600
  containsElement(elm1, elm2) {
4586
4601
  return containsElement(elm1, elm2);
4587
4602
  }
4603
+ getParentElement(element) {
4604
+ return getParentElement(element);
4605
+ }
4588
4606
  query(element, selector, multi) {
4589
4607
  return invokeQuery(element, selector, multi);
4590
4608
  }
4591
4609
  computeStyle(element, prop, defaultValue) {
4592
4610
  return window.getComputedStyle(element)[prop];
4593
4611
  }
4594
- overrideWebAnimationsSupport(supported) {
4595
- this._isNativeImpl = supported;
4596
- }
4597
- animate(element, keyframes, duration, delay, easing, previousPlayers = [], scrubberAccessRequested) {
4598
- const useKeyframes = !scrubberAccessRequested && !this._isNativeImpl;
4599
- if (useKeyframes) {
4600
- return this._cssKeyframesDriver.animate(element, keyframes, duration, delay, easing, previousPlayers);
4601
- }
4612
+ animate(element, keyframes, duration, delay, easing, previousPlayers = []) {
4602
4613
  const fill = delay == 0 ? 'both' : 'forwards';
4603
4614
  const playerOptions = { duration, delay, fill };
4604
4615
  // we check for this to avoid having a null|undefined value be present
@@ -4606,26 +4617,19 @@ class WebAnimationsDriver {
4606
4617
  if (easing) {
4607
4618
  playerOptions['easing'] = easing;
4608
4619
  }
4609
- const previousStyles = {};
4620
+ const previousStyles = new Map();
4610
4621
  const previousWebAnimationPlayers = previousPlayers.filter(player => player instanceof WebAnimationsPlayer);
4611
4622
  if (allowPreviousPlayerStylesMerge(duration, delay)) {
4612
4623
  previousWebAnimationPlayers.forEach(player => {
4613
- let styles = player.currentSnapshot;
4614
- Object.keys(styles).forEach(prop => previousStyles[prop] = styles[prop]);
4624
+ player.currentSnapshot.forEach((val, prop) => previousStyles.set(prop, val));
4615
4625
  });
4616
4626
  }
4617
- keyframes = keyframes.map(styles => copyStyles(styles, false));
4618
- keyframes = balancePreviousStylesIntoKeyframes(element, keyframes, previousStyles);
4619
- const specialStyles = packageNonAnimatableStyles(element, keyframes);
4620
- return new WebAnimationsPlayer(element, keyframes, playerOptions, specialStyles);
4627
+ let _keyframes = normalizeKeyframes(keyframes).map(styles => copyStyles(styles));
4628
+ _keyframes = balancePreviousStylesIntoKeyframes(element, _keyframes, previousStyles);
4629
+ const specialStyles = packageNonAnimatableStyles(element, _keyframes);
4630
+ return new WebAnimationsPlayer(element, _keyframes, playerOptions, specialStyles);
4621
4631
  }
4622
4632
  }
4623
- function supportsWebAnimations() {
4624
- return typeof getElementAnimateFn() === 'function';
4625
- }
4626
- function getElementAnimateFn() {
4627
- return (isBrowser() && Element.prototype['animate']) || {};
4628
- }
4629
4633
 
4630
4634
  /**
4631
4635
  * @license
@@ -4663,5 +4667,5 @@ function getElementAnimateFn() {
4663
4667
  * Generated bundle index. Do not edit.
4664
4668
  */
4665
4669
 
4666
- export { AnimationDriver, Animation as ɵAnimation, AnimationEngine as ɵAnimationEngine, AnimationStyleNormalizer as ɵAnimationStyleNormalizer, CssKeyframesDriver as ɵCssKeyframesDriver, CssKeyframesPlayer as ɵCssKeyframesPlayer, NoopAnimationDriver as ɵNoopAnimationDriver, NoopAnimationStyleNormalizer as ɵNoopAnimationStyleNormalizer, WebAnimationsDriver as ɵWebAnimationsDriver, WebAnimationsPlayer as ɵWebAnimationsPlayer, WebAnimationsStyleNormalizer as ɵWebAnimationsStyleNormalizer, allowPreviousPlayerStylesMerge as ɵallowPreviousPlayerStylesMerge, containsElement as ɵcontainsElement, invokeQuery as ɵinvokeQuery, supportsWebAnimations as ɵsupportsWebAnimations, validateStyleProperty as ɵvalidateStyleProperty };
4670
+ export { AnimationDriver, Animation as ɵAnimation, AnimationEngine as ɵAnimationEngine, AnimationStyleNormalizer as ɵAnimationStyleNormalizer, NoopAnimationDriver as ɵNoopAnimationDriver, NoopAnimationStyleNormalizer as ɵNoopAnimationStyleNormalizer, WebAnimationsDriver as ɵWebAnimationsDriver, WebAnimationsPlayer as ɵWebAnimationsPlayer, WebAnimationsStyleNormalizer as ɵWebAnimationsStyleNormalizer, allowPreviousPlayerStylesMerge as ɵallowPreviousPlayerStylesMerge, containsElement as ɵcontainsElement, getParentElement as ɵgetParentElement, invokeQuery as ɵinvokeQuery, normalizeKeyframes as ɵnormalizeKeyframes, validateStyleProperty as ɵvalidateStyleProperty };
4667
4671
  //# sourceMappingURL=browser.mjs.map