Skip to content

Commit

Permalink
fix: cleanup code, fix keepAlive and extract createH to h.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
hunterliu1003 committed Jan 16, 2024
1 parent 18a7c4f commit 9c55835
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 40 deletions.
6 changes: 3 additions & 3 deletions packages/vue-final-modal/src/Modal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { App, CSSProperties, Component, ComponentInternalInstance, FunctionalComponent, Raw, Ref, VNode } from 'vue'
import type { App, CSSProperties, Component, ComponentInternalInstance, FunctionalComponent, Raw, Ref } from 'vue'
import type { ComponentProps, ComponentSlots } from './Component'
import type { H } from './h'

export type ModalId = number | string | symbol
export type StyleValue = string | CSSProperties | (string | CSSProperties)[]
Expand Down Expand Up @@ -41,8 +42,7 @@ export type Vfm = {
modals: ComponentInternalInstance[]
openedModals: ComponentInternalInstance[]
openedModalOverlays: ComponentInternalInstance[]
dynamicModals: VNode[]
modalsContainers: Ref<symbol[]>
h: H
get: (modalId: ModalId) => undefined | ComponentInternalInstance
toggle: (modalId: ModalId, show?: boolean) => undefined | Promise<string>
open: (modalId: ModalId) => undefined | Promise<string>
Expand Down
13 changes: 2 additions & 11 deletions packages/vue-final-modal/src/components/DynamicModal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Component, PropType } from 'vue'
import { defineComponent, h } from 'vue'
import type { ModalSlotOptions, UseModalOptions, UseModalOptionsPrivate } from '..'
import { destroyVNode, isModalSlotOptions, useVfm } from '~/useApi'
import { isModalSlotOptions } from '~/useApi'
import { isString, objectEntries } from '~/utils'

