UNPKG

@motion-core/motion-gpu

Version:

Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte, React, and Vue adapter entrypoints.

130 lines (129 loc) 4.92 kB
//#region src/lib/core/error-overlay-stack.ts var stacks = /* @__PURE__ */ new WeakMap(); function getTopEntry(stack) { return stack.entries[stack.entries.length - 1]; } function getActiveHTMLElement(document) { const HTMLElementConstructor = document.defaultView?.HTMLElement; const activeElement = document.activeElement; return HTMLElementConstructor && activeElement instanceof HTMLElementConstructor ? activeElement : null; } function getBodyChildContaining(document, element) { let current = element; while (current?.parentElement && current.parentElement !== document.body) current = current.parentElement; return current?.parentElement === document.body ? current : null; } function restoreBackgroundElement(stack, element) { const wasInert = stack.backgroundElements.get(element); if (wasInert === void 0) return; element.inert = wasInert; stack.backgroundElements.delete(element); } function reconcileBackground(stack) { const topEntry = getTopEntry(stack); const activeBodyChild = topEntry ? getBodyChildContaining(stack.document, topEntry.portalRoot) : null; const nextBackgroundElements = /* @__PURE__ */ new Set(); const HTMLElementConstructor = stack.document.defaultView?.HTMLElement; if (topEntry && HTMLElementConstructor) for (const child of stack.document.body.children) { if (!(child instanceof HTMLElementConstructor) || child === activeBodyChild) continue; nextBackgroundElements.add(child); } for (const element of stack.backgroundElements.keys()) if (!nextBackgroundElements.has(element)) restoreBackgroundElement(stack, element); for (const element of nextBackgroundElements) { if (!stack.backgroundElements.has(element)) stack.backgroundElements.set(element, element.inert); element.inert = true; } } function focusTopEntry(stack) { const topEntry = getTopEntry(stack); if (!topEntry?.dialog.isConnected) return; topEntry.dialog.focus({ preventScroll: true }); } function createStack(document) { const stack = { document, entries: [], backgroundElements: /* @__PURE__ */ new Map(), baselineFocus: getActiveHTMLElement(document), focusInListener: () => void 0, keydownListener: () => void 0, observer: null }; stack.focusInListener = (event) => { const topEntry = getTopEntry(stack); const target = event.target; if (!topEntry || !target || topEntry.dialog.contains(target)) return; focusTopEntry(stack); }; stack.keydownListener = (event) => { if (event.key !== "Escape" || event.defaultPrevented) return; const topEntry = getTopEntry(stack); if (!topEntry || topEntry.dismissRequested) return; event.preventDefault(); topEntry.dismissRequested = true; try { topEntry.onDismiss(); } catch (error) { topEntry.dismissRequested = false; throw error; } }; document.addEventListener("focusin", stack.focusInListener); document.addEventListener("keydown", stack.keydownListener); const MutationObserverConstructor = document.defaultView?.MutationObserver; if (MutationObserverConstructor) { stack.observer = new MutationObserverConstructor(() => { reconcileBackground(stack); }); stack.observer.observe(document.body, { childList: true }); } stacks.set(document, stack); return stack; } function destroyStack(stack) { stack.document.removeEventListener("focusin", stack.focusInListener); stack.document.removeEventListener("keydown", stack.keydownListener); stack.observer?.disconnect(); for (const element of Array.from(stack.backgroundElements.keys())) restoreBackgroundElement(stack, element); const restoreTarget = stack.baselineFocus; stacks.delete(stack.document); if (restoreTarget?.isConnected) restoreTarget.focus({ preventScroll: true }); } function registerErrorOverlay({ dialog, portalRoot, onDismiss }) { const document = dialog.ownerDocument; const stack = stacks.get(document) ?? createStack(document); const entry = { dialog, portalRoot, onDismiss, dismissRequested: false }; stack.entries.push(entry); const activeBodyChild = getBodyChildContaining(document, portalRoot); if (activeBodyChild) restoreBackgroundElement(stack, activeBodyChild); focusTopEntry(stack); reconcileBackground(stack); let registered = true; return () => { if (!registered) return; registered = false; const entryIndex = stack.entries.indexOf(entry); if (entryIndex === -1) return; const wasTopEntry = entryIndex === stack.entries.length - 1; stack.entries.splice(entryIndex, 1); if (stack.entries.length === 0) { destroyStack(stack); return; } if (wasTopEntry) { const nextTopEntry = getTopEntry(stack); const nextActiveBodyChild = nextTopEntry ? getBodyChildContaining(document, nextTopEntry.portalRoot) : null; if (nextActiveBodyChild) restoreBackgroundElement(stack, nextActiveBodyChild); focusTopEntry(stack); } reconcileBackground(stack); }; } //#endregion export { registerErrorOverlay }; //# sourceMappingURL=error-overlay-stack.js.map