@angular/core 20.2.0-rc.1 → 20.2.1

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 (69) hide show
  1. package/api.d.d.ts +1 -1
  2. package/chrome_dev_tools_performance.d.d.ts +1 -1
  3. package/discovery.d.d.ts +1 -1
  4. package/event_dispatcher.d.d.ts +1 -1
  5. package/fesm2022/attribute.mjs +1 -1
  6. package/fesm2022/attribute.mjs.map +1 -1
  7. package/fesm2022/core.mjs +4 -4
  8. package/fesm2022/core.mjs.map +1 -1
  9. package/fesm2022/debug_node.mjs +142 -82
  10. package/fesm2022/debug_node.mjs.map +1 -1
  11. package/fesm2022/not_found.mjs +1 -1
  12. package/fesm2022/not_found.mjs.map +1 -1
  13. package/fesm2022/primitives/di.mjs +1 -1
  14. package/fesm2022/primitives/di.mjs.map +1 -1
  15. package/fesm2022/primitives/event-dispatch.mjs +1 -1
  16. package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
  17. package/fesm2022/primitives/signals.mjs +1 -1
  18. package/fesm2022/primitives/signals.mjs.map +1 -1
  19. package/fesm2022/resource.mjs +1 -1
  20. package/fesm2022/resource.mjs.map +1 -1
  21. package/fesm2022/root_effect_scheduler.mjs +1 -1
  22. package/fesm2022/root_effect_scheduler.mjs.map +1 -1
  23. package/fesm2022/rxjs-interop.mjs +1 -1
  24. package/fesm2022/rxjs-interop.mjs.map +1 -1
  25. package/fesm2022/signal.mjs +1 -1
  26. package/fesm2022/signal.mjs.map +1 -1
  27. package/fesm2022/testing.mjs +1 -1
  28. package/fesm2022/testing.mjs.map +1 -1
  29. package/fesm2022/untracked.mjs +1 -1
  30. package/fesm2022/untracked.mjs.map +1 -1
  31. package/fesm2022/weak_ref.mjs +1 -1
  32. package/fesm2022/weak_ref.mjs.map +1 -1
  33. package/graph.d.d.ts +1 -1
  34. package/index.d.ts +5 -5
  35. package/package.json +2 -2
  36. package/primitives/di/index.d.ts +1 -1
  37. package/primitives/event-dispatch/index.d.ts +1 -1
  38. package/primitives/signals/index.d.ts +1 -1
  39. package/rxjs-interop/index.d.ts +1 -1
  40. package/schematics/bundles/{apply_import_manager-OJAv7nyR.cjs → apply_import_manager-BvwNQhfG.cjs} +3 -3
  41. package/schematics/bundles/cleanup-unused-imports.cjs +5 -5
  42. package/schematics/bundles/{compiler_host-GMENszSm.cjs → compiler_host-DbXQvYKt.cjs} +2 -2
  43. package/schematics/bundles/control-flow-migration.cjs +3 -3
  44. package/schematics/bundles/document-core.cjs +5 -5
  45. package/schematics/bundles/imports-CIX-JgAN.cjs +1 -1
  46. package/schematics/bundles/{index-CvCDOy8a.cjs → index-Bcv0dPD8.cjs} +15 -14
  47. package/schematics/bundles/{index-C0gVsyDQ.cjs → index-Bphk20D_.cjs} +4 -4
  48. package/schematics/bundles/inject-flags.cjs +5 -5
  49. package/schematics/bundles/inject-migration.cjs +3 -3
  50. package/schematics/bundles/leading_space-D9nQ8UQC.cjs +1 -1
  51. package/schematics/bundles/{migrate_ts_type_references-ByPRdLHL.cjs → migrate_ts_type_references-xcaijJqF.cjs} +5 -5
  52. package/schematics/bundles/ng_decorators-B5HCqr20.cjs +1 -1
  53. package/schematics/bundles/nodes-B16H9JUd.cjs +1 -1
  54. package/schematics/bundles/output-migration.cjs +6 -6
  55. package/schematics/bundles/{project_paths-BfWTWKz0.cjs → project_paths-BaK5P5a5.cjs} +3 -3
  56. package/schematics/bundles/{project_tsconfig_paths-Bhn4jDr1.cjs → project_tsconfig_paths-COqholMT.cjs} +183 -18
  57. package/schematics/bundles/property_name-BBwFuqMe.cjs +1 -1
  58. package/schematics/bundles/route-lazy-loading.cjs +3 -3
  59. package/schematics/bundles/router-current-navigation.cjs +4 -4
  60. package/schematics/bundles/self-closing-tags-migration.cjs +4 -4
  61. package/schematics/bundles/signal-input-migration.cjs +7 -7
  62. package/schematics/bundles/signal-queries-migration.cjs +7 -7
  63. package/schematics/bundles/signals.cjs +7 -7
  64. package/schematics/bundles/standalone-migration.cjs +4 -4
  65. package/schematics/bundles/symbol-VPWguRxr.cjs +1 -1
  66. package/schematics/bundles/test-bed-get.cjs +4 -4
  67. package/signal.d.d.ts +1 -1
  68. package/testing/index.d.ts +2 -2
  69. package/weak_ref.d.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v20.2.0-rc.1
