@angular/core 20.2.0-rc.0 → 20.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +2 -8
  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 +9 -12
  8. package/fesm2022/core.mjs.map +1 -1
  9. package/fesm2022/debug_node.mjs +144 -93
  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 +2 -11
  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 +7 -15
  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-BDpMzDvN.cjs → apply_import_manager-Ch1hTvRS.cjs} +3 -3
  41. package/schematics/bundles/cleanup-unused-imports.cjs +5 -5
  42. package/schematics/bundles/{compiler_host-GNtX_RDe.cjs → compiler_host-CqB0JPzD.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-czXpbmcu.cjs → index-COhCBz0q.cjs} +4 -4
  47. package/schematics/bundles/{index-BrQFpkJq.cjs → index-DwItZ4Tw.cjs} +20 -21
  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-DLVVfu8Y.cjs → migrate_ts_type_references-BMhLua30.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-pSh0WpBI.cjs → project_paths-OWnyHise.cjs} +3 -3
  56. package/schematics/bundles/{project_tsconfig_paths-Cy7U7awR.cjs → project_tsconfig_paths-BIeidc3E.cjs} +168 -22
  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.0
2
+ * @license Angular v20.2.0
3
3
  * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -4896,12 +4896,6 @@ var ViewEncapsulation;
4896
4896
  * all the Component's styling.
4897
4897
  */
4898
4898
  ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
4899
- /**
4900
- * Similar to `ShadowDom`, but prevents any external styles from leaking into the
4901
- * component's ShadowRoot. This is useful when you want to ensure that the component's
4902
- * styles are completely isolated from the rest of the application, including global styles.
4903
- */
4904
- ViewEncapsulation[ViewEncapsulation["IsolatedShadowDom"] = 4] = "IsolatedShadowDom";
4905
4899
  })(ViewEncapsulation || (ViewEncapsulation = {}));
4906
4900
 
4907
4901
  /**
@@ -7996,9 +7990,7 @@ function locateHostElement(renderer, elementOrSelector, encapsulation, injector)
7996
7990
  const preserveHostContent = injector.get(PRESERVE_HOST_CONTENT, PRESERVE_HOST_CONTENT_DEFAULT);
7997
7991
  // When using native Shadow DOM, do not clear host element to allow native slot
7998
7992
  // projection.
7999
- const preserveContent = preserveHostContent ||
8000
- encapsulation === ViewEncapsulation.ShadowDom ||
8001
- encapsulation === ViewEncapsulation.IsolatedShadowDom;
7993
+ const preserveContent = preserveHostContent || encapsulation === ViewEncapsulation.ShadowDom;
8002
7994
  const rootElement = renderer.selectRootElement(elementOrSelector, preserveContent);
8003
7995
  applyRootElementTransform(rootElement);
8004
7996
  return rootElement;
@@ -13523,7 +13515,7 @@ class ComponentFactory extends ComponentFactory$1 {
13523
13515
  }
13524
13516
  function createRootTView(rootSelectorOrNode, componentDef, componentBindings, directives) {
13525
13517
  const tAttributes = rootSelectorOrNode
13526
- ? ['ng-version', '20.2.0-rc.0']
13518
+ ? ['ng-version', '20.2.0']
13527
13519
  : // Extract attributes and classes from the first selector only to match VE behavior.
13528
13520
  extractAttrsAndClassesFromSelector(componentDef.selectors[0]);
13529
13521
  let creationBindings = null;
@@ -13647,7 +13639,7 @@ class ComponentRef extends ComponentRef$1 {
13647
13639
  if (ngDevMode && !hasSetInput) {
13648
13640
  const cmpNameForError = stringifyForError(this.componentType);
13649
13641
  let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `;
13650
- 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.`;
13651
13643
  reportUnknownPropertyError(message);
13652
13644
  }
13653
13645
  }
@@ -21890,6 +21882,13 @@ function getLongestComputedAnimation(computedStyle) {
21890
21882
  }
21891
21883
  return longest;
21892
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
+ }
21893
21892
  /**
21894
21893
  * Determines the longest animation, but with `getComputedStyles` instead of `getAnimations`. This
21895
21894
  * is ultimately safer than getAnimations because it can be used when recalculations are in
@@ -21900,10 +21899,11 @@ function determineLongestAnimationFromComputedStyles(el, animationsMap) {
21900
21899
  const longestAnimation = getLongestComputedAnimation(computedStyle);
21901
21900
  const longestTransition = getLongestComputedTransition(computedStyle);
21902
21901
  const longest = longestAnimation.duration > longestTransition.duration ? longestAnimation : longestTransition;
21903
- if (animationsMap.has(el) && animationsMap.get(el).duration > longest.duration) {
21902
+ if (isShorterThanExistingAnimation(animationsMap.get(el), longest))
21904
21903
  return;
21904
+ if (longestExists(longest)) {
21905
+ animationsMap.set(el, longest);
21905
21906
  }
21906
- animationsMap.set(el, longest);
21907
21907
  }
21908
21908
  /**
21909
21909
  * Multiple animations can be set on an element. This grabs an element and
@@ -21912,8 +21912,8 @@ function determineLongestAnimationFromComputedStyles(el, animationsMap) {
21912
21912
  * This ensures we get the longest running animation and only remove when
21913
21913
  * that animation completes.
21914
21914
  */
