Skip to content

Commit

Permalink
refactor: refine useModal, useVNode, rename DynamicModal to UseModal
Browse files Browse the repository at this point in the history
  • Loading branch information
hunterliu1003 committed Jan 29, 2024
1 parent 449764b commit 5081259
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -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<UseModalOptions<Component> & UseModalOptionsPrivate>,
Expand All @@ -15,10 +15,9 @@ export const DynamicModal = defineComponent({
function renderDynamicModal(modal: (UseModalOptions<Component> & 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 : {}),
Expand All @@ -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)
Expand Down
13 changes: 7 additions & 6 deletions packages/vue-final-modal/src/useModal.ts
Original file line number Diff line number Diff line change
@@ -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 '.'
Expand All @@ -21,10 +21,11 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U
...withMarkRaw<T>(_options),
}) as UseModalOptions<T> & 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)
Expand Down
54 changes: 30 additions & 24 deletions packages/vue-final-modal/src/useVNode.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
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'
import type { ComponentSlots } from './Component'
import { isString, objectEntries } from './utils'

/**
* Create a dynamic vNode.
* Create a vNode by passing `CreateVNodeOptions<T>` options.
*/
export function createVNode<T extends Component>(options: CreateVNodeOptions<T>) {
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<T>`
*/
export function h<T extends Component>(options: CreateVNodeOptions<T>) {
return options
}

async function pushVNode(vNode: VNode) {
const vfm = await useSsrVfm()
vfm.vNodesContainer.push(vNode)
}
export function useVNode<T extends Component>(vNodeOptions: CreateVNodeOptions<T>, 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,
}
}

Expand All @@ -49,7 +58,7 @@ export function isVNodeOptions<T extends Component>(value: unknown): value is Cr
return false
}

export function getSlots<T extends Component>(slots?: {
function getSlots<T extends Component>(slots?: {
[K in keyof ComponentSlots<T>]?: string | Component | CreateVNodeOptions<Component>
}) {
return objectEntries(slots || {}).reduce<Record<string, () => VNode>>((acc, cur) => {
Expand All @@ -59,9 +68,6 @@ export function getSlots<T extends Component>(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
Expand Down
6 changes: 3 additions & 3 deletions viteplay/src/components/VueFinalModal/Basic.example.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ModalsContainer, VueFinalModal, createVNode, h, useModal, useVNode, useVfm } from 'vue-final-modal'
import { ModalsContainer, VueFinalModal, h, useModal, useVNode, useVfm } from 'vue-final-modal'
import DefaultSlot from '../DefaultSlot.vue'
import { modal } from './modalsHelpers'
import TestModal from './TestModal.vue'
Expand Down Expand Up @@ -80,7 +80,7 @@ function clickOutside() {
// show.value = true
// })
const { show: _show } = useVNode(createVNode({
const { show: _show } = useVNode({
component: DefaultSlot,
attrs: {
text: 'createVNode',
Expand Down Expand Up @@ -109,7 +109,7 @@ const { show: _show } = useVNode(createVNode({
// },
// }),
// },
}))
})
_show()
</script>
Expand Down

0 comments on commit 5081259

Please sign in to comment.