2
+ * @license Angular v20.2.1
3
3
  * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -13515,7 +13515,7 @@ class ComponentFactory extends ComponentFactory$1 {
13515
13515
  }
13516
13516
  function createRootTView(rootSelectorOrNode, componentDef, componentBindings, directives) {
13517
13517
  const tAttributes = rootSelectorOrNode
13518
- ? ['ng-version', '20.2.0-rc.1']
13518
+ ? ['ng-version', '20.2.1']
13519
13519
  : // Extract attributes and classes from the first selector only to match VE behavior.
13520
13520
  extractAttrsAndClassesFromSelector(componentDef.selectors[0]);
13521
13521
  let creationBindings = null;
@@ -13639,7 +13639,7 @@ class ComponentRef extends ComponentRef$1 {
13639
13639
  if (ngDevMode && !hasSetInput) {
13640
13640
  const cmpNameForError = stringifyForError(this.componentType);
13641
13641
  let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `;
13642
- message += `Make sure that the '${name}' property is declared as an input using the @Input() decorator or the input() function.`;
13642
+ message += `Make sure that the '${name}' property is declared as an input using the input() or model() function or the @Input() decorator.`;
13643
13643
  reportUnknownPropertyError(message);
13644
13644
  }
13645
13645
  }
@@ -21882,6 +21882,13 @@ function getLongestComputedAnimation(computedStyle) {
21882
21882
  }
21883
21883
  return longest;
21884
21884
  }
21885
+ function isShorterThanExistingAnimation(existing, longest) {
21886
+ return existing !== undefined && existing.duration > longest.duration;
21887
+ }
21888
+ function longestExists(longest) {
21889
+ return ((longest.animationName != undefined || longest.propertyName != undefined) &&
21890
+ longest.duration > 0);
21891
+ }
21885
21892
  /**
21886
21893
  * Determines the longest animation, but with `getComputedStyles` instead of `getAnimations`. This
21887
21894
  * is ultimately safer than getAnimations because it can be used when recalculations are in
@@ -21892,10 +21899,11 @@ function determineLongestAnimationFromComputedStyles(el, animationsMap) {
21892
21899
  const longestAnimation = getLongestComputedAnimation(computedStyle);
21893
21900
  const longestTransition = getLongestComputedTransition(computedStyle);
21894
21901
  const longest = longestAnimation.duration > longestTransition.duration ? longestAnimation : longestTransition;
21895
- if (animationsMap.has(el) && animationsMap.get(el).duration > longest.duration) {
21902
+ if (isShorterThanExistingAnimation(animationsMap.get(el), longest))
21896
21903
  return;
21904
+ if (longestExists(longest)) {
21905
+ animationsMap.set(el, longest);
21897
21906
  }
21898
- animationsMap.set(el, longest);
21899
21907
  }
21900
21908
  /**
21901
21909
  * Multiple animations can be set on an element. This grabs an element and
@@ -21904,8 +21912,8 @@ function determineLongestAnimationFromComputedStyles(el, animationsMap) {
21904
21912
  * This ensures we get the longest running animation and only remove when
21905
21913
  * that animation completes.
21906
21914
  */
21907
- function determineLongestAnimation(event, el, animationsMap, areAnimationSupported) {
21908
- if (!areAnimationSupported || !(event.target instanceof Element) || event.target !== el)
21915
+ function determineLongestAnimation(el, animationsMap, areAnimationSupported) {
21916
+ if (!areAnimationSupported)
21909
21917
  return;
21910
21918
  const animations = el.getAnimations();
21911
21919
  return animations.length === 0
@@ -21915,7 +21923,7 @@ function determineLongestAnimation(event, el, animationsMap, areAnimationSupport
21915
21923
  : determineLongestAnimationFromElementAnimations(el, animationsMap, animations);
21916
21924
  }
21917
21925
  function determineLongestAnimationFromElementAnimations(el, animationsMap, animations) {
21918
- let currentLongest = {
21926
+ let longest = {
21919
21927
  animationName: undefined,
21920
21928
  propertyName: undefined,
21921
21929
  duration: 0,
@@ -21934,14 +21942,15 @@ function determineLongestAnimationFromElementAnimations(el, animationsMap, anima
21934
21942
  // Check for CSSTransition specific property
21935
21943
  propertyName = animation.transitionProperty;
21936
21944
  }
21937
- if (duration >= currentLongest.duration) {
21938
- currentLongest = { animationName, propertyName, duration };
21945
+ if (duration >= longest.duration) {
21946
+ longest = { animationName, propertyName, duration };
21939
21947
  }
21940
21948
  }
21941
- if (animationsMap.has(el) && animationsMap.get(el).duration > currentLongest.duration) {
21949
+ if (isShorterThanExistingAnimation(animationsMap.get(el), longest))
21942
21950
  return;
21951
+ if (longestExists(longest)) {
21952
+ animationsMap.set(el, longest);
21943
21953
  }
21944
- animationsMap.set(el, currentLongest);
21945
21954
  }
21946
21955
 
21947
21956
  const DEFAULT_ANIMATIONS_DISABLED = false;
@@ -21949,6 +21958,36 @@ const areAnimationSupported = (typeof ngServerMode === 'undefined' || !ngServerM
21949
21958
  typeof document !== 'undefined' &&
21950
21959
  // tslint:disable-next-line:no-toplevel-property-access
21951
21960
  typeof document?.documentElement?.getAnimations === 'function';
21961
+ /**
21962
+ * Helper function to check if animations are disabled via injection token
21963
+ */
21964
+ function areAnimationsDisabled(lView) {
21965
+ const injector = lView[INJECTOR];
21966
+ return injector.get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
21967
+ }
21968
+ /**
21969
+ * Helper function to setup element registry cleanup when LView is destroyed
21970
+ */
21971
+ function setupElementRegistryCleanup(elementRegistry, lView, tView, nativeElement) {
21972
+ if (lView[FLAGS] & 8 /* LViewFlags.FirstLViewPass */) {
21973
+ storeCleanupWithContext(tView, lView, nativeElement, (elToClean) => {
21974
+ elementRegistry.elements.remove(elToClean);
21975
+ });
21976
+ }
21977
+ }
21978
+ /**
21979
+ * Helper function to cleanup enterClassMap data safely
21980
+ */
21981
+ function cleanupEnterClassData(element) {
21982
+ const elementData = enterClassMap.get(element);
21983
+ if (elementData) {
21984
+ for (const fn of elementData.cleanupFns) {
21985
+ fn();
21986
+ }
21987
+ enterClassMap.delete(element);
21988
+ }
21989
+ longestAnimations.delete(element);
21990
+ }
21952
21991
  const noOpAnimationComplete = () => { };
21953
21992
  // Tracks the list of classes added to a DOM node from `animate.enter` calls to ensure
21954
21993
  // we remove all of the classes in the case of animation composition via host bindings.
@@ -21958,10 +21997,26 @@ const longestAnimations = new WeakMap();
21958
21997
  // used to prevent duplicate nodes from showing up when nodes have been toggled quickly
21959
21998
  // from an `@if` or `@for`.
21960
21999
  const leavingNodes = new WeakMap();
22000
+ function clearLeavingNodes(tNode) {
22001
+ if (leavingNodes.get(tNode)?.length === 0) {
22002
+ leavingNodes.delete(tNode);
22003
+ }
22004
+ }
22005
+ function trackLeavingNodes(tNode, el) {
22006
+ // We need to track this tNode's element just to be sure we don't add
22007
+ // a new RNode for this TNode while this one is still animating away.
22008
+ // once the animation is complete, we remove this reference.
22009
+ if (leavingNodes.has(tNode)) {
22010
+ leavingNodes.get(tNode)?.push(el);
22011
+ }
22012
+ else {
22013
+ leavingNodes.set(tNode, [el]);
22014
+ }
22015
+ }
21961
22016
  /**
21962
22017
  * Instruction to handle the `animate.enter` behavior for class bindings.
21963
22018
  *
21964
- * @param value The value bound to `animate.enter`, which is a string or a string array.
22019
+ * @param value The value bound to `animate.enter`, which is a string or a function.
21965
22020
  * @returns This function returns itself so that it may be chained.
21966
22021
  *
21967
22022
  * @codeGenApi
@@ -21973,15 +22028,13 @@ function ɵɵanimateEnter(value) {
21973
22028
  }
21974
22029
  ngDevMode && assertAnimationTypes(value, 'animate.enter');
21975
22030
  const lView = getLView();
22031
+ if (areAnimationsDisabled(lView)) {
22032
+ return ɵɵanimateEnter;
22033
+ }
21976
22034
  const tNode = getCurrentTNode();
21977
22035
  const nativeElement = getNativeByTNode(tNode, lView);
21978
22036
  const renderer = lView[RENDERER];
21979
- const injector = lView[INJECTOR];
21980
- const animationsDisabled = injector.get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
21981
- const ngZone = injector.get(NgZone);
21982
- if (animationsDisabled) {
21983
- return ɵɵanimateEnter;
21984
- }
22037
+ const ngZone = lView[INJECTOR].get(NgZone);
21985
22038
  // Retrieve the actual class list from the value. This will resolve any resolver functions from
21986
22039
  // bindings.
21987
22040
  const activeClasses = getClassListFromValue(value);
@@ -21991,7 +22044,6 @@ function ɵɵanimateEnter(value) {
21991
22044
  // This also allows us to setup cancellation of animations in progress if the
21992
22045
  // gets removed early.
21993
22046
  const handleAnimationStart = (event) => {
21994
- determineLongestAnimation(event, nativeElement, longestAnimations, areAnimationSupported);
21995
22047
  setupAnimationCancel(event, renderer);
21996
22048
  const eventName = event instanceof AnimationEvent ? 'animationend' : 'transitionend';
21997
22049
  ngZone.runOutsideAngular(() => {
@@ -22000,7 +22052,7 @@ function ɵɵanimateEnter(value) {
22000
22052
  };
22001
22053
  // When the longest animation ends, we can remove all the classes
22002
22054
  const handleInAnimationEnd = (event) => {
22003
- animationEnd(event, nativeElement, renderer, cleanupFns);
22055
+ animationEnd(event, nativeElement, renderer);
22004
22056
  };
22005
22057
  // We only need to add these event listeners if there are actual classes to apply
22006
22058
  if (activeClasses && activeClasses.length > 0) {
@@ -22020,6 +22072,20 @@ function ɵɵanimateEnter(value) {
22020
22072
  for (const klass of activeClasses) {
22021
22073
  renderer.addClass(nativeElement, klass);
22022
22074
  }
22075
+ // In the case that the classes added have no animations, we need to remove
22076
+ // the classes right away. This could happen because someone is intentionally
22077
+ // preventing an animation via selector specificity.
22078
+ ngZone.runOutsideAngular(() => {
22079
+ requestAnimationFrame(() => {
22080
+ determineLongestAnimation(nativeElement, longestAnimations, areAnimationSupported);
22081
+ if (!longestAnimations.has(nativeElement)) {
22082
+ for (const klass of activeClasses) {
22083
+ renderer.removeClass(nativeElement, klass);
22084
+ }
22085
+ cleanupEnterClassData(nativeElement);
22086
+ }
22087
+ });
22088
+ });
22023
22089
  }
22024
22090
  return ɵɵanimateEnter; // For chaining
22025
22091
  }
@@ -22059,12 +22125,19 @@ function ɵɵanimateEnterListener(value) {
22059
22125
  }
22060
22126
  ngDevMode && assertAnimationTypes(value, 'animate.enter');
22061
22127
  const lView = getLView();
22062
- const tNode = getCurrentTNode();
22063
- const nativeElement = getNativeByTNode(tNode, lView);
22064
- const animationsDisabled = lView[INJECTOR].get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
22065
- if (animationsDisabled) {
22128
+ if (areAnimationsDisabled(lView)) {
22066
22129
  return ɵɵanimateEnterListener;
22067
22130
  }
22131
+ const tNode = getCurrentTNode();
22132
+ const nativeElement = getNativeByTNode(tNode, lView);
22133
+ // In the case that we have an existing node that's animating away, like when
22134
+ // an `@if` toggles quickly or `@for` adds and removes elements quickly, we
22135
+ // need to end the animation for the former node and remove it right away to
22136
+ // prevent duplicate nodes showing up.
22137
+ leavingNodes
22138
+ .get(tNode)
22139
+ ?.pop()
22140
+ ?.dispatchEvent(new CustomEvent('animationend', { detail: { cancel: true } }));
22068
22141
  value.call(lView[CONTEXT], { target: nativeElement, animationComplete: noOpAnimationComplete });
22069
22142
  return ɵɵanimateEnterListener;
22070
22143
  }
@@ -22073,7 +22146,7 @@ function ɵɵanimateEnterListener(value) {
22073
22146
  * It registers an animation with the ElementRegistry to be run when the element
22074
22147
  * is scheduled for removal from the DOM.
22075
22148
  *
22076
- * @param value The value bound to `animate.leave`, which can be a string or string array.
22149
+ * @param value The value bound to `animate.leave`, which can be a string or a function.
22077
22150
  * @returns This function returns itself so that it may be chained.
22078
22151
  *
22079
22152
  * @codeGenApi
@@ -22085,18 +22158,19 @@ function ɵɵanimateLeave(value) {
22085
22158
  }
22086
22159
  ngDevMode && assertAnimationTypes(value, 'animate.leave');
22087
22160
  const lView = getLView();
22161
+ const animationsDisabled = areAnimationsDisabled(lView);
22162
+ if (animationsDisabled) {
22163
+ return ɵɵanimateLeave;
22164
+ }
22088
22165
  const tView = getTView();
22089
22166
  const tNode = getCurrentTNode();
22090
22167
  const nativeElement = getNativeByTNode(tNode, lView);
22091
22168
  // This instruction is called in the update pass.
22092
22169
  const renderer = lView[RENDERER];
22093
- const injector = lView[INJECTOR];
22094
- // Assume ElementRegistry and ANIMATIONS_DISABLED are injectable services.
22095
22170
  const elementRegistry = getAnimationElementRemovalRegistry();
22096
22171
  ngDevMode &&
22097
22172
  assertDefined(elementRegistry.elements, 'Expected `ElementRegistry` to be present in animations subsystem');
22098
- const animationsDisabled = injector.get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
22099
- const ngZone = injector.get(NgZone);
22173
+ const ngZone = lView[INJECTOR].get(NgZone);
22100
22174
  // This function gets stashed in the registry to be used once the element removal process
22101
22175
  // begins. We pass in the values and resolvers so as to evaluate the resolved classes
22102
22176
  // at the latest possible time, meaning we evaluate them right before the animation
@@ -22107,11 +22181,7 @@ function ɵɵanimateLeave(value) {
22107
22181
  };
22108
22182
  };
22109
22183
  // Ensure cleanup if the LView is destroyed before the animation runs.
22110
- if (lView[FLAGS] & 8 /* LViewFlags.FirstLViewPass */) {
22111
- storeCleanupWithContext(tView, lView, nativeElement, (elToClean) => {
22112
- elementRegistry.elements.remove(elToClean);
22113
- });
22114
- }
22184
+ setupElementRegistryCleanup(elementRegistry, lView, tView, nativeElement);
22115
22185
  elementRegistry.elements.add(nativeElement, value, animate);
22116
22186
  return ɵɵanimateLeave; // For chaining
22117
22187
  }
@@ -22132,6 +22202,9 @@ function ɵɵanimateLeaveListener(value) {
22132
22202
  return ɵɵanimateLeaveListener;
22133
22203
  }
22134
22204
  ngDevMode && assertAnimationTypes(value, 'animate.leave');
22205
+ // Even when animations are disabled, we still need to register the element for removal
22206
+ // to ensure proper cleanup and allow developers to handle element removal in tests
22207
+ // So we don't have an early return here.
22135
22208
  const lView = getLView();
22136
22209
  const tNode = getCurrentTNode();
22137
22210
  const tView = getTView();
@@ -22139,13 +22212,13 @@ function ɵɵanimateLeaveListener(value) {
22139
22212
  if (nativeElement.nodeType !== Node.ELEMENT_NODE) {
22140
22213
  return ɵɵanimateLeaveListener;
22141
22214
  }
22142
- // Assume ElementRegistry and ANIMATIONS_DISABLED are injectable services.
22143
- const injector = lView[INJECTOR];
22144
22215
  const elementRegistry = getAnimationElementRemovalRegistry();
22145
22216
  ngDevMode &&
22146
22217
  assertDefined(elementRegistry.elements, 'Expected `ElementRegistry` to be present in animations subsystem');
22147
- const animationsDisabled = injector.get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
22148
- const animate = (el, value) => {
22218
+ const renderer = lView[RENDERER];
22219
+ const animationsDisabled = areAnimationsDisabled(lView);
22220
+ const ngZone = lView[INJECTOR].get(NgZone);
22221
+ const animate = (_el, value) => {
22149
22222
  return (removeFn) => {
22150
22223
  if (animationsDisabled) {
22151
22224
  removeFn();
@@ -22154,19 +22227,20 @@ function ɵɵanimateLeaveListener(value) {
22154
22227
  const event = {
22155
22228
  target: nativeElement,
22156
22229
  animationComplete: () => {
22230
+ clearLeavingNodes(tNode);
22157
22231
  removeFn();
22158
22232
  },
22159
22233
  };
22234
+ trackLeavingNodes(tNode, _el);
22235
+ ngZone.runOutsideAngular(() => {
22236
+ renderer.listen(_el, 'animationend', () => removeFn(), { once: true });
22237
+ });
22160
22238
  value.call(lView[CONTEXT], event);
22161
22239
  }
22162
22240
  };
22163
22241
  };
22164
22242
  // Ensure cleanup if the LView is destroyed before the animation runs.
22165
- if (lView[FLAGS] & 8 /* LViewFlags.FirstLViewPass */) {
22166
- storeCleanupWithContext(tView, lView, nativeElement, (elToClean) => {
22167
- elementRegistry.elements.remove(elToClean);
22168
- });
22169
- }
22243
+ setupElementRegistryCleanup(elementRegistry, lView, tView, nativeElement);
22170
22244
  elementRegistry.elements.addCallback(nativeElement, value, animate);
22171
22245
  return ɵɵanimateLeaveListener; // For chaining
22172
22246
  }
@@ -22211,13 +22285,7 @@ function cancelAnimationsIfRunning(element, renderer) {
22211
22285
  }
22212
22286
  }
22213
22287
  // We need to prevent any enter animation listeners from firing if they exist.
22214
- if (elementData) {
22215
- for (const fn of elementData.cleanupFns) {
22216
- fn();
22217
- }
22218
- }
22219
- longestAnimations.delete(element);
22220
- enterClassMap.delete(element);
22288
+ cleanupEnterClassData(element);
22221
22289
  }
22222
22290
  function setupAnimationCancel(event, renderer) {
22223
22291
  if (!(event.target instanceof Element))
@@ -22248,7 +22316,7 @@ function isLongestAnimation(event, nativeElement) {
22248
22316
  (longestAnimation.propertyName !== undefined &&
22249
22317
  event.propertyName === longestAnimation.propertyName)));
22250
22318
  }
22251
- function animationEnd(event, nativeElement, renderer, cleanupFns) {
22319
+ function animationEnd(event, nativeElement, renderer) {
22252
22320
  const elementData = enterClassMap.get(nativeElement);
22253
22321
  if (!elementData)
22254
22322
  return;
@@ -22261,11 +22329,7 @@ function animationEnd(event, nativeElement, renderer, cleanupFns) {
22261
22329
  for (const klass of elementData.classList) {
22262
22330
  renderer.removeClass(nativeElement, klass);
22263
22331
  }
22264
- enterClassMap.delete(nativeElement);
22265
- longestAnimations.delete(nativeElement);
22266
- for (const fn of cleanupFns) {
22267
- fn();
22268
- }
22332
+ cleanupEnterClassData(nativeElement);
22269
22333
  }
22270
22334
  }
22271
22335
  function assertAnimationTypes(value, instruction) {
@@ -22281,11 +22345,9 @@ function animateLeaveClassRunner(el, tNode, classList, finalRemoveFn, renderer,
22281
22345
  if (animationsDisabled) {
22282
22346
  longestAnimations.delete(el);
22283
22347
  finalRemoveFn();
22348
+ return;
22284
22349
  }
22285
22350
  cancelAnimationsIfRunning(el, renderer);
22286
- const handleAnimationStart = (event) => {
22287
- determineLongestAnimation(event, el, longestAnimations, areAnimationSupported);
22288
- };
22289
22351
  const handleOutAnimationEnd = (event) => {
22290
22352
  if (event instanceof CustomEvent || isLongestAnimation(event, el)) {
22291
22353
  // Now that we've found the longest animation, there's no need
@@ -22294,32 +22356,30 @@ function animateLeaveClassRunner(el, tNode, classList, finalRemoveFn, renderer,
22294
22356
  // affect any other animations on the page.
22295
22357
  event.stopImmediatePropagation();
22296
22358
  longestAnimations.delete(el);
22297
- if (leavingNodes.get(tNode)?.length === 0) {
22298
- leavingNodes.delete(tNode);
22299
- }
22359
+ clearLeavingNodes(tNode);
22300
22360
  finalRemoveFn();
22301
22361
  }
22302
22362
  };
22303
- if (!animationsDisabled) {
22304
- ngZone.runOutsideAngular(() => {
22305
- renderer.listen(el, 'animationstart', handleAnimationStart, { once: true });
22306
- renderer.listen(el, 'transitionstart', handleAnimationStart, { once: true });
22307
- renderer.listen(el, 'animationend', handleOutAnimationEnd);
22308
- renderer.listen(el, 'transitionend', handleOutAnimationEnd);
22363
+ ngZone.runOutsideAngular(() => {
22364
+ renderer.listen(el, 'animationend', handleOutAnimationEnd);
22365
+ renderer.listen(el, 'transitionend', handleOutAnimationEnd);
22366
+ });
22367
+ trackLeavingNodes(tNode, el);
22368
+ for (const item of classList) {
22369
+ renderer.addClass(el, item);
22370
+ }
22371
+ // In the case that the classes added have no animations, we need to remove
22372
+ // the element right away. This could happen because someone is intentionally
22373
+ // preventing an animation via selector specificity.
22374
+ ngZone.runOutsideAngular(() => {
22375
+ requestAnimationFrame(() => {
22376
+ determineLongestAnimation(el, longestAnimations, areAnimationSupported);
22377
+ if (!longestAnimations.has(el)) {
22378
+ clearLeavingNodes(tNode);
22379
+ finalRemoveFn();
22380
+ }
22309
22381
  });
22310
- // We need to track this tNode's element just to be sure we don't add
22311
- // a new RNode for this TNode while this one is still animating away.
22312
- // once the animation is complete, we remove this reference.
22313
- if (leavingNodes.has(tNode)) {
22314
- leavingNodes.get(tNode)?.push(el);
22315
- }
22316
- else {
22317
- leavingNodes.set(tNode, [el]);
22318
- }
22319
- for (const item of classList) {
22320
- renderer.addClass(el, item);
22321
- }
22322
- }
22382
+ });
22323
22383
  }
22324
22384
 
22325
22385
  /*!