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
JavaScript
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