export const DynamicModal = defineComponent({
Expand All @@ -13,7 +13,6 @@ export const DynamicModal = defineComponent({
},
},
setup(props) {
const { dynamicModals } = useVfm()
function renderDynamicModal(modal: (UseModalOptions<Component> & UseModalOptionsPrivate)) {
if (!modal.component)
return null
Expand All @@ -39,15 +38,7 @@ export const DynamicModal = defineComponent({
if (onUpdateModelValue)
onUpdateModelValue(value)
},
'on_closed': () => {
modal?.resolveClosed?.()
if (!modal.keepAlive) {
const vNode = dynamicModals.find(component => component.key === modal.id)
if (!vNode)
return
destroyVNode(vNode)
}
},
'on_closed': () => modal?.resolveClosed?.(),
'on_opened': () => modal?.resolveOpened?.(),
}, slots)
}
Expand Down
11 changes: 5 additions & 6 deletions packages/vue-final-modal/src/components/ModalsContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ import { useVfm } from '~/useApi'
export const ModalsContainer = defineComponent({
name: 'ModalsContainer',
setup() {
const { modalsContainers, dynamicModals } = useVfm()
const { h } = useVfm()

const uid = Symbol(__DEV__ ? 'ModalsContainer' : '')
const shouldMount = computed(() => uid === modalsContainers.value?.[0])
const shouldMount = computed(() => uid === h.containers.value?.[0])

modalsContainers.value.push(uid)
h.containers.value.push(uid)
onBeforeUnmount(() => {
modalsContainers.value = modalsContainers.value.filter(i => i !== uid)
h.containers.value = h.containers.value.filter(i => i !== uid)
})

return () => {
if (!shouldMount.value)
return null

return dynamicModals
return h.vNodes
}
},
})
33 changes: 33 additions & 0 deletions packages/vue-final-modal/src/h.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Ref, VNode } from 'vue'
import { ref, shallowReactive } from 'vue'

export type H = {
vNodes: VNode[]
containers: Ref<symbol[]>
push: (vNode: VNode) => void
remove: (vNode: VNode) => void
}

export function createH(): H {
const vNodes: VNode[] = shallowReactive([])
const containers = ref<symbol[]>([])

function push(vNode: VNode) {
if (!vNodes.includes(vNode))
vNodes.push(vNode)
}

function remove(vNode: VNode): void {
const index = vNodes.indexOf(vNode)
if (index !== undefined && index !== -1)
vNodes.splice(index, 1)
}

const _h: H = {
vNodes,
containers,
push,
remove,
}
return _h
}
16 changes: 9 additions & 7 deletions packages/vue-final-modal/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { App, ComponentInternalInstance, ComputedRef, VNode } from 'vue'
import type { App, ComponentInternalInstance, ComputedRef } from 'vue'
import { getCurrentInstance, inject, markRaw, ref, shallowReactive } from 'vue'
import { vfmSymbol } from './injectionSymbols'
import type { ModalExposed, ModalId, Vfm } from './Modal'
import { noop } from './utils'
import { createH } from './h'

// eslint-disable-next-line import/no-mutable-exports
export let activeVfm: Vfm | undefined
Expand All @@ -15,8 +16,12 @@ export const defaultVfm: Vfm = {
modals: [],
openedModals: [],
openedModalOverlays: [],
dynamicModals: [],
modalsContainers: ref([]),
h: {
vNodes: [],
containers: ref([]),
push: noop,
remove: noop,
},
get: () => undefined,
toggle: () => undefined,
open: () => undefined,
Expand All @@ -31,8 +36,6 @@ export function createVfm() {
const modals: ComponentInternalInstance[] = shallowReactive([])
const openedModals: ComponentInternalInstance[] = shallowReactive([])
const openedModalOverlays: ComponentInternalInstance[] = shallowReactive([])
const dynamicModals: VNode[] = shallowReactive([])
const modalsContainers = ref<symbol[]>([])

const vfm: Vfm = markRaw({
install(app: App) {
Expand All @@ -42,8 +45,7 @@ export function createVfm() {
modals,
openedModals,
openedModalOverlays,
dynamicModals,
modalsContainers,
h: createH(),
get(modalId: ModalId) {
return modals.find(modal => getModalExposed(modal)?.value.modalId?.value === modalId)
},
Expand Down
30 changes: 17 additions & 13 deletions packages/vue-final-modal/src/useApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,15 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U
id,
modelValue: !!_options?.defaultModelValue,
resolveOpened: () => { },
resolveClosed: () => { },
resolveClosed: tryRemoveVNode,
attrs: {},
...withMarkRaw<T>(_options),
}) as UseModalOptions<T> & UseModalOptionsPrivate

const vNode = h(DynamicModal, { modal: options, key: id })

tryOnUnmounted(() => {
if (options?.keepAlive)
return
destroyVNode(vNode)
tryRemoveVNode()
})

if (options.modelValue === true)
Expand All @@ -82,7 +80,7 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U
if (options.modelValue)
return Promise.resolve('[Vue Final Modal] modal is already opened.')

destroyVNode(vNode)
tryRemoveVNode()
options.modelValue = true
pushVNode(vNode)

Expand All @@ -97,10 +95,19 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U

options.modelValue = false
return new Promise((resolve) => {
options.resolveClosed = () => resolve('closed')
options.resolveClosed = () => {
resolve('closed')
tryRemoveVNode()
}
})
}

function tryRemoveVNode() {
if (options.keepAlive)
return
removeVNode(vNode)
}

function patchOptions(_options: Partial<UseModalOptions<T>>) {
const { slots, ...rest } = withMarkRaw(_options, options.component)

Expand Down Expand Up @@ -131,7 +138,7 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U
open,
close,
patchOptions,
destroy: () => destroyVNode(vNode),
destroy: () => removeVNode(vNode),
}
}

Expand All @@ -156,7 +163,7 @@ function patchAttrs<T extends Record<string, any>>(attrs: T, newAttrs: Partial<T

async function pushVNode(vNode: VNode) {
const vfm = await useSsrVfm()
vfm?.dynamicModals.push(vNode)
vfm.h.push(vNode)
}

/** nextTick will break the SSR, so use `activeVfm` first and then `useVfm()` */
Expand All @@ -170,12 +177,9 @@ async function useSsrVfm(): Promise<Vfm> {
}
}

export function destroyVNode(vNode: VNode): void {
function removeVNode(vNode: VNode): void {
const vfm = useVfm()

const index = vfm?.dynamicModals.indexOf(vNode)
if (index !== undefined && index !== -1)
vfm?.dynamicModals.splice(index, 1)
vfm.h.remove(vNode)
}

export function useModalSlot<T extends Component>(options: {
Expand Down

0 comments on commit 9c55835

Please sign in to comment.