{"version":3,"file":"useProgrammatic-B50-6K60.mjs","sources":["../../src/components/programmatic/InstanceRegistry.ts","../../src/components/programmatic/ProgrammaticComponent.ts","../../src/components/programmatic/useProgrammatic.ts"],"sourcesContent":["import type { ComponentInternalInstance } from \"vue\";\n\nexport default class InstanceRegistry<T = ComponentInternalInstance> {\n    entries: Array<T>;\n\n    constructor() {\n        this.entries = [];\n    }\n\n    /** Returns the number of registered active instances. */\n    count(): number {\n        return this.entries.length;\n    }\n\n    /** Returns the first registered active instance. */\n    fist(): T | undefined {\n        return this.entries.at(0);\n    }\n\n    /** Returns the last registered active instance. */\n    last(): T | undefined {\n        return this.entries.at(-1);\n    }\n\n    /** Adds a new instance to the instance stack. */\n    add(entry: T): void {\n        this.entries.push(entry);\n    }\n\n    /** Removes an instance from the instance stack. */\n    remove(entry: T): void {\n        const index = this.entries.indexOf(entry);\n        this.entries.splice(index, 1);\n    }\n\n    /** Call a function for every registered active instance. */\n    walk(callback: (value: T) => boolean | void): void {\n        // Walk a copy of the array so that the callback is allowed to remove the instance\n        this.entries = [...this.entries].filter((e) => {\n            const ret = callback(e);\n            return !(ret === true);\n        });\n    }\n}\n","import {\n    createVNode,\n    defineComponent,\n    getCurrentInstance,\n    onMounted,\n    onUnmounted,\n    type ComponentInternalInstance,\n    type VNode,\n    type VNodeTypes,\n} from \"vue\";\nimport type { ComponentProps } from \"vue-component-type-helpers\";\nimport type InstanceRegistry from \"@/components/programmatic/InstanceRegistry\";\nimport { isClient } from \"@/utils/ssr\";\n\nexport type ProgrammaticComponentProps<C extends VNodeTypes> = {\n    /**\n     * Component to be injected.\n     * Terminate the component by emitting a 'close' event — emits('close')\n     */\n    component: C;\n    /**\n     * Props to be binded to the injected component.\n     * Both attributes and properties can be used in props.\n     * Vue automatically picks the right way to assign it.\n     * `class` and `style` have the same object / array value support like in templates.\n     * Event listeners should be passed as onXxx.\n     * @see https://vuejs.org/api/render-function.html#h\n     */\n    props?: ComponentProps<C> | { container?: HTMLElement };\n    /** Programmatic component registry instance */\n    registry?: InstanceRegistry<ComponentInternalInstance>;\n};\n\nexport type CloseEventArgs<T extends VNodeTypes> =\n    Parameters<ComponentProps<T>[\"onClose\"]> extends never\n        ? unknown[]\n        : Parameters<ComponentProps<T>[\"onClose\"]>;\n\nexport type ProgrammaticComponentEmits<C extends VNodeTypes> = {\n    /**\n     * On component close event.\n     * This get called when the component emits `close` or the exposed `close` function get called.\n     */\n    close?: (...args: CloseEventArgs<C>) => void;\n    /** On component destroy event which get called when the component should be destroyed. */\n    destroy?: () => void;\n};\n\n// there is a bug with functional defineComponent and extracting the exposed type\n// export type ProgrammaticComponentExpose = ComponentExposed<\n//     typeof ProgrammaticComponent\n// >;\n\nexport type ProgrammaticComponentExpose<C extends VNodeTypes> = {\n    /** Call the close event of the component. */\n    close: (...args: CloseEventArgs<C>) => void;\n    /** Promise which get resolved on the close event. */\n    promise: Promise<CloseEventArgs<C>>;\n};\n\nexport const ProgrammaticComponent = defineComponent<\n    ProgrammaticComponentProps<VNodeTypes>,\n    ProgrammaticComponentEmits<VNodeTypes>\n>(\n    <C extends VNodeTypes>(\n        props: ProgrammaticComponentProps<C>,\n        { expose, emit, slots },\n    ) => {\n        // getting a hold of the internal instance in setup()\n        const vm = getCurrentInstance();\n        if (!vm)\n            throw new Error(\"ProgrammaticComponent initialisation failed.\");\n\n        // create response promise\n        let resolve: (args: CloseEventArgs<C>) => void;\n        const promise = new Promise<CloseEventArgs<C>>((p1) => (resolve = p1));\n\n        // add component instance to instance register\n        onMounted(() => props.registry?.add(vm));\n\n        // remove component instance from instance register\n        onUnmounted(() => props.registry?.remove(vm));\n\n        function close(...args: CloseEventArgs<C>): void {\n            // emit `onClose` event\n            emit(\"close\", ...args);\n\n            // call promise resolve\n            resolve(args);\n\n            // emit `destory` event after animation is finished\n            setTimeout(() => {\n                if (isClient)\n                    window.requestAnimationFrame(() => emit(\"destroy\"));\n                else emit(\"destroy\");\n            });\n        }\n\n        /** expose public functionalities for programmatic usage */\n        expose({ close, promise } satisfies ProgrammaticComponentExpose<C>);\n\n        // return render function which renders given component\n        return (): VNode =>\n            createVNode(\n                props.component,\n                { ...props.props, onClose: close },\n                slots[\"default\"],\n            );\n    },\n    {\n        name: \"ProgrammaticApp\",\n        // manual runtime props declaration is currently still needed.\n        props: [\"component\", \"props\", \"registry\"],\n        // manual runtime emits declaration\n        emits: [\"close\", \"destroy\"],\n        // manual runtime slot declaration\n        slots: [\"default\"],\n    },\n);\n","import {\n    createApp,\n    toValue,\n    type App,\n    type ComponentInternalInstance,\n    type EmitsToProps,\n    type MaybeRefOrGetter,\n    type VNode,\n    type VNodeTypes,\n} from \"vue\";\n\nimport InstanceRegistry from \"@/components/programmatic/InstanceRegistry\";\nimport { VueInstance } from \"@/utils/plugins\";\nimport { useTeleportDefault, resolveElement } from \"@/composables\";\n\nimport {\n    ProgrammaticComponent,\n    type ProgrammaticComponentProps,\n    type ProgrammaticComponentEmits,\n    type ProgrammaticComponentExpose,\n} from \"./ProgrammaticComponent\";\n\ndeclare module \"../../index\" {\n    interface OrugaProgrammatic {\n        programmatic: typeof ComponentProgrammatic;\n    }\n}\n\n/** programmatic global instance registry if no custom is defined */\nconst registry = new InstanceRegistry<ComponentInternalInstance>();\n\n/** useProgrammatic composable `open` function options */\nexport type ProgrammaticOptions<C extends VNodeTypes> = {\n    /**\n     * Specify a target the component get rendered into.\n     * @default `document.body`\n     */\n    target?: MaybeRefOrGetter<string | HTMLElement | null>;\n    /**\n     * Specify the template `id` for the programmatic container element.\n     * @default `programmatic-app`\n     */\n    appId?: string;\n} & Omit<ProgrammaticComponentProps<C>, \"component\"> & // component props\n    EmitsToProps<Omit<ProgrammaticComponentEmits<C>, \"destroy\">>; // component emit props\n\n/** public options interface for programmatically called components */\nexport type ProgrammaticComponentOptions<C extends VNodeTypes> = EmitsToProps<\n    Pick<ProgrammaticComponentEmits<C>, \"close\">\n> &\n    // make the type extendable\n    Record<string, any>;\n\n/** useProgrammatic composable `open` function return value */\nexport type ProgrammaticExpose<C extends VNodeTypes = VNode> =\n    ProgrammaticComponentExpose<C>;\n\nexport const ComponentProgrammatic = {\n    /** Returns the number of registered active instances. */\n    count: registry.count,\n    /**\n     * Create a new programmatic component instance.\n     * @param component component to render\n     * @param options render options\n     */\n    open<C extends VNodeTypes>(\n        component: C,\n        options?: ProgrammaticOptions<C>,\n    ): ProgrammaticExpose<C> {\n        options = { registry, ...options };\n\n        const targetQuery = toValue(options.target);\n        // define the target container\n        const target: HTMLElement | null =\n            // either by a given query selector / element\n            (targetQuery && resolveElement(targetQuery)) ||\n            // or by the default teleport target config\n            resolveElement(useTeleportDefault());\n        if (!target)\n            throw new Error(\"ComponentProgrammatic - no target is defined.\");\n\n        // create app container\n        let container: HTMLDivElement | undefined =\n            document.createElement(\"div\");\n        container.id = options.appId || \"programmatic-app\";\n\n        // place the app container into the target element\n        target.appendChild(container);\n\n        // clear instance handler\n        function onDestroy(): void {\n            // destroy app/component\n            if (app) {\n                app.unmount();\n                app = undefined;\n            }\n            // clear container\n            if (container && target) {\n                target.removeChild(container);\n                container = undefined;\n            }\n        }\n\n        // create a new vue app instance with the ProgrammaticComponent as root\n        let app: App | undefined = createApp(ProgrammaticComponent, {\n            registry: options.registry, // programmatic registry instance - can be overriden by given in options\n            component, // the component which should be rendered\n            props: { ...options.props, container: target }, // component props including the target as `container`\n            onClose: options.onClose, // custom onClose handler\n            onDestroy, // node destory cleanup handler\n        });\n\n        // share the current context to the new app instance if running inside a nother app\n        if (VueInstance)\n            app._context = Object.assign(app._context, VueInstance._context);\n\n        // render the new vue instance into the container\n        const instance = app.mount(container);\n\n        // return exposed programmatic functionalities from the mounted component instance\n        return instance as unknown as ProgrammaticExpose<C>;\n    },\n    /** close the last registred instance in the global programmatic instance registry */\n    close(...args: unknown[]): void {\n        registry.last()?.exposed?.close(...args);\n    },\n    /** close all instances in the global programmatic instance registry */\n    closeAll(...args: unknown[]): void {\n        registry.walk((entry) => entry.exposed?.close(...args));\n    },\n};\n\nexport default ComponentProgrammatic;\n"],"names":[],"mappings":"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"}