{"version":3,"file":"index.mjs","sources":["../../../src/scope/index.ts"],"sourcesContent":["import { removeItem } from \"motion-utils\"\nimport { releaseElement } from \"../animation/animate/element\"\nimport type { AnimationOptions } from \"../animation/types\"\nimport { ElementOrSelector, resolveElements } from \"../utils/resolve-elements\"\nimport { activeScope, ActiveScope, addToScope } from \"./active\"\nimport { toMediaQuery } from \"./media\"\n\n/**\n * A media query or shorthand (see `toMediaQuery`), or named conditions.\n * With named conditions, setup runs when any of them match, and their\n * state is available as `scope.media`.\n */\nexport type MediaConditions = string | Record<string, string>\n\nexport interface ScopeOptions {\n    /**\n     * Default transition for every `animate()` call made in this scope.\n     */\n    transition?: AnimationOptions\n\n    /**\n     * Only run setup while these conditions match. When they change, the\n     * scope is cancelled and setup runs again.\n     */\n    matchMedia?: MediaConditions\n}\n\nexport type ScopeState = \"active\" | \"stopped\" | \"cancelled\"\n\nexport interface MotionScope {\n    /**\n     * `\"active\"` until `stop()` or `cancel()` is called. Lets async work\n     * check whether its scope has gone before it starts animating.\n     */\n    state: ScopeState\n\n    /**\n     * Whether each named `matchMedia` condition matched when setup last ran.\n     */\n    media: Record<string, boolean>\n\n    /**\n     * Run `callback` in this scope, so animations, scroll and view\n     * listeners and gestures it starts are collected.\n     */\n    run<R>(callback: () => R): R\n\n    /**\n     * Return a function that runs `callback` in this scope, for instance\n     * as an event handler.\n     */\n    bind<F extends (...args: any[]) => any>(callback: F): F\n\n    /**\n     * Run `callback` outside of any scope, so what it starts is not\n     * collected and survives this scope being stopped or cancelled.\n     */\n    ignore<R>(callback: () => R): R\n\n    /**\n     * Stop everything in this scope and remove its media listeners.\n     * Styles are left as they are.\n     */\n    stop(): void\n\n    /**\n     * As `stop()`, and restore the inline styles of every element\n     * animated in this scope to what they were before.\n     */\n    cancel(): void\n\n    /**\n     * Cancel, then run setup again if the media conditions match.\n     */\n    refresh(): void\n}\n\nexport type ScopeSetup = (scope: MotionScope) => void | VoidFunction\n\n/**\n * Create a scope that collects the animations, scroll and view\n * listeners, gestures and resize observers started inside it, so they\n * can be stopped or cancelled together.\n *\n * An optional root element or selector comes first. Selectors used\n * inside the scope resolve within it.\n *\n * ```js\n * const scope = scopeMotion(\n *     \".list\",\n *     ({ media }) => {\n *         animate(\"li\", { x: media.desktop ? 100 : 0 })\n *     },\n *     { transition: { duration: 0.5 }, matchMedia: { desktop: \">=800\" } }\n * )\n * ```\n *\n * @public\n */\nexport function scopeMotion(\n    setup?: ScopeSetup,\n    options?: ScopeOptions\n): MotionScope\nexport function scopeMotion(\n    root: ElementOrSelector,\n    setup?: ScopeSetup,\n    options?: ScopeOptions\n): MotionScope\nexport function scopeMotion(...args: [any?, any?, any?]): MotionScope {\n    const root: ElementOrSelector =\n        typeof args[0] === \"function\" ? undefined : args.shift()\n    const [setup, options = {}] = args as [ScopeSetup?, ScopeOptions?]\n\n    const { transition, matchMedia } = options\n    const queries: [string, MediaQueryList][] = []\n    const styles = new Map<Element, string | null>()\n    let cleanups: VoidFunction[] = []\n    let isPending = false\n\n    const active: ActiveScope = {\n        root: resolveElements(root)[0],\n        transition,\n        add(cleanup) {\n            cleanups.push(cleanup)\n            return () => removeItem(cleanups, cleanup)\n        },\n        bind: (callback) =>\n            ((...args: any[]) => {\n                const result = scope.run(() => callback(...args))\n                return typeof result === \"function\"\n                    ? active.bind(result)\n                    : result\n            }) as typeof callback,\n        track(element) {\n            styles.has(element) ||\n                styles.set(element, element.getAttribute(\"style\"))\n        },\n    }\n\n    const clear = (restore?: boolean) => {\n        const current = cleanups\n        cleanups = []\n        for (let i = current.length - 1; i >= 0; i--) current[i]()\n\n        restore &&\n            styles.forEach((style, element) => {\n                releaseElement(element)\n                style === null\n                    ? element.removeAttribute(\"style\")\n                    : element.setAttribute(\"style\", style)\n            })\n        styles.clear()\n    }\n\n    const start = () => {\n        scope.state = \"active\"\n        let matches = !queries.length\n        scope.media = {}\n\n        for (const [name, query] of queries) {\n            matches = (scope.media[name] = query.matches) || matches\n        }\n\n        if (matches && setup) {\n            const cleanup = scope.run(() => setup(scope))\n            typeof cleanup === \"function\" && active.add(cleanup)\n        }\n    }\n\n    const onChange = () => {\n        if (isPending) return\n        isPending = true\n\n        /**\n         * Several conditions can change together, for instance two\n         * breakpoints crossed by one resize. Refresh once.\n         */\n        queueMicrotask(() => {\n            isPending = false\n            queries.length && scope.refresh()\n        })\n    }\n\n    const kill = (restore?: boolean) => {\n        scope.state = restore ? \"cancelled\" : \"stopped\"\n        for (const [, query] of queries) {\n            query.removeEventListener(\"change\", onChange)\n        }\n        queries.length = 0\n        clear(restore)\n    }\n\n    const runIn = <R>(target: ActiveScope | undefined, callback: () => R) => {\n        const prev = activeScope.current\n        activeScope.current = target\n        try {\n            return callback()\n        } finally {\n            activeScope.current = prev\n        }\n    }\n\n    const scope: MotionScope = {\n        state: \"active\",\n        media: {},\n        run: (callback) => runIn(active, callback),\n        ignore: (callback) => runIn(undefined, callback),\n        bind: active.bind,\n        stop: () => kill(),\n        cancel: () => kill(true),\n        refresh() {\n            clear(true)\n            start()\n        },\n    }\n\n    if (matchMedia && typeof window !== \"undefined\") {\n        const conditions =\n            typeof matchMedia === \"string\"\n                ? { matches: matchMedia }\n                : matchMedia\n\n        for (const name in conditions) {\n            const query = window.matchMedia(toMediaQuery(conditions[name]))\n            query.addEventListener(\"change\", onChange)\n            queries.push([name, query])\n        }\n    }\n\n    /**\n     * A scope created inside another is cancelled with it.\n     */\n    addToScope(scope.cancel)\n\n    start()\n\n    return scope\n}\n"],"names":[],"mappings":"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"}