//#region src/components/animate-view/context.ts var instances = /* @__PURE__ */ new Set(); /** * The transition currently collecting participants. Registration closes as * soon as the update has flushed — NOT when the animation finishes playing * (which can take seconds), so unrelated mounts/updates during playback are * never misregistered. */ var activeTransition = null; /** * The most recently started transition. The browser skips an interrupted * transition when a new one begins, and the skipped one's `finished` settles * too — this guard stops a stale transition from removing names the newer * transition has applied. */ var latestTransition = null; /** Cancel functions returned by `animateViewLayers`, keyed by instance. */ var animationCleanups = /* @__PURE__ */ new Map(); function registerAnimateView(handle) { instances.add(handle); } function unregisterAnimateView(handle) { instances.delete(handle); } function getAnimateViews() { return instances; } function getActiveViewTransition() { return activeTransition; } function beginViewTransition(types) { activeTransition = { types, participants: [] }; latestTransition = activeTransition; return activeTransition; } /** * Close participant registration once the transition's DOM update has * flushed. The transition's pseudo-element snapshot is taken after this * point, so no further lifecycle events can belong to it. */ function closeViewTransitionRegistration(transition) { if (activeTransition === transition) activeTransition = null; } function endViewTransition(transition) { if (latestTransition !== transition) return; latestTransition = null; for (const instance of instances) instance.removeLayerNames(); if (activeTransition === transition) activeTransition = null; /** * Destroy every layer animation, not just forget them. Custom-value * animations are WAAPI animations attached to pseudo-elements BY NAME — * left lingering, they re-attach and replay when the same name reappears * in a later transition (wrap-around carousels, repeated shared-element * opens), and their accumulation crashes the Chrome renderer on rapid * navigation. */ for (const cleanup of animationCleanups.values()) cleanup(); animationCleanups.clear(); } /** * Store the cancel function for a participant's layer animation(s). * Multi-root participants produce one call per layer name — compose them. */ function setViewTransitionCleanup(handle, cleanup) { const existing = animationCleanups.get(handle); animationCleanups.set(handle, existing ? () => { existing(); cleanup(); } : cleanup); } /** * Cancel a layer animation still playing for an unmounted instance. Also * suppresses its `onAnimationComplete` via the cleanup's `active` guard. */ function cancelViewTransitionAnimation(handle) { const cleanup = animationCleanups.get(handle); if (cleanup) { animationCleanups.delete(handle); cleanup(); } } /** * Record that an instance is participating in the active transition. * The first recorded type wins within a single transition — an entering * element that also re-renders stays an "enter", not an "update". */ function recordParticipant(type, handle, transition = activeTransition) { if (!transition) return; if (transition.participants.some((p) => p.handle === handle)) return; transition.participants.push({ handle, layerNames: [...handle.layerNames], type, props: handle.getProps(), shareName: handle.getShareName() }); } //#endregion export { beginViewTransition, cancelViewTransitionAnimation, closeViewTransitionRegistration, endViewTransition, getActiveViewTransition, getAnimateViews, recordParticipant, registerAnimateView, setViewTransitionCleanup, unregisterAnimateView };