// Event-driven animation orchestration primitives.
//
// Reveal surfaces (Agents panel, sidebars, editor form) animate on the shared
// Splitter via CSS transitions; popovers animate via Radix/CSS animations. To
// sequence "surface A finishes before surface B starts" without guessing
// millisecond durations, we rely on real completion signals:
//
// - The animation OWNER (Splitter / popover) reports completion through a
//   settle registry keyed by a stable surface key (createSettleRegistry).
// - The ORCHESTRATOR can also await an element's running animations directly via
//   the Web Animations API (waitForElementAnimations), used for portaled Radix
//   popovers that are not Splitter panels.
//
// A safety timeout is only ever a guardrail so the pipeline can never hang if an
// expected transitionend/animationend is missed (it resolves, never rejects).
const DEFAULT_SAFETY_MS = 1500;
export function createSettleRegistry() {
    const pending = new Map();
    const flush = (key) => {
        const entry = pending.get(key);
        if (!entry)
            return;
        pending.delete(key);
        window.clearTimeout(entry.timer);
        entry.resolvers.forEach((resolve) => resolve());
    };
    return {
        waitForSurfaceSettled: (key, opts) => new Promise((resolve) => {
            const existing = pending.get(key);
            if (existing) {
                existing.resolvers.push(resolve);
                return;
            }
            const timer = window.setTimeout(() => flush(key), opts?.safetyMs ?? DEFAULT_SAFETY_MS);
            pending.set(key, { resolvers: [resolve], timer });
        }),
        notifySettled: flush,
    };
}
function nextFrame() {
    return new Promise((resolve) => {
        window.requestAnimationFrame(() => resolve());
    });
}
async function awaitRunningAnimations(el, safetyMs) {
    const getAnimations = el.getAnimations;
    if (typeof getAnimations !== "function")
        return;
    const animations = getAnimations.call(el, { subtree: true });
    if (!animations || animations.length === 0)
        return;
    await Promise.race([
        Promise.allSettled(animations.map((animation) => animation.finished)),
        new Promise((resolve) => window.setTimeout(resolve, safetyMs)),
    ]);
}
/**
 * Wait until all CSS transitions/animations currently running on `el` (and its
 * subtree) have finished, using the Web Animations API. A double-rAF start-gate
 * lets a freshly-triggered animation begin before we sample; if nothing is
 * running afterwards we treat the surface as already settled and resolve
 * immediately. `getAnimations` is feature-detected (absent in jsdom).
 */
export async function waitForElementAnimations(el, opts) {
    if (!el)
        return;
    // Let React commit + style recalc start the transition before sampling.
    await nextFrame();
    await nextFrame();
    await awaitRunningAnimations(el, opts?.safetyMs ?? DEFAULT_SAFETY_MS);
}
/**
 * Like waitForElementAnimations, but resolves the element by selector AFTER the
 * start-gate. Use for portaled surfaces (e.g. Radix popovers) that only mount
 * once their open animation begins, so a query at call time would return null.
 */
export async function waitForSelectorAnimations(selector, opts) {
    await nextFrame();
    await nextFrame();
    const el = document.querySelector(selector);
    if (!el)
        return;
    await awaitRunningAnimations(el, opts?.safetyMs ?? DEFAULT_SAFETY_MS);
}
//# sourceMappingURL=animationSettle.js.map