}
-interface ModalSlotOptionsConcreteComponent extends UseModalOptionsConcreteComponent
{}
-interface ModalSlotOptionsComponentOptions
extends UseModalOptionsComponentOptions
{}
-type ModalSlot = string | Component | UseModalOptionsBase
+type SlotAttrs
= (RawProps & P) | ({} extends P ? null : never)
+interface ModalSlotOptionsConcreteComponent
{ component: ConcreteComponent
; attrs?: SlotAttrs
}
+interface ModalSlotOptionsComponentOptions
{ component: ComponentOptions
; attrs?: SlotAttrs
}
+
+export interface ModalSlotOptions { component: Raw; attrs?: Record }
+export type ModalSlot = string | Component | ModalSlotOptions
export type UseModalOptionsSlots = {
- slots?: string | Component | {
+ slots?: {
default: ModalSlot
[key: string]: ModalSlot
}
@@ -31,7 +34,7 @@ export type UseModalOptionsSlots = {
export type UseModalOptions = {
defaultModelValue?: boolean
context?: Vfm
- component: Raw
+ component?: Raw
attrs?: Record
} & UseModalOptionsSlots
diff --git a/packages/vue-final-modal/src/useApi.ts b/packages/vue-final-modal/src/useApi.ts
index d1bb6bfe..250f4f13 100644
--- a/packages/vue-final-modal/src/useApi.ts
+++ b/packages/vue-final-modal/src/useApi.ts
@@ -1,9 +1,11 @@
import { isString, tryOnUnmounted } from '@vueuse/core'
import { computed, inject, markRaw, reactive, useAttrs } from 'vue'
+import type { Component, Raw } from 'vue'
import VueFinalModal from './components/VueFinalModal/VueFinalModal.vue'
import type CoreModal from './components/CoreModal/CoreModal.vue'
import { internalVfmSymbol, vfmSymbol } from './injectionSymbols'
-import type { ComponentProps, IOverloadedUseModalFn, InternalVfm, UseModalOptions, UseModalOptionsPrivate, UseModalOptionsSlots, UseModalReturnType, Vfm } from './Modal'
+
+import type { ComponentProps, IOverloadedUseModalFn, InternalVfm, ModalSlot, ModalSlotOptions, UseModalOptions, UseModalOptionsPrivate, UseModalReturnType, Vfm } from './Modal'
/**
* Returns the vfm instance. Equivalent to using `$vfm` inside
@@ -20,12 +22,12 @@ export function useInternalVfm(): InternalVfm {
return inject(internalVfmSymbol)!
}
-function withMarkRaw(options: Partial) {
+function withMarkRaw(options: Partial, DefaultComponent: Component = VueFinalModal) {
const { component, slots: innerSlots, ...rest } = options
const slots = typeof innerSlots === 'undefined'
? {}
- : Object.fromEntries(Object.entries(innerSlots).map(([name, maybeComponent]) => {
+ : Object.fromEntries(Object.entries(innerSlots).map(([name, maybeComponent]) => {
if (isString(maybeComponent))
return [name, maybeComponent] as const
@@ -41,7 +43,7 @@ function withMarkRaw(options: Partial) {
return {
...rest,
- component: markRaw(component || VueFinalModal),
+ component: markRaw(component || DefaultComponent),
slots,
}
}
@@ -83,13 +85,21 @@ export const useModal: IOverloadedUseModalFn = function (_options: UseModalOptio
}
function patchOptions(_options: Partial) {
- const _patchOptions = withMarkRaw(_options)
- if (_patchOptions?.attrs)
- Object.assign(options.attrs || {}, _patchOptions.attrs)
- if (_patchOptions?.component)
- Object.assign(options.component || {}, _patchOptions.component)
- if (_patchOptions?.slots)
- Object.assign(options.slots || {}, _patchOptions.slots)
+ const { slots, ...rest } = withMarkRaw(_options, options.component)
+
+ // patch options.component and options.attrs
+ patchComponentOptions(options, rest)
+
+ // patch options.slots
+ if (slots) {
+ Object.entries(slots).forEach(([name, slot]) => {
+ const originSlot = options.slots![name]
+ if (isModalSlotOptions(originSlot) && isModalSlotOptions(slot))
+ patchComponentOptions(originSlot, slot)
+ else
+ options.slots![name] = slot
+ })
+ }
}
function destroy(): void {
@@ -115,6 +125,31 @@ export const useModal: IOverloadedUseModalFn = function (_options: UseModalOptio
return modal
}
+function patchAttrs>(attrs: T, newAttrs: Partial): T {
+ Object.entries(newAttrs).forEach(([key, value]) => {
+ attrs[key as keyof T] = value
+ })
+
+ return attrs
+}
+
+type ComponentOptions = {
+ component?: Raw
+ attrs?: Record
+}
+
+function patchComponentOptions(options: ComponentOptions, newOptions: ComponentOptions) {
+ if (newOptions.component)
+ options.component = newOptions.component
+
+ if (newOptions.attrs)
+ patchAttrs(options.attrs!, newOptions.attrs)
+}
+
+function isModalSlotOptions(value: any): value is ModalSlotOptions {
+ return 'component' in value || 'attrs' in value
+}
+
export function pickModalProps(props: any, modalProps: any) {
return Object.keys(modalProps).reduce((acc, propName) => {
acc[propName] = props[propName]