|
|
|
@ -1,16 +1,49 @@
|
|
|
|
|
import type { VNode } from '@vue/runtime-dom' |
|
|
|
|
import { render } from '@vue/runtime-dom' |
|
|
|
|
import type { DefineComponent, VNode } from '@vue/runtime-dom' |
|
|
|
|
import { isVNode, render } from '@vue/runtime-dom' |
|
|
|
|
import type { ComponentPublicInstance } from '@vue/runtime-core' |
|
|
|
|
import { isClient } from '@vueuse/core' |
|
|
|
|
import { createEventHook, h, ref, toReactive, tryOnScopeDispose, useNuxtApp, watch } from '#imports' |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Programmatically create a component and attach it to the body (or a specific mount target), like a dialog or modal. |
|
|
|
|
* This composable is not SSR friendly - it should be used only on the client. |
|
|
|
|
* |
|
|
|
|
* @param componentOrVNode The component to create and attach. Can be a VNode or a component definition. |
|
|
|
|
* @param props The props to pass to the component. |
|
|
|
|
* @param mountTarget The target to attach the component to. Defaults to the document body |
|
|
|
|
* |
|
|
|
|
* @example |
|
|
|
|
* import { useDialog } from '#imports' |
|
|
|
|
* import DlgQuickImport from '~/components/dlg/QuickImport.vue' |
|
|
|
|
* |
|
|
|
|
* function openQuickImportDialog(type: string) { |
|
|
|
|
* // create a ref for showing/hiding the modal
|
|
|
|
|
* const isOpen = ref(true) |
|
|
|
|
* |
|
|
|
|
* const { close, vNode } = useDialog(DlgQuickImport, { |
|
|
|
|
* 'modelValue': isOpen, |
|
|
|
|
* 'importType': type, |
|
|
|
|
* 'onUpdate:modelValue': closeDialog, |
|
|
|
|
* }) |
|
|
|
|
* |
|
|
|
|
* function closeDialog() { |
|
|
|
|
* // hide the modal
|
|
|
|
|
* isOpen.value = false |
|
|
|
|
* |
|
|
|
|
* // debounce destroying the component, so the modal transition can finish
|
|
|
|
|
* close(1000) |
|
|
|
|
* } |
|
|
|
|
* } |
|
|
|
|
*/ |
|
|
|
|
export function useDialog( |
|
|
|
|
component: any, |
|
|
|
|
componentOrVNode: DefineComponent<any, any, any> | VNode, |
|
|
|
|
props: NonNullable<Parameters<typeof h>[1]> = {}, |
|
|
|
|
mountTarget?: Element | ComponentPublicInstance, |
|
|
|
|
) { |
|
|
|
|
if (typeof document === 'undefined' || !isClient) { |
|
|
|
|
console.warn('[useDialog]: Cannot use outside of browser!') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const closeHook = createEventHook<void>() |
|
|
|
|
const mountedHook = createEventHook<void>() |
|
|
|
|
|
|
|
|
@ -29,7 +62,7 @@ export function useDialog(
|
|
|
|
|
const stop = watch( |
|
|
|
|
toReactive(props), |
|
|
|
|
(reactiveProps) => { |
|
|
|
|
const vNode = h(component, reactiveProps) |
|
|
|
|
const vNode = isVNode(componentOrVNode) ? componentOrVNode : h(componentOrVNode, reactiveProps) |
|
|
|
|
|
|
|
|
|
vNode.appContext = useNuxtApp().vueApp._context |
|
|
|
|
|
|
|
|
|