diff --git a/.changeset/smooth-snakes-think.md b/.changeset/smooth-snakes-think.md new file mode 100644 index 00000000..580070f0 --- /dev/null +++ b/.changeset/smooth-snakes-think.md @@ -0,0 +1,5 @@ +--- +'@lottiefiles/dotlottie-web': minor +--- + +feat: 🎸 added freezeOnOffscreen option to renderConfig diff --git a/apps/dotlottie-web-example/src/main.ts b/apps/dotlottie-web-example/src/main.ts index 74f00ee8..53190b8c 100644 --- a/apps/dotlottie-web-example/src/main.ts +++ b/apps/dotlottie-web-example/src/main.ts @@ -3,6 +3,7 @@ import './styles.css'; import type { Fit, Mode } from '@lottiefiles/dotlottie-web'; import { DotLottieWorker as DotLottie } from '@lottiefiles/dotlottie-web'; +// import { DotLottie } from '@lottiefiles/dotlottie-web'; import wasmUrl from '../../../packages/web/dist/dotlottie-player.wasm?url'; @@ -11,7 +12,7 @@ const app = document.getElementById('app') as HTMLDivElement; const baseUrl = window.location.origin + import.meta.env.BASE_URL; app.innerHTML = ` -
+
@@ -165,6 +166,8 @@ allCanvas.forEach((canvas) => { }); dotLottie.addEventListener('loadError', console.error); + dotLottie.addEventListener('freeze', console.log); + dotLottie.addEventListener('unfreeze', console.log); window.addEventListener('resize', () => { dotLottie.resize(); diff --git a/apps/with-parcel-example/tsconfig.json b/apps/with-parcel-example/tsconfig.json new file mode 100644 index 00000000..511a025b --- /dev/null +++ b/apps/with-parcel-example/tsconfig.json @@ -0,0 +1,9 @@ +{ + // Extend from the build config + "extends": "../../tsconfig.dev.json", + + // Compiler options + "compilerOptions": {}, + + "include": ["src"] +} diff --git a/packages/react/src/use-dotlottie-worker.tsx b/packages/react/src/use-dotlottie-worker.tsx index cde2db99..84093875 100644 --- a/packages/react/src/use-dotlottie-worker.tsx +++ b/packages/react/src/use-dotlottie-worker.tsx @@ -82,24 +82,6 @@ export const useDotLottieWorker = (config?: DotLottieWorkerConfig): UseDotLottie } }, []); - const intersectionObserver = useMemo(() => { - if (isServerSide()) return null; - - const observerCallback = (entries: IntersectionObserverEntry[]): void => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - dotLottieRef.current?.unfreeze(); - } else { - dotLottieRef.current?.freeze(); - } - }); - }; - - return new IntersectionObserver(observerCallback, { - threshold: 0, - }); - }, []); - const resizeObserver = useMemo(() => { if (isServerSide()) return null; @@ -138,22 +120,6 @@ export const useDotLottieWorker = (config?: DotLottieWorkerConfig): UseDotLottie canvas, }); - // Check if the canvas is initially in view - const initialEntry = canvas.getBoundingClientRect(); - - if ( - initialEntry.top >= 0 && - initialEntry.left >= 0 && - initialEntry.bottom <= (window.innerHeight || document.documentElement.clientHeight) && - initialEntry.right <= (window.innerWidth || document.documentElement.clientWidth) - ) { - dotLottieInstance.unfreeze(); - } else { - dotLottieInstance.freeze(); - } - - intersectionObserver?.observe(canvas); - if (config?.autoResizeCanvas) { resizeObserver?.observe(canvas); } @@ -167,11 +133,10 @@ export const useDotLottieWorker = (config?: DotLottieWorkerConfig): UseDotLottie dotLottieInstance?.destroy(); setDotLottie(null); resizeObserver?.disconnect(); - intersectionObserver?.disconnect(); canvas?.removeEventListener('mouseenter', hoverHandler); canvas?.removeEventListener('mouseleave', hoverHandler); }; - }, [intersectionObserver, resizeObserver, hoverHandler]); + }, [resizeObserver, hoverHandler]); // speed reactivity useEffect(() => { @@ -216,15 +181,10 @@ export const useDotLottieWorker = (config?: DotLottieWorkerConfig): UseDotLottie useEffect(() => { if (!dotLottieRef.current) return; - if ( - typeof config?.segment === 'object' && - Array.isArray(config.segment) && - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - config.segment.length === 2 - ) { - const startFrame = config.segment[0]; - const endFrame = config.segment[1]; + const startFrame = config?.segment?.[0]; + const endFrame = config?.segment?.[1]; + if (typeof startFrame === 'number' && typeof endFrame === 'number') { dotLottieRef.current.setSegment(startFrame, endFrame); } }, [config?.segment]); diff --git a/packages/react/src/use-dotlottie.tsx b/packages/react/src/use-dotlottie.tsx index 42d2ec08..924402de 100644 --- a/packages/react/src/use-dotlottie.tsx +++ b/packages/react/src/use-dotlottie.tsx @@ -81,24 +81,6 @@ export const useDotLottie = (config?: DotLottieConfig): UseDotLottieResult => { } }, []); - const intersectionObserver = useMemo(() => { - if (isServerSide()) return null; - - const observerCallback = (entries: IntersectionObserverEntry[]): void => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - dotLottieRef.current?.unfreeze(); - } else { - dotLottieRef.current?.freeze(); - } - }); - }; - - return new IntersectionObserver(observerCallback, { - threshold: 0, - }); - }, []); - const resizeObserver = useMemo(() => { if (isServerSide()) return null; @@ -137,22 +119,6 @@ export const useDotLottie = (config?: DotLottieConfig): UseDotLottieResult => { canvas, }); - // Check if the canvas is initially in view - const initialEntry = canvas.getBoundingClientRect(); - - if ( - initialEntry.top >= 0 && - initialEntry.left >= 0 && - initialEntry.bottom <= (window.innerHeight || document.documentElement.clientHeight) && - initialEntry.right <= (window.innerWidth || document.documentElement.clientWidth) - ) { - dotLottieInstance.unfreeze(); - } else { - dotLottieInstance.freeze(); - } - - intersectionObserver?.observe(canvas); - if (config?.autoResizeCanvas) { resizeObserver?.observe(canvas); } @@ -166,11 +132,10 @@ export const useDotLottie = (config?: DotLottieConfig): UseDotLottieResult => { dotLottieInstance?.destroy(); setDotLottie(null); resizeObserver?.disconnect(); - intersectionObserver?.disconnect(); canvas?.removeEventListener('mouseenter', hoverHandler); canvas?.removeEventListener('mouseleave', hoverHandler); }; - }, [intersectionObserver, resizeObserver, hoverHandler]); + }, [resizeObserver, hoverHandler]); // speed reactivity useEffect(() => { @@ -215,15 +180,10 @@ export const useDotLottie = (config?: DotLottieConfig): UseDotLottieResult => { useEffect(() => { if (!dotLottieRef.current) return; - if ( - typeof config?.segment === 'object' && - Array.isArray(config.segment) && - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - config.segment.length === 2 - ) { - const startFrame = config.segment[0]; - const endFrame = config.segment[1]; + const startFrame = config?.segment?.[0]; + const endFrame = config?.segment?.[1]; + if (typeof startFrame === 'number' && typeof endFrame === 'number') { dotLottieRef.current.setSegment(startFrame, endFrame); } }, [config?.segment]); diff --git a/packages/solid/src/use-dotlottie.tsx b/packages/solid/src/use-dotlottie.tsx index 0371abf2..0b4fe9e4 100644 --- a/packages/solid/src/use-dotlottie.tsx +++ b/packages/solid/src/use-dotlottie.tsx @@ -75,24 +75,6 @@ export const useDotLottie = (config: DotLottieConfig): UseDotLottieReturn => { } }; - const intersectionObserver = createMemo(() => { - if (isServer) return null; - - const observerCallback = debounce((entries: IntersectionObserverEntry[]) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - dotLottie()?.unfreeze(); - } else { - dotLottie()?.freeze(); - } - }); - }, 150); - - return new IntersectionObserver(observerCallback, { - threshold: 0, - }); - }); - const resizeObserver = createMemo(() => { if (isServer) return null; @@ -114,21 +96,6 @@ export const useDotLottie = (config: DotLottieConfig): UseDotLottieReturn => { setDotLottie(dotLottieInstance); - // check if canvas is initially in view - const initialEntry = canvas.getBoundingClientRect(); - - if ( - initialEntry.top >= 0 && - initialEntry.left >= 0 && - initialEntry.bottom <= (window.innerHeight || document.documentElement.clientHeight) && - initialEntry.right <= (window.innerWidth || document.documentElement.clientWidth) - ) { - dotLottie()?.unfreeze(); - } else { - dotLottie()?.freeze(); - } - - intersectionObserver()?.observe(canvas); if (config.autoResizeCanvas) { resizeObserver()?.observe(canvas); } @@ -137,7 +104,6 @@ export const useDotLottie = (config: DotLottieConfig): UseDotLottieReturn => { canvas.addEventListener('mouseleave', hoverHandler); } else { dotLottie()?.destroy(); - intersectionObserver()?.disconnect(); resizeObserver()?.disconnect(); } @@ -156,7 +122,6 @@ export const useDotLottie = (config: DotLottieConfig): UseDotLottieReturn => { dotLottie()?.destroy(); setDotLottie(null); resizeObserver()?.disconnect(); - intersectionObserver()?.disconnect(); if (canvasRef) { canvasRef.removeEventListener('mouseenter', hoverHandler); canvasRef.removeEventListener('mouseleave', hoverHandler); diff --git a/packages/svelte/src/lib/Dotlottie.svelte b/packages/svelte/src/lib/Dotlottie.svelte index f9bf5a68..7c0252f8 100644 --- a/packages/svelte/src/lib/Dotlottie.svelte +++ b/packages/svelte/src/lib/Dotlottie.svelte @@ -69,27 +69,15 @@ } }, 150)); - const intersectionObserver = new IntersectionObserver(debounce((entries: IntersectionObserverEntry[]) => { - entries.forEach(entry => { - if (entry.isIntersecting) { - dotLottie.unfreeze(); - } else { - dotLottie.freeze(); - } - }); - }, 150), { threshold: 0 }); - if (autoResizeCanvas) { resizeObserver.observe(canvas); } - intersectionObserver.observe(canvas); canvas.addEventListener('mouseenter', hoverHandler); canvas.addEventListener('mouseleave', hoverHandler); return () => { resizeObserver.disconnect(); - intersectionObserver.disconnect(); canvas.removeEventListener('mouseenter', hoverHandler); canvas.removeEventListener('mouseleave', hoverHandler); dotLottie.destroy(); diff --git a/packages/vue/src/dotlottie.ts b/packages/vue/src/dotlottie.ts index 49e7d5f6..d4dc5f35 100644 --- a/packages/vue/src/dotlottie.ts +++ b/packages/vue/src/dotlottie.ts @@ -60,7 +60,6 @@ export const DotLottieVue = defineComponent({ useFrameInterpolation, } = toRefs(props); let dotLottie: DotLottie | null = null; - let intersectionObserver: IntersectionObserver | null = null; let resizeObserver: ResizeObserver | null = null; // Prop change @@ -99,9 +98,13 @@ export const DotLottieVue = defineComponent({ watch( () => segment?.value, (newVal) => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (dotLottie && Array.isArray(newVal) && newVal.length === 2) { - dotLottie.setSegment(newVal[0], newVal[1]); + if (!dotLottie) return; + + const startFrame = newVal?.[0]; + const endFrame = newVal?.[1]; + + if (typeof startFrame === 'number' && typeof endFrame === 'number') { + dotLottie.setSegment(startFrame, endFrame); } }, ); @@ -172,23 +175,6 @@ export const DotLottieVue = defineComponent({ }, ); - function getIntersectionObserver(): IntersectionObserver { - return new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - dotLottie?.unfreeze(); - } else { - dotLottie?.freeze(); - } - }); - }, - { - threshold: 0, - }, - ); - } - function getResizeObserver(): ResizeObserver { return new ResizeObserver((entries) => { entries.forEach(() => { @@ -212,8 +198,6 @@ export const DotLottieVue = defineComponent({ autoplay: shouldAutoplay, }); - intersectionObserver = getIntersectionObserver(); - intersectionObserver.observe(canvas.value); if (typeof autoResizeCanvas?.value === 'boolean' && autoResizeCanvas.value) { resizeObserver = getResizeObserver(); resizeObserver.observe(canvas.value); @@ -226,7 +210,6 @@ export const DotLottieVue = defineComponent({ onBeforeUnmount(() => { resizeObserver?.disconnect(); - intersectionObserver?.disconnect(); canvas.value?.addEventListener('mouseenter', hoverHandler); canvas.value?.addEventListener('mouseleave', hoverHandler); dotLottie?.destroy(); diff --git a/packages/wc/src/dotlottie-wc.ts b/packages/wc/src/dotlottie-wc.ts index 3eb25629..732728e0 100644 --- a/packages/wc/src/dotlottie-wc.ts +++ b/packages/wc/src/dotlottie-wc.ts @@ -28,8 +28,6 @@ export class DotLottieWC extends LitElement { @state() public dotLottie: DotLottie | null = null; - private readonly _intersectionObserver: IntersectionObserver; - private readonly _resizeObserver: ResizeObserver; public static override styles = css` @@ -46,20 +44,6 @@ export class DotLottieWC extends LitElement { public constructor() { super(); - this._intersectionObserver = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (this.dotLottie) { - if (entry.isIntersecting) { - this.dotLottie.unfreeze(); - } else { - this.dotLottie.freeze(); - } - } - }); - }, - { threshold: 0.1 }, - ); this._resizeObserver = new ResizeObserver((entries) => { if (this.dotLottie && entries[0]) { @@ -92,7 +76,6 @@ export class DotLottieWC extends LitElement { this.dotLottie = null; } - this._intersectionObserver.disconnect(); this._resizeObserver.disconnect(); } @@ -124,7 +107,6 @@ export class DotLottieWC extends LitElement { renderConfig: this.renderConfig, useFrameInterpolation: this.useFrameInterpolation, }); - this._intersectionObserver.observe(canvas); this._resizeObserver.observe(canvas); } } diff --git a/packages/web/src/dotlottie.ts b/packages/web/src/dotlottie.ts index d4d984cb..92cb0733 100644 --- a/packages/web/src/dotlottie.ts +++ b/packages/web/src/dotlottie.ts @@ -4,8 +4,9 @@ import type { DotLottiePlayer, MainModule, Mode as CoreMode, VectorFloat, Marker import { DotLottieWasmLoader } from './core'; import type { EventListener, EventType } from './event-manager'; import { EventManager } from './event-manager'; +import { OffscreenObserver } from './offscreen-observer'; import type { Mode, Fit, Config, Layout, Manifest, RenderConfig, Data } from './types'; -import { getDefaultDPR, hexStringToRGBAInt, isDotLottie, isLottie } from './utils'; +import { getDefaultDPR, hexStringToRGBAInt, isDotLottie, isElementInViewport, isLottie } from './utils'; const createCoreMode = (mode: Mode, module: MainModule): CoreMode => { if (mode === 'reverse') { @@ -96,6 +97,8 @@ export class DotLottie { this._frameManager = new AnimationFrameManager(); this._renderConfig = { devicePixelRatio: config.renderConfig?.devicePixelRatio || getDefaultDPR(), + // freezeOnOffscreen is true by default to prevent unnecessary rendering when the canvas is offscreen + freezeOnOffscreen: config.renderConfig?.freezeOnOffscreen ?? true, }; DotLottieWasmLoader.load() @@ -243,6 +246,10 @@ export class DotLottie { console.error('something went wrong, the animation was suppose to autoplay'); } } + + if (IS_BROWSER && this._canvas instanceof HTMLCanvasElement && this._renderConfig.freezeOnOffscreen) { + OffscreenObserver.observe(this._canvas, this); + } } else { this._dispatchError('Failed to load animation data'); } @@ -523,6 +530,20 @@ export class DotLottie { this._eventManager.dispatch({ type: 'play' }); this._animationFrameId = this._frameManager.requestAnimationFrame(this._draw.bind(this)); } + + /* + Check if the canvas is offscreen and freezing is enabled + If freezeOnOffscreen is true and the canvas is currently outside the viewport, + we immediately freeze the animation to avoid unnecessary rendering and performance overhead. + */ + if ( + IS_BROWSER && + this._canvas instanceof HTMLCanvasElement && + this._renderConfig.freezeOnOffscreen && + !isElementInViewport(this._canvas) + ) { + this.freeze(); + } } public pause(): void { @@ -614,6 +635,10 @@ export class DotLottie { } public destroy(): void { + if (IS_BROWSER && this._canvas instanceof HTMLCanvasElement) { + OffscreenObserver.unobserve(this._canvas); + } + this._dotLottieCore?.delete(); this._dotLottieCore = null; this._context = null; @@ -683,12 +708,28 @@ export class DotLottie { } public setRenderConfig(config: RenderConfig): void { + const { devicePixelRatio, freezeOnOffscreen, ...restConfig } = config; + this._renderConfig = { ...this._renderConfig, - ...config, + ...restConfig, // devicePixelRatio is a special case, it should be set to the default value if it's not provided - devicePixelRatio: config.devicePixelRatio || getDefaultDPR(), + devicePixelRatio: devicePixelRatio || getDefaultDPR(), + freezeOnOffscreen: freezeOnOffscreen ?? true, }; + + if (IS_BROWSER && this._canvas instanceof HTMLCanvasElement) { + if (this._renderConfig.freezeOnOffscreen) { + OffscreenObserver.observe(this._canvas, this); + } else { + OffscreenObserver.unobserve(this._canvas); + // If the animation was previously frozen, we need to unfreeze it now + // to ensure it resumes rendering when the canvas is back onscreen. + if (this._isFrozen) { + this.unfreeze(); + } + } + } } public loadAnimation(animationId: string): void { diff --git a/packages/web/src/offscreen-observer.ts b/packages/web/src/offscreen-observer.ts new file mode 100644 index 00000000..68451325 --- /dev/null +++ b/packages/web/src/offscreen-observer.ts @@ -0,0 +1,50 @@ +import type { DotLottie } from './dotlottie'; +import type { DotLottieWorker } from './worker/dotlottie'; + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class OffscreenObserver { + private static _observer: IntersectionObserver | null = null; + + private static readonly _observedCanvases = new Map(); + + private static _initializeObserver(): void { + if (this._observer) return; + + const intersectionObserverCallback = (entries: IntersectionObserverEntry[]): void => { + entries.forEach((entry) => { + const instance = this._observedCanvases.get(entry.target as HTMLCanvasElement); + + if (instance) { + if (entry.isIntersecting) { + instance.unfreeze(); + } else { + instance.freeze(); + } + } + }); + }; + + this._observer = new IntersectionObserver(intersectionObserverCallback, { + threshold: 0, + }); + } + + public static observe(canvas: HTMLCanvasElement, dotLottieInstance: DotLottie | DotLottieWorker): void { + this._initializeObserver(); + + if (this._observedCanvases.has(canvas)) return; + + this._observedCanvases.set(canvas, dotLottieInstance); + this._observer?.observe(canvas); + } + + public static unobserve(canvas: HTMLCanvasElement): void { + this._observer?.unobserve(canvas); + this._observedCanvases.delete(canvas); + + if (this._observedCanvases.size === 0) { + this._observer?.disconnect(); + this._observer = null; + } + } +} diff --git a/packages/web/src/types.ts b/packages/web/src/types.ts index 6f83e4f3..036c34cb 100644 --- a/packages/web/src/types.ts +++ b/packages/web/src/types.ts @@ -1,5 +1,6 @@ export interface RenderConfig { devicePixelRatio?: number; + freezeOnOffscreen?: boolean; } export type Mode = 'forward' | 'reverse' | 'bounce' | 'reverse-bounce'; diff --git a/packages/web/src/utils.ts b/packages/web/src/utils.ts index 32264158..c12112c9 100644 --- a/packages/web/src/utils.ts +++ b/packages/web/src/utils.ts @@ -57,3 +57,14 @@ export function getDefaultDPR(): number { return 1 + (dpr - 1) * DEFAULT_DPR_FACTOR; } + +export function isElementInViewport(element: HTMLElement): boolean { + const rect = element.getBoundingClientRect(); + + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); +} diff --git a/packages/web/src/worker/dotlottie.ts b/packages/web/src/worker/dotlottie.ts index 80ef9ee6..09ea2fac 100644 --- a/packages/web/src/worker/dotlottie.ts +++ b/packages/web/src/worker/dotlottie.ts @@ -2,8 +2,9 @@ import { IS_BROWSER } from '../constants'; import type { Marker } from '../core'; import type { EventType, EventListener, FrameEvent } from '../event-manager'; import { EventManager } from '../event-manager'; +import { OffscreenObserver } from '../offscreen-observer'; import type { Config, Layout, Manifest, Mode, RenderConfig } from '../types'; -import { getDefaultDPR } from '../utils'; +import { getDefaultDPR, isElementInViewport } from '../utils'; import type { MethodParamsMap, MethodResultMap, RpcRequest, RpcResponse } from './types'; import { WorkerManager } from './worker-manager'; @@ -125,6 +126,8 @@ export class DotLottieWorker { renderConfig: { ...config.renderConfig, devicePixelRatio: config.renderConfig?.devicePixelRatio || getDefaultDPR(), + // freezeOnOffscreen is true by default to prevent unnecessary rendering when the canvas is offscreen + freezeOnOffscreen: config.renderConfig?.freezeOnOffscreen ?? true, }, }); @@ -164,6 +167,15 @@ export class DotLottieWorker { if (rpcResponse.method === 'onLoad' && rpcResponse.result.instanceId === this._id) { await this._updateDotLottieInstanceState(); this._eventManager.dispatch(rpcResponse.result.event); + + // start observing the canvas for offscreen changes + if ( + IS_BROWSER && + this._canvas instanceof HTMLCanvasElement && + this._dotLottieInstanceState.renderConfig.freezeOnOffscreen + ) { + OffscreenObserver.observe(this._canvas, this); + } } if (rpcResponse.method === 'onComplete' && rpcResponse.result.instanceId === this._id) { @@ -355,6 +367,20 @@ export class DotLottieWorker { await this._sendMessage('play', { instanceId: this._id }); await this._updateDotLottieInstanceState(); + + /* + Check if the canvas is offscreen and freezing is enabled + If freezeOnOffscreen is true and the canvas is currently outside the viewport, + we immediately freeze the animation to avoid unnecessary rendering and performance overhead. + */ + if ( + IS_BROWSER && + this._canvas instanceof HTMLCanvasElement && + this._dotLottieInstanceState.renderConfig.freezeOnOffscreen && + !isElementInViewport(this._canvas) + ) { + await this.freeze(); + } } public async pause(): Promise { @@ -402,16 +428,33 @@ export class DotLottieWorker { public async setRenderConfig(renderConfig: RenderConfig): Promise { if (!this._created) return; + const { devicePixelRatio, freezeOnOffscreen, ...restConfig } = renderConfig; + await this._sendMessage('setRenderConfig', { instanceId: this._id, renderConfig: { ...this._dotLottieInstanceState.renderConfig, - ...renderConfig, + ...restConfig, // devicePixelRatio is a special case, it should be set to the default value if it's not provided - devicePixelRatio: renderConfig.devicePixelRatio || getDefaultDPR(), + devicePixelRatio: devicePixelRatio || getDefaultDPR(), + freezeOnOffscreen: freezeOnOffscreen ?? true, }, }); + await this._updateDotLottieInstanceState(); + + if (IS_BROWSER && this._canvas instanceof HTMLCanvasElement) { + if (this._dotLottieInstanceState.renderConfig.freezeOnOffscreen) { + OffscreenObserver.observe(this._canvas, this); + } else { + OffscreenObserver.unobserve(this._canvas); + // If the animation was previously frozen, we need to unfreeze it now + // to ensure it resumes rendering when the canvas is back onscreen. + if (this._dotLottieInstanceState.isFrozen) { + await this.unfreeze(); + } + } + } } public async setUseFrameInterpolation(useFrameInterpolation: boolean): Promise { @@ -465,6 +508,10 @@ export class DotLottieWorker { DotLottieWorker._workerManager.unassignAnimationFromWorker(this._id); this._eventManager.removeAllEventListeners(); + + if (IS_BROWSER && this._canvas instanceof HTMLCanvasElement) { + OffscreenObserver.unobserve(this._canvas); + } } public async freeze(): Promise { diff --git a/packages/web/tests/dotlottie-worker.test.ts b/packages/web/tests/dotlottie-worker.test.ts index f015064c..72dc19de 100644 --- a/packages/web/tests/dotlottie-worker.test.ts +++ b/packages/web/tests/dotlottie-worker.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable require-atomic-updates */ import { describe, beforeEach, afterEach, test, expect, vi } from 'vitest'; import { DotLottieWorker as DotLottie } from '../src'; @@ -1762,3 +1763,202 @@ test('setViewport() sets the viewport', async () => { expect(updated).toBe(true); }); + +test('freezeOnOffscreen defaults to true when not defined', async () => { + const onFreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + // freezeOnOffscreen is not explicitly defined + }); + + dotLottie.addEventListener('freeze', onFreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('freeze when canvas is initially offscreen and freezeOnOffscreen is true', async () => { + const onFreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('do not freeze when canvas is initially offscreen and freezeOnOffscreen is false', async () => { + const onFreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: false, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(onFreeze).not.toHaveBeenCalled(); + + expect(dotLottie.isFrozen).toBe(false); +}); + +test('freeze when canvas goes offscreen during animation', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(dotLottie.isPlaying).toBe(true); + }); + + canvas.style.marginTop = '100vh'; + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('unfreeze when canvas comes back into the viewport', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + canvas.style.marginTop = '0'; + + await vi.waitFor(() => { + expect(onUnfreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isPlaying).toBe(true); + expect(dotLottie.isFrozen).toBe(false); +}); + +test('stay frozen if canvas remains offscreen and freezeOnOffscreen is true', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); + expect(onUnfreeze).not.toHaveBeenCalled(); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('update freezeOnOffscreen using setRenderConfig', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); + + await dotLottie.setRenderConfig({ + freezeOnOffscreen: false, + }); + + canvas.style.marginTop = '0'; + + await vi.waitFor(() => { + expect(onUnfreeze).toHaveBeenCalledTimes(1); + }); + + canvas.style.marginTop = '100vh'; + + await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(onFreeze).toHaveBeenCalledTimes(1); + + expect(dotLottie.isFrozen).toBe(false); +}); diff --git a/packages/web/tests/dotlottie.test.ts b/packages/web/tests/dotlottie.test.ts index 98699c15..78fde18d 100644 --- a/packages/web/tests/dotlottie.test.ts +++ b/packages/web/tests/dotlottie.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable require-atomic-updates */ import { describe, beforeEach, afterEach, test, expect, vi } from 'vitest'; import type { Config, Layout, Mode } from '../src'; @@ -1774,3 +1775,202 @@ test('setViewport() sets the viewport', async () => { expect(updated).toBe(true); }); + +test('freezeOnOffscreen defaults to true when not defined', async () => { + const onFreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + // freezeOnOffscreen is not explicitly defined + }); + + dotLottie.addEventListener('freeze', onFreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('freeze when canvas is initially offscreen and freezeOnOffscreen is true', async () => { + const onFreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('do not freeze when canvas is initially offscreen and freezeOnOffscreen is false', async () => { + const onFreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: false, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(onFreeze).not.toHaveBeenCalled(); + + expect(dotLottie.isFrozen).toBe(false); +}); + +test('freeze when canvas goes offscreen during animation', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(dotLottie.isPlaying).toBe(true); + }); + + canvas.style.marginTop = '100vh'; + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('unfreeze when canvas comes back into the viewport', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + canvas.style.marginTop = '0'; + + await vi.waitFor(() => { + expect(onUnfreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isPlaying).toBe(true); + expect(dotLottie.isFrozen).toBe(false); +}); + +test('stay frozen if canvas remains offscreen and freezeOnOffscreen is true', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); + expect(onUnfreeze).not.toHaveBeenCalled(); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + + expect(dotLottie.isFrozen).toBe(true); +}); + +test('update freezeOnOffscreen using setRenderConfig', async () => { + const onFreeze = vi.fn(); + const onUnfreeze = vi.fn(); + + canvas.style.marginTop = '100vh'; + + dotLottie = new DotLottie({ + canvas, + src: jsonSrc, + autoplay: true, + renderConfig: { + freezeOnOffscreen: true, + }, + }); + + dotLottie.addEventListener('freeze', onFreeze); + dotLottie.addEventListener('unfreeze', onUnfreeze); + + await vi.waitFor(() => { + expect(onFreeze).toHaveBeenCalledTimes(1); + }); + + expect(dotLottie.isFrozen).toBe(true); + + dotLottie.setRenderConfig({ + freezeOnOffscreen: false, + }); + + canvas.style.marginTop = '0'; + + await vi.waitFor(() => { + expect(onUnfreeze).toHaveBeenCalledTimes(1); + }); + + canvas.style.marginTop = '100vh'; + + await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(onFreeze).toHaveBeenCalledTimes(1); + + expect(dotLottie.isFrozen).toBe(false); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c6b3ee6..ae24c630 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12353,73 +12353,69 @@ snapshots: '@open-draft/until@2.1.0': {} - '@parcel/bundler-default@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/bundler-default@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 '@parcel/graph': 3.2.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/rust': 2.12.0 '@parcel/utils': 2.12.0 nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/cache@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/cache@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.5) '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/logger': 2.12.0 '@parcel/utils': 2.12.0 lmdb: 2.8.5 - transitivePeerDependencies: - - '@swc/helpers' '@parcel/codeframe@2.12.0': dependencies: chalk: 4.1.2 - '@parcel/compressor-raw@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/compressor-raw@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' '@parcel/config-default@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)(postcss@8.4.39)(terser@5.31.1)(typescript@5.4.5)': dependencies: - '@parcel/bundler-default': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/compressor-raw': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/bundler-default': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/compressor-raw': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/core': 2.12.0(@swc/helpers@0.5.5) - '@parcel/namer-default': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/optimizer-css': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/optimizer-htmlnano': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)(postcss@8.4.39)(terser@5.31.1)(typescript@5.4.5) - '@parcel/optimizer-image': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/optimizer-svgo': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/namer-default': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/optimizer-css': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/optimizer-htmlnano': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(postcss@8.4.39)(terser@5.31.1)(typescript@5.4.5) + '@parcel/optimizer-image': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/optimizer-svgo': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/optimizer-swc': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/packager-css': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/packager-html': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/packager-js': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/packager-raw': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/packager-svg': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/packager-wasm': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/reporter-dev-server': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/resolver-default': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/runtime-browser-hmr': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/runtime-js': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/runtime-react-refresh': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/runtime-service-worker': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-babel': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-css': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-html': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-image': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/packager-css': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/packager-html': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/packager-js': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/packager-raw': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/packager-svg': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/packager-wasm': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/reporter-dev-server': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/resolver-default': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/runtime-browser-hmr': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/runtime-js': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/runtime-react-refresh': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/runtime-service-worker': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-babel': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-css': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-html': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-image': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/transformer-js': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) - '@parcel/transformer-json': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-postcss': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-posthtml': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-raw': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-react-refresh-wrap': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/transformer-svg': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/transformer-json': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-postcss': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-posthtml': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-raw': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-react-refresh-wrap': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/transformer-svg': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) transitivePeerDependencies: - '@swc/helpers' - cssnano @@ -12434,20 +12430,20 @@ snapshots: '@parcel/core@2.12.0(@swc/helpers@0.5.5)': dependencies: '@mischnic/json-sourcemap': 0.1.1 - '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/diagnostic': 2.12.0 '@parcel/events': 2.12.0 '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/graph': 3.2.0 '@parcel/logger': 2.12.0 '@parcel/package-manager': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/profiler': 2.12.0 '@parcel/rust': 2.12.0 '@parcel/source-map': 2.1.1 '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) abortcontroller-polyfill: 1.7.5 base-x: 3.0.10 browserslist: 4.23.2 @@ -12475,7 +12471,7 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/utils': 2.12.0 '@parcel/watcher': 2.4.1 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) transitivePeerDependencies: - '@swc/helpers' @@ -12492,14 +12488,13 @@ snapshots: dependencies: chalk: 4.1.2 - '@parcel/namer-default@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/namer-default@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' '@parcel/node-resolver-core@3.3.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: @@ -12513,10 +12508,10 @@ snapshots: transitivePeerDependencies: - '@parcel/core' - '@parcel/optimizer-css@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/optimizer-css@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 browserslist: 4.23.2 @@ -12524,18 +12519,16 @@ snapshots: nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/optimizer-htmlnano@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)(postcss@8.4.39)(terser@5.31.1)(typescript@5.4.5)': + '@parcel/optimizer-htmlnano@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(postcss@8.4.39)(terser@5.31.1)(typescript@5.4.5)': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) htmlnano: 2.1.1(postcss@8.4.39)(svgo@2.8.0)(terser@5.31.1)(typescript@5.4.5) nullthrows: 1.1.1 posthtml: 0.16.6 svgo: 2.8.0 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - cssnano - postcss - purgecss @@ -12545,31 +12538,28 @@ snapshots: - typescript - uncss - '@parcel/optimizer-image@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/optimizer-image@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.5) '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/rust': 2.12.0 '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - transitivePeerDependencies: - - '@swc/helpers' + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) - '@parcel/optimizer-svgo@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/optimizer-svgo@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 svgo: 2.8.0 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' '@parcel/optimizer-swc@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 '@swc/core': 1.3.107(@swc/helpers@0.5.5) @@ -12587,39 +12577,37 @@ snapshots: '@parcel/node-resolver-core': 3.3.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@swc/core': 1.3.107(@swc/helpers@0.5.5) semver: 7.6.3 transitivePeerDependencies: - '@swc/helpers' - '@parcel/packager-css@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/packager-css@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 lightningcss: 1.26.0 nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/packager-html@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/packager-html@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 posthtml: 0.16.6 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/packager-js@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/packager-js@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/rust': 2.12.0 '@parcel/source-map': 2.1.1 '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) @@ -12628,38 +12616,33 @@ snapshots: nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/packager-raw@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/packager-raw@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/packager-svg@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/packager-svg@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/utils': 2.12.0 posthtml: 0.16.6 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/packager-wasm@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/packager-wasm@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/plugin@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/plugin@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' '@parcel/profiler@2.12.0': dependencies: @@ -12667,79 +12650,71 @@ snapshots: '@parcel/events': 2.12.0 chrome-trace-event: 1.0.3 - '@parcel/reporter-cli@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/reporter-cli@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/utils': 2.12.0 chalk: 4.1.2 term-size: 2.2.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/reporter-dev-server@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/reporter-dev-server@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/reporter-tracer@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/reporter-tracer@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 chrome-trace-event: 1.0.3 nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/resolver-default@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/resolver-default@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/node-resolver-core': 3.3.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/runtime-browser-hmr@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/runtime-browser-hmr@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/runtime-js@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/runtime-js@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/runtime-react-refresh@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/runtime-react-refresh@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 react-error-overlay: 6.0.9 react-refresh: 0.9.0 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/runtime-service-worker@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/runtime-service-worker@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' '@parcel/rust@2.12.0': {} @@ -12747,10 +12722,10 @@ snapshots: dependencies: detect-libc: 1.0.3 - '@parcel/transformer-babel@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-babel@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 browserslist: 4.23.2 @@ -12759,12 +12734,11 @@ snapshots: semver: 7.6.3 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-css@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-css@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 browserslist: 4.23.2 @@ -12772,12 +12746,11 @@ snapshots: nullthrows: 1.1.1 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-html@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-html@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/rust': 2.12.0 nullthrows: 1.1.1 posthtml: 0.16.6 @@ -12787,45 +12760,41 @@ snapshots: srcset: 4.0.0 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-image@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-image@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.5) - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) nullthrows: 1.1.1 - transitivePeerDependencies: - - '@swc/helpers' '@parcel/transformer-js@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.5) '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/rust': 2.12.0 '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@swc/helpers': 0.5.5 browserslist: 4.23.2 nullthrows: 1.1.1 regenerator-runtime: 0.13.11 semver: 7.6.3 - '@parcel/transformer-json@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-json@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) json5: 2.2.3 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-postcss@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-postcss@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/rust': 2.12.0 '@parcel/utils': 2.12.0 clone: 2.1.2 @@ -12834,11 +12803,10 @@ snapshots: semver: 7.6.3 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-posthtml@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-posthtml@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 posthtml: 0.16.6 @@ -12847,28 +12815,25 @@ snapshots: semver: 7.6.3 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-raw@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-raw@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-react-refresh-wrap@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-react-refresh-wrap@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 react-refresh: 0.9.0 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' - '@parcel/transformer-svg@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/transformer-svg@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/diagnostic': 2.12.0 - '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/rust': 2.12.0 nullthrows: 1.1.1 posthtml: 0.16.6 @@ -12877,16 +12842,15 @@ snapshots: semver: 7.6.3 transitivePeerDependencies: - '@parcel/core' - - '@swc/helpers' '@parcel/types@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': dependencies: - '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/diagnostic': 2.12.0 '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/package-manager': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/source-map': 2.1.1 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) utility-types: 3.11.0 transitivePeerDependencies: - '@parcel/core' @@ -12959,7 +12923,7 @@ snapshots: '@parcel/watcher-win32-ia32': 2.4.1 '@parcel/watcher-win32-x64': 2.4.1 - '@parcel/workers@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5)': + '@parcel/workers@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.5) '@parcel/diagnostic': 2.12.0 @@ -12968,8 +12932,6 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 - transitivePeerDependencies: - - '@swc/helpers' '@peculiar/asn1-schema@2.3.8': dependencies: @@ -19576,9 +19538,9 @@ snapshots: '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) '@parcel/logger': 2.12.0 '@parcel/package-manager': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/reporter-cli': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/reporter-dev-server': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) - '@parcel/reporter-tracer': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5))(@swc/helpers@0.5.5) + '@parcel/reporter-cli': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/reporter-dev-server': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) + '@parcel/reporter-tracer': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.5)) '@parcel/utils': 2.12.0 chalk: 4.1.2 commander: 7.2.0