21915
- function determineLongestAnimation(event, el, animationsMap, areAnimationSupported) {
21916
- if (!areAnimationSupported || !(event.target instanceof Element) || event.target !== el)
21915
+ function determineLongestAnimation(el, animationsMap, areAnimationSupported) {
21916
+ if (!areAnimationSupported)
21917
21917
  return;
21918
21918
  const animations = el.getAnimations();
21919
21919
  return animations.length === 0
@@ -21923,7 +21923,7 @@ function determineLongestAnimation(event, el, animationsMap, areAnimationSupport
21923
21923
  : determineLongestAnimationFromElementAnimations(el, animationsMap, animations);
21924
21924
  }
21925
21925
  function determineLongestAnimationFromElementAnimations(el, animationsMap, animations) {
21926
- let currentLongest = {
21926
+ let longest = {
21927
21927
  animationName: undefined,
21928
21928
  propertyName: undefined,
21929
21929
  duration: 0,
@@ -21942,14 +21942,15 @@ function determineLongestAnimationFromElementAnimations(el, animationsMap, anima
21942
21942
  // Check for CSSTransition specific property
21943
21943
  propertyName = animation.transitionProperty;
21944
21944
  }
21945
- if (duration >= currentLongest.duration) {
21946
- currentLongest = { animationName, propertyName, duration };
21945
+ if (duration >= longest.duration) {
21946
+ longest = { animationName, propertyName, duration };
21947
21947
  }
21948
21948
  }
21949
- if (animationsMap.has(el) && animationsMap.get(el).duration > currentLongest.duration) {
21949
+ if (isShorterThanExistingAnimation(animationsMap.get(el), longest))
21950
21950
  return;
21951
+ if (longestExists(longest)) {
21952
+ animationsMap.set(el, longest);
21951
21953
  }
21952
- animationsMap.set(el, currentLongest);
21953
21954
  }
21954
21955
 
21955
21956
  const DEFAULT_ANIMATIONS_DISABLED = false;
@@ -21957,6 +21958,36 @@ const areAnimationSupported = (typeof ngServerMode === 'undefined' || !ngServerM
21957
21958
  typeof document !== 'undefined' &&
21958
21959
  // tslint:disable-next-line:no-toplevel-property-access
21959
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
+ }
21960
21991
  const noOpAnimationComplete = () => { };
21961
21992
  // Tracks the list of classes added to a DOM node from `animate.enter` calls to ensure
21962
21993
  // we remove all of the classes in the case of animation composition via host bindings.
@@ -21966,10 +21997,26 @@ const longestAnimations = new WeakMap();
21966
21997
  // used to prevent duplicate nodes from showing up when nodes have been toggled quickly
21967
21998
  // from an `@if` or `@for`.
21968
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
+ }
21969
22016
  /**
21970
22017
  * Instruction to handle the `animate.enter` behavior for class bindings.
21971
22018
  *
21972
- * @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.
21973
22020
  * @returns This function returns itself so that it may be chained.
21974
22021
  *
21975
22022
  * @codeGenApi
@@ -21981,15 +22028,13 @@ function ɵɵanimateEnter(value) {
21981
22028
  }
21982
22029
  ngDevMode && assertAnimationTypes(value, 'animate.enter');
21983
22030
  const lView = getLView();
22031
+ if (areAnimationsDisabled(lView)) {
22032
+ return ɵɵanimateEnter;
22033
+ }
21984
22034
  const tNode = getCurrentTNode();
21985
22035
  const nativeElement = getNativeByTNode(tNode, lView);
21986
22036
  const renderer = lView[RENDERER];
21987
- const injector = lView[INJECTOR];
21988
- const animationsDisabled = injector.get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
21989
- const ngZone = injector.get(NgZone);
21990
- if (animationsDisabled) {
21991
- return ɵɵanimateEnter;
21992
- }
22037
+ const ngZone = lView[INJECTOR].get(NgZone);
21993
22038
  // Retrieve the actual class list from the value. This will resolve any resolver functions from
21994
22039
  // bindings.
21995
22040
  const activeClasses = getClassListFromValue(value);
@@ -21999,7 +22044,6 @@ function ɵɵanimateEnter(value) {
21999
22044
  // This also allows us to setup cancellation of animations in progress if the
22000
22045
  // gets removed early.
22001
22046
  const handleAnimationStart = (event) => {
22002
- determineLongestAnimation(event, nativeElement, longestAnimations, areAnimationSupported);
22003
22047
  setupAnimationCancel(event, renderer);
22004
22048
  const eventName = event instanceof AnimationEvent ? 'animationend' : 'transitionend';
22005
22049
  ngZone.runOutsideAngular(() => {
@@ -22008,7 +22052,7 @@ function ɵɵanimateEnter(value) {
22008
22052
  };
22009
22053
  // When the longest animation ends, we can remove all the classes
22010
22054
  const handleInAnimationEnd = (event) => {
22011
- animationEnd(event, nativeElement, renderer, cleanupFns);
22055
+ animationEnd(event, nativeElement, renderer);
22012
22056
  };
22013
22057
  // We only need to add these event listeners if there are actual classes to apply
22014
22058
  if (activeClasses && activeClasses.length > 0) {
@@ -22028,6 +22072,20 @@ function ɵɵanimateEnter(value) {
22028
22072
  for (const klass of activeClasses) {
22029
22073
  renderer.addClass(nativeElement, klass);
22030
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
+ });
22031
22089
  }
22032
22090
  return ɵɵanimateEnter; // For chaining
22033
22091
  }
@@ -22067,12 +22125,19 @@ function ɵɵanimateEnterListener(value) {
22067
22125
  }
22068
22126
  ngDevMode && assertAnimationTypes(value, 'animate.enter');
22069
22127
  const lView = getLView();
22070
- const tNode = getCurrentTNode();
22071
- const nativeElement = getNativeByTNode(tNode, lView);
22072
- const animationsDisabled = lView[INJECTOR].get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
22073
- if (animationsDisabled) {
22128
+ if (areAnimationsDisabled(lView)) {
22074
22129
  return ɵɵanimateEnterListener;
22075
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 } }));
22076
22141
  value.call(lView[CONTEXT], { target: nativeElement, animationComplete: noOpAnimationComplete });
22077
22142
  return ɵɵanimateEnterListener;
22078
22143
  }
@@ -22081,7 +22146,7 @@ function ɵɵanimateEnterListener(value) {
22081
22146
  * It registers an animation with the ElementRegistry to be run when the element
22082
22147
  * is scheduled for removal from the DOM.
22083
22148
  *
22084
- * @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.
22085
22150
  * @returns This function returns itself so that it may be chained.
22086
22151
  *
22087
22152
  * @codeGenApi
@@ -22093,18 +22158,19 @@ function ɵɵanimateLeave(value) {
22093
22158
  }
22094
22159
  ngDevMode && assertAnimationTypes(value, 'animate.leave');
22095
22160
  const lView = getLView();
22161
+ const animationsDisabled = areAnimationsDisabled(lView);
22162
+ if (animationsDisabled) {
22163
+ return ɵɵanimateLeave;
22164
+ }
22096
22165
  const tView = getTView();
22097
22166
  const tNode = getCurrentTNode();
22098
22167
  const nativeElement = getNativeByTNode(tNode, lView);
22099
22168
  // This instruction is called in the update pass.
22100
22169
  const renderer = lView[RENDERER];
22101
- const injector = lView[INJECTOR];
22102
- // Assume ElementRegistry and ANIMATIONS_DISABLED are injectable services.
22103
22170
  const elementRegistry = getAnimationElementRemovalRegistry();
22104
22171
  ngDevMode &&
22105
22172
  assertDefined(elementRegistry.elements, 'Expected `ElementRegistry` to be present in animations subsystem');
22106
- const animationsDisabled = injector.get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
22107
- const ngZone = injector.get(NgZone);
22173
+ const ngZone = lView[INJECTOR].get(NgZone);
22108
22174
  // This function gets stashed in the registry to be used once the element removal process
22109
22175
  // begins. We pass in the values and resolvers so as to evaluate the resolved classes
22110
22176
  // at the latest possible time, meaning we evaluate them right before the animation
@@ -22115,11 +22181,7 @@ function ɵɵanimateLeave(value) {
22115
22181
  };
22116
22182
  };
22117
22183
  // Ensure cleanup if the LView is destroyed before the animation runs.
22118
- if (lView[FLAGS] & 8 /* LViewFlags.FirstLViewPass */) {
22119
- storeCleanupWithContext(tView, lView, nativeElement, (elToClean) => {
22120
- elementRegistry.elements.remove(elToClean);
22121
- });
22122
- }
22184
+ setupElementRegistryCleanup(elementRegistry, lView, tView, nativeElement);
22123
22185
  elementRegistry.elements.add(nativeElement, value, animate);
22124
22186
  return ɵɵanimateLeave; // For chaining
22125
22187
  }
@@ -22140,6 +22202,9 @@ function ɵɵanimateLeaveListener(value) {
22140
22202
  return ɵɵanimateLeaveListener;
22141
22203
  }
22142
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.
22143
22208
  const lView = getLView();
22144
22209
  const tNode = getCurrentTNode();
22145
22210
  const tView = getTView();
@@ -22147,13 +22212,13 @@ function ɵɵanimateLeaveListener(value) {
22147
22212
  if (nativeElement.nodeType !== Node.ELEMENT_NODE) {
22148
22213
  return ɵɵanimateLeaveListener;
22149
22214
  }
22150
- // Assume ElementRegistry and ANIMATIONS_DISABLED are injectable services.
22151
- const injector = lView[INJECTOR];
22152
22215
  const elementRegistry = getAnimationElementRemovalRegistry();
22153
22216
  ngDevMode &&
22154
22217
  assertDefined(elementRegistry.elements, 'Expected `ElementRegistry` to be present in animations subsystem');
22155
- const animationsDisabled = injector.get(ANIMATIONS_DISABLED, DEFAULT_ANIMATIONS_DISABLED);
22156
- 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) => {
22157
22222
  return (removeFn) => {
22158
22223
  if (animationsDisabled) {
22159
22224
  removeFn();
@@ -22162,19 +22227,20 @@ function ɵɵanimateLeaveListener(value) {
22162
22227
  const event = {
22163
22228
  target: nativeElement,
22164
22229
  animationComplete: () => {
22230
+ clearLeavingNodes(tNode);
22165
22231
  removeFn();
22166
22232
  },
22167
22233
  };
22234
+ trackLeavingNodes(tNode, _el);
22235
+ ngZone.runOutsideAngular(() => {
22236
+ renderer.listen(_el, 'animationend', () => removeFn(), { once: true });
22237
+ });
22168
22238
  value.call(lView[CONTEXT], event);
22169
22239
  }
22170
22240
  };
22171
22241
  };
22172
22242
  // Ensure cleanup if the LView is destroyed before the animation runs.
22173
- if (lView[FLAGS] & 8 /* LViewFlags.FirstLViewPass */) {
22174
- storeCleanupWithContext(tView, lView, nativeElement, (elToClean) => {
22175
- elementRegistry.elements.remove(elToClean);
22176
- });
22177
- }
22243
+ setupElementRegistryCleanup(elementRegistry, lView, tView, nativeElement);
22178
22244
  elementRegistry.elements.addCallback(nativeElement, value, animate);
22179
22245
  return ɵɵanimateLeaveListener; // For chaining
22180
22246
  }
@@ -22219,13 +22285,7 @@ function cancelAnimationsIfRunning(element, renderer) {
22219
22285
  }
22220
22286
  }
22221
22287
  // We need to prevent any enter animation listeners from firing if they exist.
22222
- if (elementData) {
22223
- for (const fn of elementData.cleanupFns) {
22224
- fn();
22225
- }
22226
- }
22227
- longestAnimations.delete(element);
22228
- enterClassMap.delete(element);
22288
+ cleanupEnterClassData(element);
22229
22289
  }
