async.mjs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /**
  2. * @license Angular v19.2.13
  3. * (c) 2010-2025 Google LLC. https://angular.io/
  4. * License: MIT
  5. */
  6. import { DOCUMENT } from '@angular/common';
  7. import * as i0 from '@angular/core';
  8. import { InjectionToken, inject, Injector, ɵRuntimeError as _RuntimeError, ɵChangeDetectionScheduler as _ChangeDetectionScheduler, Injectable, ɵperformanceMarkFeature as _performanceMarkFeature, makeEnvironmentProviders, NgZone, RendererFactory2, ANIMATION_MODULE_TYPE } from '@angular/core';
  9. import { DomRendererFactory2 } from '../dom_renderer-DGKzginR.mjs';
  10. const ANIMATION_PREFIX = '@';
  11. class AsyncAnimationRendererFactory {
  12. doc;
  13. delegate;
  14. zone;
  15. animationType;
  16. moduleImpl;
  17. _rendererFactoryPromise = null;
  18. scheduler = null;
  19. injector = inject(Injector);
  20. loadingSchedulerFn = inject(ɵASYNC_ANIMATION_LOADING_SCHEDULER_FN, {
  21. optional: true,
  22. });
  23. _engine;
  24. /**
  25. *
  26. * @param moduleImpl allows to provide a mock implmentation (or will load the animation module)
  27. */
  28. constructor(doc, delegate, zone, animationType, moduleImpl) {
  29. this.doc = doc;
  30. this.delegate = delegate;
  31. this.zone = zone;
  32. this.animationType = animationType;
  33. this.moduleImpl = moduleImpl;
  34. }
  35. /** @docs-private */
  36. ngOnDestroy() {
  37. // When the root view is removed, the renderer defers the actual work to the
  38. // `TransitionAnimationEngine` to do this, and the `TransitionAnimationEngine` doesn't actually
  39. // remove the DOM node, but just calls `markElementAsRemoved()`. The actual DOM node is not
  40. // removed until `TransitionAnimationEngine` "flushes".
  41. // Note: we already flush on destroy within the `InjectableAnimationEngine`. The injectable
  42. // engine is not provided when async animations are used.
  43. this._engine?.flush();
  44. }
  45. /**
  46. * @internal
  47. */
  48. loadImpl() {
  49. // Note on the `.then(m => m)` part below: Closure compiler optimizations in g3 require
  50. // `.then` to be present for a dynamic import (or an import should be `await`ed) to detect
  51. // the set of imported symbols.
  52. const loadFn = () => this.moduleImpl ?? import('@angular/animations/browser').then((m) => m);
  53. let moduleImplPromise;
  54. if (this.loadingSchedulerFn) {
  55. moduleImplPromise = this.loadingSchedulerFn(loadFn);
  56. }
  57. else {
  58. moduleImplPromise = loadFn();
  59. }
  60. return moduleImplPromise
  61. .catch((e) => {
  62. throw new _RuntimeError(5300 /* RuntimeErrorCode.ANIMATION_RENDERER_ASYNC_LOADING_FAILURE */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
  63. 'Async loading for animations package was ' +
  64. 'enabled, but loading failed. Angular falls back to using regular rendering. ' +
  65. "No animations will be displayed and their styles won't be applied.");
  66. })
  67. .then(({ ɵcreateEngine, ɵAnimationRendererFactory }) => {
  68. // We can't create the renderer yet because we might need the hostElement and the type
  69. // Both are provided in createRenderer().
  70. this._engine = ɵcreateEngine(this.animationType, this.doc);
  71. const rendererFactory = new ɵAnimationRendererFactory(this.delegate, this._engine, this.zone);
  72. this.delegate = rendererFactory;
  73. return rendererFactory;
  74. });
  75. }
  76. /**
  77. * This method is delegating the renderer creation to the factories.
  78. * It uses default factory while the animation factory isn't loaded
  79. * and will rely on the animation factory once it is loaded.
  80. *
  81. * Calling this method will trigger as side effect the loading of the animation module
  82. * if the renderered component uses animations.
  83. */
  84. createRenderer(hostElement, rendererType) {
  85. const renderer = this.delegate.createRenderer(hostElement, rendererType);
  86. if (renderer.ɵtype === 0 /* AnimationRendererType.Regular */) {
  87. // The factory is already loaded, this is an animation renderer
  88. return renderer;
  89. }
  90. // We need to prevent the DomRenderer to throw an error because of synthetic properties
  91. if (typeof renderer.throwOnSyntheticProps === 'boolean') {
  92. renderer.throwOnSyntheticProps = false;
  93. }
  94. // Using a dynamic renderer to switch the renderer implementation once the module is loaded.
  95. const dynamicRenderer = new DynamicDelegationRenderer(renderer);
  96. // Kick off the module loading if the component uses animations but the module hasn't been
  97. // loaded yet.
  98. if (rendererType?.data?.['animation'] && !this._rendererFactoryPromise) {
  99. this._rendererFactoryPromise = this.loadImpl();
  100. }
  101. this._rendererFactoryPromise
  102. ?.then((animationRendererFactory) => {
  103. const animationRenderer = animationRendererFactory.createRenderer(hostElement, rendererType);
  104. dynamicRenderer.use(animationRenderer);
  105. this.scheduler ??= this.injector.get(_ChangeDetectionScheduler, null, { optional: true });
  106. this.scheduler?.notify(10 /* NotificationSource.AsyncAnimationsLoaded */);
  107. })
  108. .catch((e) => {
  109. // Permanently use regular renderer when loading fails.
  110. dynamicRenderer.use(renderer);
  111. });
  112. return dynamicRenderer;
  113. }
  114. begin() {
  115. this.delegate.begin?.();
  116. }
  117. end() {
  118. this.delegate.end?.();
  119. }
  120. whenRenderingDone() {
  121. return this.delegate.whenRenderingDone?.() ?? Promise.resolve();
  122. }
  123. /**
  124. * Used during HMR to clear any cached data about a component.
  125. * @param componentId ID of the component that is being replaced.
  126. */
  127. componentReplaced(componentId) {
  128. // Flush the engine since the renderer destruction waits for animations to be done.
  129. this._engine?.flush();
  130. this.delegate.componentReplaced?.(componentId);
  131. }
  132. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: AsyncAnimationRendererFactory, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
  133. static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: AsyncAnimationRendererFactory });
  134. }
  135. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: AsyncAnimationRendererFactory, decorators: [{
  136. type: Injectable
  137. }], ctorParameters: () => [{ type: Document }, { type: i0.RendererFactory2 }, { type: i0.NgZone }, { type: undefined }, { type: Promise }] });
  138. /**
  139. * The class allows to dynamicly switch between different renderer implementations
  140. * by changing the delegate renderer.
  141. */
  142. class DynamicDelegationRenderer {
  143. delegate;
  144. // List of callbacks that need to be replayed on the animation renderer once its loaded
  145. replay = [];
  146. ɵtype = 1 /* AnimationRendererType.Delegated */;
  147. constructor(delegate) {
  148. this.delegate = delegate;
  149. }
  150. use(impl) {
  151. this.delegate = impl;
  152. if (this.replay !== null) {
  153. // Replay queued actions using the animation renderer to apply
  154. // all events and properties collected while loading was in progress.
  155. for (const fn of this.replay) {
  156. fn(impl);
  157. }
  158. // Set to `null` to indicate that the queue was processed
  159. // and we no longer need to collect events and properties.
  160. this.replay = null;
  161. }
  162. }
  163. get data() {
  164. return this.delegate.data;
  165. }
  166. destroy() {
  167. this.replay = null;
  168. this.delegate.destroy();
  169. }
  170. createElement(name, namespace) {
  171. return this.delegate.createElement(name, namespace);
  172. }
  173. createComment(value) {
  174. return this.delegate.createComment(value);
  175. }
  176. createText(value) {
  177. return this.delegate.createText(value);
  178. }
  179. get destroyNode() {
  180. return this.delegate.destroyNode;
  181. }
  182. appendChild(parent, newChild) {
  183. this.delegate.appendChild(parent, newChild);
  184. }
  185. insertBefore(parent, newChild, refChild, isMove) {
  186. this.delegate.insertBefore(parent, newChild, refChild, isMove);
  187. }
  188. removeChild(parent, oldChild, isHostElement) {
  189. this.delegate.removeChild(parent, oldChild, isHostElement);
  190. }
  191. selectRootElement(selectorOrNode, preserveContent) {
  192. return this.delegate.selectRootElement(selectorOrNode, preserveContent);
  193. }
  194. parentNode(node) {
  195. return this.delegate.parentNode(node);
  196. }
  197. nextSibling(node) {
  198. return this.delegate.nextSibling(node);
  199. }
  200. setAttribute(el, name, value, namespace) {
  201. this.delegate.setAttribute(el, name, value, namespace);
  202. }
  203. removeAttribute(el, name, namespace) {
  204. this.delegate.removeAttribute(el, name, namespace);
  205. }
  206. addClass(el, name) {
  207. this.delegate.addClass(el, name);
  208. }
  209. removeClass(el, name) {
  210. this.delegate.removeClass(el, name);
  211. }
  212. setStyle(el, style, value, flags) {
  213. this.delegate.setStyle(el, style, value, flags);
  214. }
  215. removeStyle(el, style, flags) {
  216. this.delegate.removeStyle(el, style, flags);
  217. }
  218. setProperty(el, name, value) {
  219. // We need to keep track of animation properties set on default renderer
  220. // So we can also set them also on the animation renderer
  221. if (this.shouldReplay(name)) {
  222. this.replay.push((renderer) => renderer.setProperty(el, name, value));
  223. }
  224. this.delegate.setProperty(el, name, value);
  225. }
  226. setValue(node, value) {
  227. this.delegate.setValue(node, value);
  228. }
  229. listen(target, eventName, callback, options) {
  230. // We need to keep track of animation events registred by the default renderer
  231. // So we can also register them against the animation renderer
  232. if (this.shouldReplay(eventName)) {
  233. this.replay.push((renderer) => renderer.listen(target, eventName, callback, options));
  234. }
  235. return this.delegate.listen(target, eventName, callback, options);
  236. }
  237. shouldReplay(propOrEventName) {
  238. //`null` indicates that we no longer need to collect events and properties
  239. return this.replay !== null && propOrEventName.startsWith(ANIMATION_PREFIX);
  240. }
  241. }
  242. /**
  243. * Provides a custom scheduler function for the async loading of the animation package.
  244. *
  245. * Private token for investigation purposes
  246. */
  247. const ɵASYNC_ANIMATION_LOADING_SCHEDULER_FN = new InjectionToken(ngDevMode ? 'async_animation_loading_scheduler_fn' : '');
  248. /**
  249. * Returns the set of dependency-injection providers
  250. * to enable animations in an application. See [animations guide](guide/animations)
  251. * to learn more about animations in Angular.
  252. *
  253. * When you use this function instead of the eager `provideAnimations()`, animations won't be
  254. * rendered until the renderer is loaded.
  255. *
  256. * @usageNotes
  257. *
  258. * The function is useful when you want to enable animations in an application
  259. * bootstrapped using the `bootstrapApplication` function. In this scenario there
  260. * is no need to import the `BrowserAnimationsModule` NgModule at all, just add
  261. * providers returned by this function to the `providers` list as show below.
  262. *
  263. * ```ts
  264. * bootstrapApplication(RootComponent, {
  265. * providers: [
  266. * provideAnimationsAsync()
  267. * ]
  268. * });
  269. * ```
  270. *
  271. * @param type pass `'noop'` as argument to disable animations.
  272. *
  273. * @publicApi
  274. */
  275. function provideAnimationsAsync(type = 'animations') {
  276. _performanceMarkFeature('NgAsyncAnimations');
  277. // Animations don't work on the server so we switch them over to no-op automatically.
  278. if (typeof ngServerMode !== 'undefined' && ngServerMode) {
  279. type = 'noop';
  280. }
  281. return makeEnvironmentProviders([
  282. {
  283. provide: RendererFactory2,
  284. useFactory: (doc, renderer, zone) => {
  285. return new AsyncAnimationRendererFactory(doc, renderer, zone, type);
  286. },
  287. deps: [DOCUMENT, DomRendererFactory2, NgZone],
  288. },
  289. {
  290. provide: ANIMATION_MODULE_TYPE,
  291. useValue: type === 'noop' ? 'NoopAnimations' : 'BrowserAnimations',
  292. },
  293. ]);
  294. }
  295. export { provideAnimationsAsync, ɵASYNC_ANIMATION_LOADING_SCHEDULER_FN, AsyncAnimationRendererFactory as ɵAsyncAnimationRendererFactory };
  296. //# sourceMappingURL=async.mjs.map