UNPKG

ngx-lottie

Version:

<h1 align="center"> <img src="https://raw.githubusercontent.com/ngx-lottie/ngx-lottie/master/docs/assets/lottie.gif"> </h1>

471 lines (462 loc) 28.3 kB
import { isPlatformServer } from '@angular/common'; import * as i0 from '@angular/core'; import { booleanAttribute, InjectionToken, signal, viewChild, inject, NgZone, input, computed, PLATFORM_ID, Injector, DestroyRef, afterNextRender, ɵisPromise as _isPromise, runInInjectionContext, effect, untracked, Directive, output, ViewEncapsulation, ChangeDetectionStrategy, Component, makeEnvironmentProviders } from '@angular/core'; import { outputFromObservable, toObservable } from '@angular/core/rxjs-interop'; import { switchMap, EMPTY, Observable } from 'rxjs'; /** * Transforms a value (typically a string) to a boolean. * Intended to be used as a transform function of an input. * * @see https://material.angular.io/cdk/coercion/overview */ const coerceBooleanAttribute = booleanAttribute; const DOT_LOTTIE_OPTIONS = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'DOT_LOTTIE_OPTIONS' : ''); /** * Optional injection token for custom WASM URL. * If provided, the base directive will configure it before creating DotLottie instances. */ const DOT_LOTTIE_WASM_URL = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'DOT_LOTTIE_WASM_URL' : ''); class ɵɵBaseDotLottieDirective { /** * Static flag to track if WASM URL has been configured globally. */ static { this.wasmUrlConfigured = false; } constructor() { this.instance = signal(undefined, ...(ngDevMode ? [{ debugName: "instance" }] : [])); this.isLoaded = signal(false, ...(ngDevMode ? [{ debugName: "isLoaded" }] : [])); this.canvas = viewChild.required('canvas'); this.ngZone = inject(NgZone); this.className = input(...(ngDevMode ? [undefined, { debugName: "className" }] : [])); this.containerStyles = input(...(ngDevMode ? [undefined, { debugName: "containerStyles" }] : [])); this.animationId = input(...(ngDevMode ? [undefined, { debugName: "animationId" }] : [])); this.autoplay = input(false, { ...(ngDevMode ? { debugName: "autoplay" } : {}), transform: coerceBooleanAttribute }); this.backgroundColor = input(...(ngDevMode ? [undefined, { debugName: "backgroundColor" }] : [])); this.data = input(...(ngDevMode ? [undefined, { debugName: "data" }] : [])); this.layout = input(...(ngDevMode ? [undefined, { debugName: "layout" }] : [])); this.loop = input(false, { ...(ngDevMode ? { debugName: "loop" } : {}), transform: coerceBooleanAttribute }); this.marker = input(...(ngDevMode ? [undefined, { debugName: "marker" }] : [])); this.mode = input(...(ngDevMode ? [undefined, { debugName: "mode" }] : [])); this.renderConfig = input(...(ngDevMode ? [undefined, { debugName: "renderConfig" }] : [])); this.segment = input(...(ngDevMode ? [undefined, { debugName: "segment" }] : [])); this.speed = input(...(ngDevMode ? [undefined, { debugName: "speed" }] : [])); this.src = input(...(ngDevMode ? [undefined, { debugName: "src" }] : [])); this.themeId = input(...(ngDevMode ? [undefined, { debugName: "themeId" }] : [])); this.useFrameInterpolation = input(true, { ...(ngDevMode ? { debugName: "useFrameInterpolation" } : {}), transform: coerceBooleanAttribute }); this.stateMachineId = input(...(ngDevMode ? [undefined, { debugName: "stateMachineId" }] : [])); this.stateMachineConfig = input(...(ngDevMode ? [undefined, { debugName: "stateMachineConfig" }] : [])); /** * Emitted when the animation completes playback. */ this.complete = outputFromObservable(this.awaitInstanceAndStartListening('complete')); /** * Emitted when the animation has successfully loaded. */ this.load = outputFromObservable(this.awaitInstanceAndStartListening('load')); /** * Emitted when an error occurs during animation loading. */ this.loadError = outputFromObservable(this.awaitInstanceAndStartListening('loadError')); /** * Emitted when an error occurs during animation rendering. */ this.renderError = outputFromObservable(this.awaitInstanceAndStartListening('renderError')); /** * Emitted when the animation is paused. */ this.pause = outputFromObservable(this.awaitInstanceAndStartListening('pause')); /** * Emitted when the animation starts playing. */ this.play = outputFromObservable(this.awaitInstanceAndStartListening('play')); /** * Emitted when the animation is stopped. */ this.stop = outputFromObservable(this.awaitInstanceAndStartListening('stop')); /** * Emitted when the animation instance is destroyed. */ this.destroy = outputFromObservable(this.awaitInstanceAndStartListening('destroy')); /** * Emitted when the WASM module is initialized and ready. */ this.ready = outputFromObservable(this.awaitInstanceAndStartListening('ready')); /** * Emitted on each frame change. Useful for tracking the current frame. */ this.frame = outputFromObservable(this.awaitInstanceAndStartListening('frame')); /** * Emitted when the animation is frozen (rendering paused). */ this.freeze = outputFromObservable(this.awaitInstanceAndStartListening('freeze')); /** * Emitted when the animation is unfrozen (rendering resumed). */ this.unfreeze = outputFromObservable(this.awaitInstanceAndStartListening('unfreeze')); this.mergedContainerStyles = computed(() => ({ width: '100%', height: '100%', lineHeight: '0', ...this.containerStyles(), }), ...(ngDevMode ? [{ debugName: "mergedContainerStyles" }] : [])); this.canvasStyles = { width: '100%', height: '100%' }; if ((typeof ngServerMode !== 'undefined' && ngServerMode) || isPlatformServer(inject(PLATFORM_ID))) { return; } const injector = inject(Injector); const destroyRef = inject(DestroyRef); const options = inject(DOT_LOTTIE_OPTIONS); const wasmUrl = inject(DOT_LOTTIE_WASM_URL, { optional: true }); afterNextRender(async () => { const DotLottie = await this.ngZone.runOutsideAngular(() => { const player = options.player(); return _isPromise(player) ? player : Promise.resolve(player); }); if (wasmUrl !== null && ɵɵBaseDotLottieDirective.wasmUrlConfigured === false) { ɵɵBaseDotLottieDirective.wasmUrlConfigured = true; DotLottie.setWasmUrl(wasmUrl); } // Guard against component destruction during async import. if (destroyRef.destroyed) { return; } runInInjectionContext(injector, () => this.render(destroyRef, DotLottie)); }); } render(destroyRef, DotLottieConstructor) { const canvas = this.canvas().nativeElement; const instance = this.ngZone.runOutsideAngular(() => { return new DotLottieConstructor({ canvas, ...this.buildConfig(), }); }); this.instance.set(instance); this.dotLottieCreated.emit(instance); // Track when the DotLottie animation is fully loaded. // This is necessary for state machine initialization, which requires // the animation to be loaded before a state machine can be started. this.ngZone.runOutsideAngular(() => { const onLoad = () => this.isLoaded.set(true); instance.addEventListener('load', onLoad); destroyRef.onDestroy(() => instance.removeEventListener('load', onLoad)); }); // Each effect tracks a single input signal and updates the corresponding // DotLottie instance property when that input changes. This provides // fine-grained reactivity similar to React's `useEffect` with dependency arrays. effect(() => { this.ngZone.runOutsideAngular(() => instance.loadAnimation(this.animationId() ?? '')); }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setBackgroundColor(this.backgroundColor() ?? '')); }); effect(() => { const data = this.data(); if (typeof data !== 'string' && typeof data !== 'object') return; this.ngZone.runOutsideAngular(() => instance.load({ ...this.buildConfig(), data })); }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setLayout(this.layout() ?? {})); }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setLoop(this.loop() ?? false)); }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setMarker(this.marker() ?? '')); }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setMode(this.mode() ?? 'forward')); }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setRenderConfig(this.renderConfig() ?? {})); }); effect(() => { const segment = this.segment(); if (typeof segment?.[0] === 'number' && typeof segment?.[1] === 'number') { this.ngZone.runOutsideAngular(() => instance.setSegment(segment[0], segment[1])); } }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setSpeed(this.speed() ?? 1)); }); effect(() => { const src = this.src(); if (typeof src !== 'string') return; this.ngZone.runOutsideAngular(() => instance.load({ ...this.buildConfig(), src })); }); effect(() => { const themeId = this.themeId(); if (typeof themeId !== 'string') return; this.ngZone.runOutsideAngular(() => instance.setTheme(themeId)); }); effect(() => { this.ngZone.runOutsideAngular(() => instance.setUseFrameInterpolation(this.useFrameInterpolation() ?? true)); }); effect(() => { const isLoaded = this.isLoaded(); const stateMachineId = this.stateMachineId(); // Wait for instance to be ready and loaded. if (!isLoaded) return; if (typeof stateMachineId === 'string' && stateMachineId) { this.ngZone.runOutsideAngular(() => { const smLoaded = instance.stateMachineLoad(stateMachineId); if (smLoaded) { instance.stateMachineStart(); } }); } else { this.ngZone.runOutsideAngular(() => instance.stateMachineStop()); } }); effect(() => { this.ngZone.runOutsideAngular(() => instance.stateMachineSetConfig(this.stateMachineConfig() ?? null)); }); destroyRef.onDestroy(() => { // Since `destroy()` calls `eventManager.dispatch` with `destroy`, // we're unaware of any upcoming asynchronous jobs scheduled in the // Angular context that might redundantly trigger change detection. this.ngZone.runOutsideAngular(() => { instance.destroy(); }); }); } buildConfig() { return untracked(() => ({ animationId: this.animationId(), autoplay: this.autoplay(), backgroundColor: this.backgroundColor(), data: this.data(), layout: this.layout(), loop: this.loop(), marker: this.marker(), mode: this.mode(), renderConfig: this.renderConfig(), segment: this.segment(), speed: this.speed(), src: this.src(), themeId: this.themeId(), useFrameInterpolation: this.useFrameInterpolation(), })); } awaitInstanceAndStartListening(name) { return toObservable(this.instance).pipe(switchMap(instance => { if (instance === undefined) return EMPTY; return new Observable(subscriber => { const onEvent = (event) => { subscriber.next(event); }; this.ngZone.runOutsideAngular(() => { instance.addEventListener(name, onEvent); }); return () => { instance.removeEventListener(name, onEvent); }; }); })); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ɵɵBaseDotLottieDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.0.6", type: ɵɵBaseDotLottieDirective, isStandalone: true, inputs: { className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, containerStyles: { classPropertyName: "containerStyles", publicName: "containerStyles", isSignal: true, isRequired: false, transformFunction: null }, animationId: { classPropertyName: "animationId", publicName: "animationId", isSignal: true, isRequired: false, transformFunction: null }, autoplay: { classPropertyName: "autoplay", publicName: "autoplay", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, marker: { classPropertyName: "marker", publicName: "marker", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, renderConfig: { classPropertyName: "renderConfig", publicName: "renderConfig", isSignal: true, isRequired: false, transformFunction: null }, segment: { classPropertyName: "segment", publicName: "segment", isSignal: true, isRequired: false, transformFunction: null }, speed: { classPropertyName: "speed", publicName: "speed", isSignal: true, isRequired: false, transformFunction: null }, src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, themeId: { classPropertyName: "themeId", publicName: "themeId", isSignal: true, isRequired: false, transformFunction: null }, useFrameInterpolation: { classPropertyName: "useFrameInterpolation", publicName: "useFrameInterpolation", isSignal: true, isRequired: false, transformFunction: null }, stateMachineId: { classPropertyName: "stateMachineId", publicName: "stateMachineId", isSignal: true, isRequired: false, transformFunction: null }, stateMachineConfig: { classPropertyName: "stateMachineConfig", publicName: "stateMachineConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { complete: "complete", load: "load", loadError: "loadError", renderError: "renderError", pause: "pause", play: "play", stop: "stop", destroy: "destroy", ready: "ready", frame: "frame", freeze: "freeze", unfreeze: "unfreeze" }, viewQueries: [{ propertyName: "canvas", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ɵɵBaseDotLottieDirective, decorators: [{ type: Directive }], ctorParameters: () => [], propDecorators: { canvas: [{ type: i0.ViewChild, args: ['canvas', { isSignal: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], containerStyles: [{ type: i0.Input, args: [{ isSignal: true, alias: "containerStyles", required: false }] }], animationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationId", required: false }] }], autoplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoplay", required: false }] }], backgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundColor", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], loop: [{ type: i0.Input, args: [{ isSignal: true, alias: "loop", required: false }] }], marker: [{ type: i0.Input, args: [{ isSignal: true, alias: "marker", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], renderConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderConfig", required: false }] }], segment: [{ type: i0.Input, args: [{ isSignal: true, alias: "segment", required: false }] }], speed: [{ type: i0.Input, args: [{ isSignal: true, alias: "speed", required: false }] }], src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], themeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeId", required: false }] }], useFrameInterpolation: [{ type: i0.Input, args: [{ isSignal: true, alias: "useFrameInterpolation", required: false }] }], stateMachineId: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateMachineId", required: false }] }], stateMachineConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateMachineConfig", required: false }] }], complete: [{ type: i0.Output, args: ["complete"] }], load: [{ type: i0.Output, args: ["load"] }], loadError: [{ type: i0.Output, args: ["loadError"] }], renderError: [{ type: i0.Output, args: ["renderError"] }], pause: [{ type: i0.Output, args: ["pause"] }], play: [{ type: i0.Output, args: ["play"] }], stop: [{ type: i0.Output, args: ["stop"] }], destroy: [{ type: i0.Output, args: ["destroy"] }], ready: [{ type: i0.Output, args: ["ready"] }], frame: [{ type: i0.Output, args: ["frame"] }], freeze: [{ type: i0.Output, args: ["freeze"] }], unfreeze: [{ type: i0.Output, args: ["unfreeze"] }] } }); /** * Separate DotLottie and DotLottieWorker components architecture * * WHY TWO COMPONENTS INSTEAD OF ONE WITH CONFIGURATION: * * 1. **Type Safety**: Each component has a precise output type (DotLottie vs DotLottieWorker). * Users get compile-time guarantees about which instance type they're working with. * A single configurable component would require runtime type checking and type assertions. * * 2. **Clear Intent**: The component selector itself (`ng-dotlottie` vs `ng-dotlottie-worker`) * explicitly communicates which rendering strategy is being used. No need to inspect * configuration to understand the behavior. * * 3. **Bundle Optimization**: Tree-shaking works better with separate components. If an app * only uses `ng-dotlottie`, the DotLottieWorker code can be completely eliminated from * the bundle. A single component would bundle both implementations. * * 4. **Simpler API**: No configuration prop needed (e.g., `useWorker` boolean). Less surface * area for bugs - users can't accidentally misconfigure or change modes at runtime. * * 5. **Performance Predictability**: DotLottie and DotLottieWorker have different performance * characteristics and browser support. Separate components make this distinction explicit * and prevent unintended mode switching during the component lifecycle. * * 6. **Maintainability**: If DotLottie and DotLottieWorker diverge in their APIs or * initialization logic in future library versions, handling them separately is cleaner * than conditional logic scattered throughout a single component. * * 7. **Testing**: Each component can be tested independently with focused test suites. * No need for parameterized tests or complex setup to cover both modes. * * TRADE-OFF: * - Slight code duplication (two component classes), but shared implementation in * ɵɵBaseDotLottieDirective minimizes this. The duplication is purely declarative * (selector, output type override) which is acceptable for the benefits gained. */ class DotLottieComponent extends ɵɵBaseDotLottieDirective { constructor() { super(...arguments); this.dotLottieCreated = output(); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DotLottieComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: DotLottieComponent, isStandalone: true, selector: "ng-dotlottie", outputs: { dotLottieCreated: "dotLottieCreated" }, usesInheritance: true, ngImport: i0, template: ` <div [class]="className()" [style]="mergedContainerStyles()"> <canvas #canvas class="ng-dotlottie-canvas" [style]="canvasStyles"></canvas> </div> `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DotLottieComponent, decorators: [{ type: Component, args: [{ selector: 'ng-dotlottie', template: ` <div [class]="className()" [style]="mergedContainerStyles()"> <canvas #canvas class="ng-dotlottie-canvas" [style]="canvasStyles"></canvas> </div> `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }] }], propDecorators: { dotLottieCreated: [{ type: i0.Output, args: ["dotLottieCreated"] }] } }); /** * Separate DotLottie and DotLottieWorker components architecture * * WHY TWO COMPONENTS INSTEAD OF ONE WITH CONFIGURATION: * * 1. **Type Safety**: Each component has a precise output type (DotLottie vs DotLottieWorker). * Users get compile-time guarantees about which instance type they're working with. * A single configurable component would require runtime type checking and type assertions. * * 2. **Clear Intent**: The component selector itself (`ng-dotlottie` vs `ng-dotlottie-worker`) * explicitly communicates which rendering strategy is being used. No need to inspect * configuration to understand the behavior. * * 3. **Bundle Optimization**: Tree-shaking works better with separate components. If an app * only uses `ng-dotlottie`, the DotLottieWorker code can be completely eliminated from * the bundle. A single component would bundle both implementations. * * 4. **Simpler API**: No configuration prop needed (e.g., `useWorker` boolean). Less surface * area for bugs - users can't accidentally misconfigure or change modes at runtime. * * 5. **Performance Predictability**: DotLottie and DotLottieWorker have different performance * characteristics and browser support. Separate components make this distinction explicit * and prevent unintended mode switching during the component lifecycle. * * 6. **Maintainability**: If DotLottie and DotLottieWorker diverge in their APIs or * initialization logic in future library versions, handling them separately is cleaner * than conditional logic scattered throughout a single component. * * 7. **Testing**: Each component can be tested independently with focused test suites. * No need for parameterized tests or complex setup to cover both modes. * * TRADE-OFF: * - Slight code duplication (two component classes), but shared implementation in * ɵɵBaseDotLottieDirective minimizes this. The duplication is purely declarative * (selector, output type override) which is acceptable for the benefits gained. */ class DotLottieWorkerComponent extends ɵɵBaseDotLottieDirective { constructor() { super(...arguments); this.dotLottieCreated = output(); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DotLottieWorkerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: DotLottieWorkerComponent, isStandalone: true, selector: "ng-dotlottie-worker", outputs: { dotLottieCreated: "dotLottieCreated" }, usesInheritance: true, ngImport: i0, template: ` <div [class]="className()" [style]="mergedContainerStyles()"> <canvas #canvas class="ng-dotlottie-worker-canvas" [style]="canvasStyles"></canvas> </div> `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DotLottieWorkerComponent, decorators: [{ type: Component, args: [{ selector: 'ng-dotlottie-worker', template: ` <div [class]="className()" [style]="mergedContainerStyles()"> <canvas #canvas class="ng-dotlottie-worker-canvas" [style]="canvasStyles"></canvas> </div> `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }] }], propDecorators: { dotLottieCreated: [{ type: i0.Output, args: ["dotLottieCreated"] }] } }); /** * Provides DotLottie configuration and optional features for the application. * * @param options - Configuration specifying how to load the `DotLottie` player class * @param features - Additional feature providers (e.g., `withDotLottieWasmUrl`) * @returns Environment providers for dependency injection * * @example * // Synchronous loading * import { DotLottie } from '@lottiefiles/dotlottie-web'; * * export const appConfig: ApplicationConfig = { * providers: [ * provideDotLottie({ * player: () => DotLottie, * }), * ], * }; * * @example * // Lazy loading with custom WASM URL * export const appConfig: ApplicationConfig = { * providers: [ * provideDotLottie( * { * player: () => import('@lottiefiles/dotlottie-web').then(m => m.DotLottie), * }, * withDotLottieWasmUrl('/assets/dotlottie-player.wasm'), * ), * ], * }; */ function provideDotLottie(options, ...features) { return makeEnvironmentProviders([ { provide: DOT_LOTTIE_OPTIONS, useValue: options, }, features, ]); } /** * Feature provider that configures a custom URL for the DotLottie WASM file. * The WASM URL is set lazily when the first DotLottie component renders, * rather than during app initialization. * * @param wasmUrl - Path or URL to the dotlottie-player WASM file. * Relative URLs will be resolved to absolute URLs automatically. * * @example * export const appConfig: ApplicationConfig = { * providers: [ * provideDotLottie( * { player: () => import('@lottiefiles/dotlottie-web').then(m => m.DotLottieWorker) }, * withDotLottieWasmUrl(() => 'http://localhost:4200/assets/dotlottie-player.wasm'), * ), * ], * }; */ function withDotLottieWasmUrl(wasmUrl) { return makeEnvironmentProviders([ { provide: DOT_LOTTIE_WASM_URL, useFactory: wasmUrl, }, ]); } /** * Generated bundle index. Do not edit. */ export { DotLottieComponent, DotLottieWorkerComponent, provideDotLottie, withDotLottieWasmUrl, ɵɵBaseDotLottieDirective }; //# sourceMappingURL=ngx-lottie-dotlottie-web.mjs.map