Skip to content

Commit

Permalink
refactor: rename useC2v to useVNode
Browse files Browse the repository at this point in the history
  • Loading branch information
hunterliu1003 committed Jan 29, 2024
1 parent a79cd54 commit ee11efe
Show file tree
Hide file tree
Showing 14 changed files with 128 additions and 133 deletions.
8 changes: 4 additions & 4 deletions docs/content/2.get-started/1.guide/4.types.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ The exported types in VueFinalModal.
export type ModalId = number | string | symbol
```
## C2VOptions
## CreateVNodeOptions
```ts
export type C2VOptions<T extends Component> = {
export type CreateVNodeOptions<T extends Component> = {
component: T
attrs?: ComponentProps<T>
slots?: {
[K in keyof ComponentSlots<T>]?: string | Component | C2VOptions<Component>
[K in keyof ComponentSlots<T>]?: string | Component | CreateVNodeOptions<Component>
}
}
```
Expand All @@ -29,7 +29,7 @@ export type UseModalOptions<T extends Component> = {
component?: T
attrs?: ComponentProps<T>
slots?: {
[K in keyof ComponentSlots<T>]?: string | Component | C2VOptions<Component>
[K in keyof ComponentSlots<T>]?: string | Component | CreateVNodeOptions<Component>
}
}
```
Expand Down
6 changes: 3 additions & 3 deletions docs/content/3.api/2.composables/1.use-modal.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,15 @@ const modalInstance = useModal({
#### with `Component`, `Props` and `Events`

```ts
import { VueFinalModal, useModal, c2v } from 'vue-final-modal'
import { VueFinalModal, useModal, h } from 'vue-final-modal'
// ModalContent is the component you want to put into the modal content
import ModalContent from './ModalContent.vue'

const modalInstance = useModal({
component: VueFinalModal,
attrs: { ... },
slots: {
default: c2v({
default: h({
component: ModalContent,
attrs: {
// Bind ModalContent props
Expand All @@ -137,7 +137,7 @@ const modalInstance = useModal({
```

::alert{type=info}
`c2v()` is a function that provides better DX for type checking. It just returns the same object you passed in.
`h()` is a function that provides better DX for type checking. It just returns the same object you passed in.
::

## Type Declarations
Expand Down
6 changes: 3 additions & 3 deletions packages/vue-final-modal/src/Modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import type { VNodesContainer } from './useVNodesContainer'
export type ModalId = number | string | symbol
export type StyleValue = string | CSSProperties | (string | CSSProperties)[]

export type C2VOptions<T extends Component> = {
export type CreateVNodeOptions<T extends Component> = {
component: T
attrs?: ComponentProps<T>
slots?: {
[K in keyof ComponentSlots<T>]?: string | Component | C2VOptions<Component>
[K in keyof ComponentSlots<T>]?: string | Component | CreateVNodeOptions<Component>
}
}

Expand All @@ -19,7 +19,7 @@ export type UseModalOptions<T extends Component> = {
component?: T
attrs?: ComponentProps<T>
slots?: {
[K in keyof ComponentSlots<T>]?: string | Component | C2VOptions<Component>
[K in keyof ComponentSlots<T>]?: string | Component | CreateVNodeOptions<Component>
}
}

Expand Down
44 changes: 18 additions & 26 deletions packages/vue-final-modal/src/components/DynamicModal.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { Component, PropType } from 'vue'
import { defineComponent, h } from 'vue'
import type { C2VOptions, UseModalOptions, UseModalOptionsPrivate } from '..'
import { isString, objectEntries } from '~/utils'
import { getSlots, isC2VOptions } from '~/useC2v'
import type { UseModalOptions, UseModalOptionsPrivate } from '..'
import { getSlots } from '~/useVNode'

export const DynamicModal = defineComponent({
name: 'DynamicModal',
Expand All @@ -16,31 +15,24 @@ export const DynamicModal = defineComponent({
function renderDynamicModal(modal: (UseModalOptions<Component> & UseModalOptionsPrivate)) {
if (!modal.component)
return null
const slots = objectEntries(modal.slots || {}).reduce((acc, cur) => {
const slotName = cur[0] as string
const slot = cur[1] as string | Component | C2VOptions<Component>
if (isString(slot))
acc[slotName] = () => h('div', { innerHTML: slot })
else if (isC2VOptions(slot))
acc[slotName] = () => h(slot.component, slot.attrs, slot.slots ? getSlots(slot.slots) : undefined)
else
acc[slotName] = () => h(slot)
return acc
}, {} as any)

return h(modal.component, {
'modelValue': modal.modelValue,
'displayDirective': modal?.keepAlive ? 'show' : undefined,
...(typeof modal.attrs === 'object' ? modal.attrs : {}),
'onUpdate:modelValue': (value: boolean) => {
modal.modelValue = value
const onUpdateModelValue = modal.attrs?.['onUpdate:modelValue']
if (onUpdateModelValue)
onUpdateModelValue(value)
return h(
modal.component,
{
'modelValue': modal.modelValue,
'displayDirective': modal?.keepAlive ? 'show' : undefined,
...(typeof modal.attrs === 'object' ? modal.attrs : {}),
'onUpdate:modelValue': (value: boolean) => {
modal.modelValue = value
const onUpdateModelValue = modal.attrs?.['onUpdate:modelValue']
if (onUpdateModelValue)
onUpdateModelValue(value)
},
'on_closed': () => modal?.resolveClosed?.(),
'on_opened': () => modal?.resolveOpened?.(),
},
'on_closed': () => modal?.resolveClosed?.(),
'on_opened': () => modal?.resolveOpened?.(),
}, slots)
getSlots(modal.slots || {}),
)
}

return () => renderDynamicModal(props.modal)
Expand Down
2 changes: 1 addition & 1 deletion packages/vue-final-modal/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export { vueFinalModalProps } from './components/VueFinalModal/VueFinalModalProp
export type { VueFinalModalEmits } from './components/VueFinalModal/VueFinalModal.vue'

/** Composables */
export { useC2v, c2v } from './useC2v'
export { createVNode, useVNode, h } from './useVNode'
export { useVfm } from './useVfm'
export { useModal } from './useModal'
export { useVfmAttrs } from './useVfmAttrs'
Expand Down
53 changes: 0 additions & 53 deletions packages/vue-final-modal/src/useC2v.ts

This file was deleted.

26 changes: 12 additions & 14 deletions packages/vue-final-modal/src/useModal.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import type { Component } from 'vue'
import { h, markRaw, reactive } from 'vue'
import { tryOnUnmounted } from '@vueuse/core'
import { isString, objectEntries } from './utils'
import { DynamicModal } from './components/DynamicModal'
import { isC2VOptions } from './useC2v'
import { pushVNode, removeVNode } from './useVfm'
import type { C2VOptions, UseModalOptions, UseModalOptionsPrivate, UseModalReturnType } from '.'
import { isVNodeOptions, useVNode } from './useVNode'
import type { CreateVNodeOptions, UseModalOptions, UseModalOptionsPrivate, UseModalReturnType } from '.'
import { VueFinalModal } from '.'

/**
Expand All @@ -25,20 +23,20 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U

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

tryOnUnmounted(() => {
tryRemoveVNode()
const { show, hide } = useVNode(vNode, {
tryOnUnmounted: () => tryRemoveVNode(),
})

if (options.modelValue === true)
pushVNode(vNode)
show()

function open(): Promise<string> {
if (options.modelValue)
return Promise.resolve('[Vue Final Modal] modal is already opened.')

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

return new Promise((resolve) => {
options.resolveOpened = () => resolve('opened')
Expand All @@ -61,7 +59,7 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U
function tryRemoveVNode() {
if (options.keepAlive)
return
removeVNode(vNode)
hide()
}

function patchOptions(_options: Partial<UseModalOptions<T>>) {
Expand All @@ -81,7 +79,7 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U
const originSlot = options.slots![name]
if (isString(originSlot))
options.slots![name] = slot
else if (isC2VOptions(originSlot) && isC2VOptions(slot))
else if (isVNodeOptions(originSlot) && isVNodeOptions(slot))
patchComponentOptions(originSlot, slot)
else
options.slots![name] = slot
Expand All @@ -94,7 +92,7 @@ export function useModal<T extends Component = typeof VueFinalModal>(_options: U
open,
close,
patchOptions,
destroy: () => removeVNode(vNode),
destroy: () => hide(),
}
}

Expand All @@ -107,7 +105,7 @@ function withMarkRaw<T extends Component>(options: Partial<UseModalOptions<T>>,
if (isString(maybeComponent))
return [name, maybeComponent] as const

if (isC2VOptions(maybeComponent)) {
if (isVNodeOptions(maybeComponent)) {
return [name, {
...maybeComponent,
component: markRaw(maybeComponent.component),
Expand All @@ -125,8 +123,8 @@ function withMarkRaw<T extends Component>(options: Partial<UseModalOptions<T>>,
}

function patchComponentOptions<T extends Component>(
options: UseModalOptions<T> | C2VOptions<Component>,
newOptions: Partial<UseModalOptions<T>> | C2VOptions<Component>,
options: UseModalOptions<T> | CreateVNodeOptions<Component>,
newOptions: Partial<UseModalOptions<T>> | CreateVNodeOptions<Component>,
) {
if (newOptions.component)
options.component = newOptions.component
Expand Down
69 changes: 69 additions & 0 deletions packages/vue-final-modal/src/useVNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { Component, VNode } from 'vue'
import { h as _h, isVNode } 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.
*/
export function createVNode<T extends Component>(options: CreateVNodeOptions<T>) {
const id = Symbol(__DEV__ ? 'createVNode' : '')
const vNode = _h(options.component, { key: id, ...options.attrs }, options.slots)
return vNode
}

/**
* Create a dynamic vNode.
*/
export function h<T extends Component>(options: CreateVNodeOptions<T>) {
return options
}

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

async function removeVNode(vNode: VNode) {
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),
}
}

export function isVNodeOptions<T extends Component>(value: unknown): value is CreateVNodeOptions<T> {
if (typeof value === 'object' && value !== null)
return 'component' in value
else
return false
}

export function getSlots<T extends Component>(slots?: {
[K in keyof ComponentSlots<T>]?: string | Component | CreateVNodeOptions<Component>
}) {
return objectEntries(slots || {}).reduce<Record<string, () => VNode>>((acc, cur) => {
const slotName = cur[0] as string
const slot = cur[1] as string | Component | CreateVNodeOptions<Component>
if (isString(slot))
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
}, {})
}
11 changes: 0 additions & 11 deletions packages/vue-final-modal/src/useVfm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { VNode } from 'vue'
import { nextTick } from 'vue'
import type { Vfm } from './Modal'
import { activeVfm, getActiveVfm } from './plugin'
Expand Down Expand Up @@ -31,13 +30,3 @@ export async function useSsrVfm(): Promise<Vfm> {
return useVfm()
}
}

export async function pushVNode(vNode: VNode) {
const vfm = await useSsrVfm()
vfm.vNodesContainer.push(vNode)
}

export function removeVNode(vNode: VNode): void {
const vfm = useVfm()
vfm.vNodesContainer.remove(vNode)
}
Loading

0 comments on commit ee11efe

Please sign in to comment.