mirror of https://github.com/nocodb/nocodb
braks
2 years ago
2 changed files with 68 additions and 0 deletions
@ -0,0 +1,67 @@ |
|||||||
|
import { render } from '@vue/runtime-dom' |
||||||
|
import type { ComponentPublicInstance } from '@vue/runtime-core' |
||||||
|
import { createEventHook, h, 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. |
||||||
|
*/ |
||||||
|
export function useDialog( |
||||||
|
component: any, |
||||||
|
props: NonNullable<Parameters<typeof h>[1]> = {}, |
||||||
|
mountTarget?: Element | ComponentPublicInstance, |
||||||
|
) { |
||||||
|
const closeHook = createEventHook<void>() |
||||||
|
const mountedHook = createEventHook<void>() |
||||||
|
|
||||||
|
const isMounted = $ref(false) |
||||||
|
|
||||||
|
const domNode = document.createElement('div') |
||||||
|
|
||||||
|
/** if specified, append vnode to mount target instead of document.body */ |
||||||
|
if (mountTarget) { |
||||||
|
if ('$el' in mountTarget) { |
||||||
|
mountTarget.$el.appendChild(domNode) |
||||||
|
} else { |
||||||
|
mountTarget.appendChild(domNode) |
||||||
|
} |
||||||
|
} else { |
||||||
|
document.body.appendChild(domNode) |
||||||
|
} |
||||||
|
|
||||||
|
/** When props change, we want to re-render the element with the new prop values */ |
||||||
|
watch( |
||||||
|
toReactive(props), |
||||||
|
(reactiveProps) => { |
||||||
|
const vNode = h(component, reactiveProps) |
||||||
|
|
||||||
|
vNode.appContext = useNuxtApp().vueApp._context |
||||||
|
|
||||||
|
render(vNode, domNode) |
||||||
|
|
||||||
|
if (!isMounted) mountedHook.trigger() |
||||||
|
}, |
||||||
|
{ deep: true, immediate: true }, |
||||||
|
) |
||||||
|
|
||||||
|
/** When calling scope is disposed, destroy component */ |
||||||
|
tryOnScopeDispose(close) |
||||||
|
|
||||||
|
/** destroy component, can be debounced */ |
||||||
|
function close(debounce = 0) { |
||||||
|
setTimeout(() => { |
||||||
|
render(null, domNode) |
||||||
|
|
||||||
|
setTimeout(() => { |
||||||
|
document.body.removeChild(domNode) |
||||||
|
}, 100) |
||||||
|
|
||||||
|
closeHook.trigger() |
||||||
|
}, debounce) |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
close, |
||||||
|
onClose: closeHook.on, |
||||||
|
onMounted: mountedHook.on, |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue