diff --git a/packages/vue-final-modal/src/components/DynamicModal.ts b/packages/vue-final-modal/src/components/UseModal.ts similarity index 80% rename from packages/vue-final-modal/src/components/DynamicModal.ts rename to packages/vue-final-modal/src/components/UseModal.ts index 7626d2ce..73bc7d59 100644 --- a/packages/vue-final-modal/src/components/DynamicModal.ts +++ b/packages/vue-final-modal/src/components/UseModal.ts @@ -1,10 +1,10 @@ import type { Component, PropType } from 'vue' -import { defineComponent, h } from 'vue' +import { defineComponent } from 'vue' import type { UseModalOptions, UseModalOptionsPrivate } from '..' -import { getSlots } from '~/useVNode' +import { createVNode } from '~/useVNode' -export const DynamicModal = defineComponent({ - name: 'DynamicModal', +export const UseModal = defineComponent({ + name: 'UseModal', props: { modal: { type: Object as PropType & UseModalOptionsPrivate>, @@ -15,10 +15,9 @@ export const DynamicModal = defineComponent({ function renderDynamicModal(modal: (UseModalOptions & UseModalOptionsPrivate)) { if (!modal.component) return null - - return h( - modal.component, - { + return createVNode({ + component: modal.component, + attrs: { 'modelValue': modal.modelValue, 'displayDirective': modal?.keepAlive ? 'show' : undefined, ...(typeof modal.attrs === 'object' ? modal.attrs : {}), @@ -31,8 +30,8 @@ export const DynamicModal = defineComponent({ 'on_closed': () => modal?.resolveClosed?.(), 'on_opened': () => modal?.resolveOpened?.(), }, - getSlots(modal.slots || {}), - ) + slots: modal.slots, + }) } return () => renderDynamicModal(props.modal) diff --git a/packages/vue-final-modal/src/useModal.ts b/packages/vue-final-modal/src/useModal.ts index b7f707b3..0e48e150 100644 --- a/packages/vue-final-modal/src/useModal.ts +++ b/packages/vue-final-modal/src/useModal.ts @@ -1,7 +1,7 @@ import type { Component } from 'vue' -import { h, markRaw, reactive } from 'vue' +import { markRaw, reactive } from 'vue' import { isString, objectEntries } from './utils' -import { DynamicModal } from './components/DynamicModal' +import { UseModal } from './components/UseModal' import { isVNodeOptions, useVNode } from './useVNode' import type { CreateVNodeOptions, UseModalOptions, UseModalOptionsPrivate, UseModalReturnType } from '.' import { VueFinalModal } from '.' @@ -21,10 +21,11 @@ export function useModal(_options: U ...withMarkRaw(_options), }) as UseModalOptions & UseModalOptionsPrivate - const vNode = h(DynamicModal, { modal: options, key: id }) - - const { show, hide } = useVNode(vNode, { - tryOnUnmounted: () => tryRemoveVNode(), + const { show, hide } = useVNode({ + component: UseModal, + attrs: { modal: options, key: id }, + }, { + onUnmounted: () => tryRemoveVNode(), }) if (options.modelValue === true) diff --git a/packages/vue-final-modal/src/useVNode.ts b/packages/vue-final-modal/src/useVNode.ts index aba1d6c3..facbff01 100644 --- a/packages/vue-final-modal/src/useVNode.ts +++ b/packages/vue-final-modal/src/useVNode.ts @@ -1,5 +1,5 @@ import type { Component, VNode } from 'vue' -import { h as _h, isVNode } from 'vue' +import { h as _h } from 'vue' import { tryOnUnmounted } from '@vueuse/core' import type { CreateVNodeOptions } from './Modal' import { useSsrVfm, useVfm } from './useVfm' @@ -7,38 +7,47 @@ import type { ComponentSlots } from './Component' import { isString, objectEntries } from './utils' /** - * Create a dynamic vNode. + * Create a vNode by passing `CreateVNodeOptions` options. */ export function createVNode(options: CreateVNodeOptions) { - const id = Symbol(__DEV__ ? 'createVNode' : '') - const vNode = _h(options.component, { key: id, ...options.attrs }, getSlots(options.slots)) - return vNode + return _h(options.component, options.attrs, getSlots(options.slots)) } /** - * Create a dynamic vNode. + * A type helper for `CreateVNodeOptions` */ export function h(options: CreateVNodeOptions) { return options } -async function pushVNode(vNode: VNode) { - const vfm = await useSsrVfm() - vfm.vNodesContainer.push(vNode) -} +export function useVNode(vNodeOptions: CreateVNodeOptions, options?: { + onUnmounted?: (vNode: VNode) => void +}) { + if (vNodeOptions.attrs) { + const id = Symbol(__DEV__ ? 'createVNode' : '') + Object.assign(vNodeOptions.attrs, { key: id }) + } + const vNode = createVNode(vNodeOptions) + tryOnUnmounted(() => { + if (options?.onUnmounted) + options?.onUnmounted(vNode) + else + hide() + }) -async function removeVNode(vNode: VNode) { - const vfm = useVfm() - vfm.vNodesContainer.remove(vNode) -} + async function show() { + const vfm = await useSsrVfm() + vfm.vNodesContainer.push(vNode) + } + + async function hide() { + const vfm = useVfm() + vfm.vNodesContainer.remove(vNode) + } -export function useVNode(vNode: VNode, options?: { - tryOnUnmounted?: (vNode: VNode) => void -}) { - tryOnUnmounted(() => options?.tryOnUnmounted?.(vNode)) return { - show: () => pushVNode(vNode), - hide: () => removeVNode(vNode), + show, + hide, } } @@ -49,7 +58,7 @@ export function isVNodeOptions(value: unknown): value is Cr return false } -export function getSlots(slots?: { +function getSlots(slots?: { [K in keyof ComponentSlots]?: string | Component | CreateVNodeOptions }) { return objectEntries(slots || {}).reduce VNode>>((acc, cur) => { @@ -59,9 +68,6 @@ export function getSlots(slots?: { acc[slotName] = () => _h('div', { innerHTML: slot }) else if (isVNodeOptions(slot)) acc[slotName] = () => _h(slot.component, slot.attrs, slot.slots ? getSlots(slot.slots) : undefined) - else if (isVNode(slot)) - // acc[slotName] = () => slot - return acc else acc[slotName] = () => _h(slot) return acc diff --git a/viteplay/src/components/VueFinalModal/Basic.example.vue b/viteplay/src/components/VueFinalModal/Basic.example.vue index a83da37d..9b09a641 100644 --- a/viteplay/src/components/VueFinalModal/Basic.example.vue +++ b/viteplay/src/components/VueFinalModal/Basic.example.vue @@ -1,6 +1,6 @@