22230
22290
  function setupAnimationCancel(event, renderer) {
22231
22291
  if (!(event.target instanceof Element))
@@ -22256,7 +22316,7 @@ function isLongestAnimation(event, nativeElement) {
22256
22316
  (longestAnimation.propertyName !== undefined &&
22257
22317
  event.propertyName === longestAnimation.propertyName)));
22258
22318
  }
22259
- function animationEnd(event, nativeElement, renderer, cleanupFns) {
22319
+ function animationEnd(event, nativeElement, renderer) {
22260
22320
  const elementData = enterClassMap.get(nativeElement);
22261
22321
  if (!elementData)
22262
22322
  return;
@@ -22269,11 +22329,7 @@ function animationEnd(event, nativeElement, renderer, cleanupFns) {
22269
22329
  for (const klass of elementData.classList) {
22270
22330
  renderer.removeClass(nativeElement, klass);
22271
22331
  }
22272
- enterClassMap.delete(nativeElement);
22273
- longestAnimations.delete(nativeElement);
22274
- for (const fn of cleanupFns) {
22275
- fn();
22276
- }
22332
+ cleanupEnterClassData(nativeElement);
22277
22333
  }
22278
22334
  }
22279
22335
  function assertAnimationTypes(value, instruction) {
@@ -22289,11 +22345,9 @@ function animateLeaveClassRunner(el, tNode, classList, finalRemoveFn, renderer,
22289
22345
  if (animationsDisabled) {
22290
22346
  longestAnimations.delete(el);
22291
22347
  finalRemoveFn();
22348
+ return;
22292
22349
  }
22293
22350
  cancelAnimationsIfRunning(el, renderer);
22294
- const handleAnimationStart = (event) => {
22295
- determineLongestAnimation(event, el, longestAnimations, areAnimationSupported);
22296
- };
22297
22351
  const handleOutAnimationEnd = (event) => {
22298
22352
  if (event instanceof CustomEvent || isLongestAnimation(event, el)) {
22299
22353
  // Now that we've found the longest animation, there's no need
@@ -22302,32 +22356,30 @@ function animateLeaveClassRunner(el, tNode, classList, finalRemoveFn, renderer,
22302
22356
  // affect any other animations on the page.
22303
22357
  event.stopImmediatePropagation();
22304
22358
  longestAnimations.delete(el);
22305
- if (leavingNodes.get(tNode)?.length === 0) {
22306
- leavingNodes.delete(tNode);
22307
- }
22359
+ clearLeavingNodes(tNode);
22308
22360
  finalRemoveFn();
22309
22361
  }
22310
22362
  };
22311
- if (!animationsDisabled) {
22312
- ngZone.runOutsideAngular(() => {
22313
- renderer.listen(el, 'animationstart', handleAnimationStart, { once: true });
22314
- renderer.listen(el, 'transitionstart', handleAnimationStart, { once: true });
22315
- renderer.listen(el, 'animationend', handleOutAnimationEnd);
22316
- 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
+ }
22317
22381
  });
22318
- // We need to track this tNode's element just to be sure we don't add
22319
- // a new RNode for this TNode while this one is still animating away.
22320
- // once the animation is complete, we remove this reference.
22321
- if (leavingNodes.has(tNode)) {
22322
- leavingNodes.get(tNode)?.push(el);
22323
- }
22324
- else {
22325
- leavingNodes.set(tNode, [el]);
22326
- }
22327
- for (const item of classList) {
22328
- renderer.addClass(el, item);
22329
- }
22330
- }
22382
+ });
22331
22383
  }
22332
22384
 
22333
22385
  /*!
@@ -29077,8 +29129,7 @@ function recreateLView(importMeta, id, newDef, oldDef, lView) {
29077
29129
  // shadow root. The browser will throw if we attempt to attach another one and there's no way
29078
29130
  // to detach it. Our only option is to make a clone only of the root node, replace the node
29079
29131
  // with the clone and use it for the newly-created LView.
29080
- if (oldDef.encapsulation === ViewEncapsulation.ShadowDom ||
29081
- oldDef.encapsulation === ViewEncapsulation.IsolatedShadowDom) {
29132
+ if (oldDef.encapsulation === ViewEncapsulation.ShadowDom) {
29082
29133
  const newHost = host.cloneNode(false);
29083
29134
  host.replaceWith(newHost);
29084
29135
  host = newHost;