2025-06-29 14:09:09 +08:00
import type { ExtendedModalApi , ModalApiOptions , ModalProps } from "./modal" ;
2025-03-03 19:24:51 +00:00
2025-06-29 14:09:09 +08:00
import { defineComponent , h , inject , nextTick , provide , reactive , ref } from "vue" ;
2025-03-03 19:24:51 +00:00
2025-06-29 14:09:09 +08:00
import { useStore } from "/@/vben/shared/store" ;
2025-03-03 19:24:51 +00:00
2025-06-29 14:09:09 +08:00
import { ModalApi } from "./modal-api" ;
import VbenModal from "./modal.vue" ;
2025-03-03 19:24:51 +00:00
2025-06-29 14:09:09 +08:00
const USER_MODAL_INJECT_KEY = Symbol ( "VBEN_MODAL_INJECT" ) ;
2025-03-03 19:24:51 +00:00
const DEFAULT_MODAL_PROPS : Partial < ModalProps > = { } ;
export function setDefaultModalProps ( props : Partial < ModalProps > ) {
Object . assign ( DEFAULT_MODAL_PROPS , props ) ;
}
2025-06-29 14:09:09 +08:00
export function useVbenModal < TParentModalProps extends ModalProps = ModalProps > ( options : ModalApiOptions = { } ) {
2025-03-03 19:24:51 +00:00
// Modal一般会抽离出来,所以如果有传入 connectedComponent,则表示为外部调用,与内部组件进行连接
// 外部的Modal通过provide/inject传递api
const { connectedComponent } = options ;
if ( connectedComponent ) {
const extendedApi = reactive ( { } ) ;
const isModalReady = ref ( true ) ;
const Modal = defineComponent (
( props : TParentModalProps , { attrs , slots } ) = > {
provide ( USER_MODAL_INJECT_KEY , {
extendApi ( api : ExtendedModalApi ) {
// 不能直接给 reactive 赋值,会丢失响应
// 不能用 Object.assign,会丢失 api 的原型函数
Object . setPrototypeOf ( extendedApi , api ) ;
} ,
options ,
async reCreateModal() {
isModalReady . value = false ;
await nextTick ( ) ;
isModalReady . value = true ;
} ,
} ) ;
checkProps ( extendedApi as ExtendedModalApi , {
. . . props ,
. . . attrs ,
. . . slots ,
} ) ;
return ( ) = >
h (
2025-06-29 14:09:09 +08:00
isModalReady . value ? connectedComponent : "div" ,
2025-03-03 19:24:51 +00:00
{
. . . props ,
. . . attrs ,
} ,
2025-06-29 14:09:09 +08:00
slots
2025-03-03 19:24:51 +00:00
) ;
} ,
{
2025-06-29 14:09:09 +08:00
name : "VbenParentModal" ,
2025-10-05 07:59:56 +00:00
inheritAttrs : false ,
2025-06-29 14:09:09 +08:00
}
2025-03-03 19:24:51 +00:00
) ;
return [ Modal , extendedApi as ExtendedModalApi ] as const ;
}
const injectData = inject < any > ( USER_MODAL_INJECT_KEY , { } ) ;
const mergedOptions = {
. . . DEFAULT_MODAL_PROPS ,
. . . injectData . options ,
. . . options ,
} as ModalApiOptions ;
mergedOptions . onOpenChange = ( isOpen : boolean ) = > {
options . onOpenChange ? . ( isOpen ) ;
injectData . options ? . onOpenChange ? . ( isOpen ) ;
} ;
const onClosed = mergedOptions . onClosed ;
mergedOptions . onClosed = ( ) = > {
onClosed ? . ( ) ;
if ( mergedOptions . destroyOnClose ) {
injectData . reCreateModal ? . ( ) ;
}
} ;
const api = new ModalApi ( mergedOptions ) ;
const extendedApi : ExtendedModalApi = api as never ;
2025-06-29 14:09:09 +08:00
extendedApi . useStore = selector = > {
2025-03-03 19:24:51 +00:00
return useStore ( api . store , selector ) ;
} ;
const Modal = defineComponent (
( props : ModalProps , { attrs , slots } ) = > {
return ( ) = >
h (
VbenModal ,
{
. . . props ,
. . . attrs ,
modalApi : extendedApi ,
} ,
2025-06-29 14:09:09 +08:00
slots
2025-03-03 19:24:51 +00:00
) ;
} ,
{
2025-06-29 14:09:09 +08:00
name : "VbenModal" ,
2025-10-05 07:59:56 +00:00
inheritAttrs : false ,
2025-06-29 14:09:09 +08:00
}
2025-03-03 19:24:51 +00:00
) ;
injectData . extendApi ? . ( extendedApi ) ;
return [ Modal , extendedApi ] as const ;
}
async function checkProps ( api : ExtendedModalApi , attrs : Record < string , any > ) {
if ( ! attrs || Object . keys ( attrs ) . length === 0 ) {
return ;
}
await nextTick ( ) ;
const state = api ? . store ? . state ;
if ( ! state ) {
return ;
}
const stateKeys = new Set ( Object . keys ( state ) ) ;
for ( const attr of Object . keys ( attrs ) ) {
2025-06-29 14:09:09 +08:00
if ( stateKeys . has ( attr ) && ! [ "class" ] . includes ( attr ) ) {
2025-03-03 19:24:51 +00:00
// connectedComponent存在时,不要传入Modal的props,会造成复杂度提升,如果你需要修改Modal的props,请使用 useModal 或者api
2025-06-29 14:09:09 +08:00
console . warn ( ` [Vben Modal]: When 'connectedComponent' exists, do not set props or slots ' ${ attr } ', which will increase complexity. If you need to modify the props of Modal, please use useVbenModal or api. ` ) ;
2025-03-03 19:24:51 +00:00
}
}
}