@@ -57,24 +57,25 @@ export interface ModalEmits extends DialogRootEmits {
5757 ' after:leave' : []
5858 ' after:enter' : []
5959 ' close:prevent' : []
60+ ' close' : []
6061}
6162
6263export interface ModalSlots {
6364 default(props : { open: boolean }): any
64- content(props ? : {}): any
65- header(props ? : {}): any
66- title(props ? : {}): any
67- description(props ? : {}): any
65+ content(props : { close : () => void }): any
66+ header(props : { close : () => void }): any
67+ title(props : { close : () => void }): any
68+ description(props : { close : () => void }): any
6869 close(props : { ui: { [K in keyof Required <Modal [' slots' ]>]: (props ? : Record <string , any >) => string } }): any
69- body(props ? : {}): any
70- footer(props ? : {}): any
70+ body(props : { close : () => void }): any
71+ footer(props : { close : () => void }): any
7172}
7273 </script >
7374
7475<script setup lang="ts">
7576import { computed , toRef } from ' vue'
7677import { DialogRoot , DialogTrigger , DialogPortal , DialogOverlay , DialogContent , DialogTitle , DialogDescription , DialogClose , VisuallyHidden , useForwardPropsEmits } from ' reka-ui'
77- import { reactivePick } from ' @vueuse/core'
78+ import { reactivePick , useVModel } from ' @vueuse/core'
7879import { useAppConfig } from ' #imports'
7980import { useLocale } from ' ../composables/useLocale'
8081import { usePortal } from ' ../composables/usePortal'
@@ -95,7 +96,8 @@ const slots = defineSlots<ModalSlots>()
9596const { t } = useLocale ()
9697const appConfig = useAppConfig () as Modal [' AppConfig' ]
9798
98- const rootProps = useForwardPropsEmits (reactivePick (props , ' open' , ' defaultOpen' , ' modal' ), emits )
99+ const open = useVModel (props , ' open' , emits , { passive: true })
100+ const rootProps = useForwardPropsEmits (reactivePick (props , ' defaultOpen' , ' modal' ), emits )
99101const portalProps = usePortal (toRef (() => props .portal ))
100102const contentProps = toRef (() => props .content )
101103const contentEvents = computed (() => {
@@ -122,10 +124,15 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.modal || {})
122124 transition: props .transition ,
123125 fullscreen: props .fullscreen
124126}))
127+
128+ function closeModal() {
129+ open .value = false
130+ emits (' close' )
131+ }
125132 </script >
126133
127134<template >
128- <DialogRoot v-slot = " { open } " v-bind =" rootProps" >
135+ <DialogRoot v-model:open = " open" v-bind =" rootProps" >
129136 <DialogTrigger v-if =" !!slots.default" as-child :class =" props.class" >
130137 <slot :open =" open" />
131138 </DialogTrigger >
@@ -136,30 +143,30 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.modal || {})
136143 <DialogContent :class =" ui.content({ class: [!slots.default && props.class, props.ui?.content] })" v-bind =" contentProps" @after-enter =" emits('after:enter')" @after-leave =" emits('after:leave')" v-on =" contentEvents" >
137144 <VisuallyHidden v-if =" !!slots.content && ((title || !!slots.title) || (description || !!slots.description))" >
138145 <DialogTitle v-if =" title || !!slots.title" >
139- <slot name =" title" >
146+ <slot name =" title" :close = " closeModal " >
140147 {{ title }}
141148 </slot >
142149 </DialogTitle >
143150
144151 <DialogDescription v-if =" description || !!slots.description" >
145- <slot name =" description" >
152+ <slot name =" description" :close = " closeModal " >
146153 {{ description }}
147154 </slot >
148155 </DialogDescription >
149156 </VisuallyHidden >
150157
151- <slot name =" content" >
158+ <slot name =" content" :close = " closeModal " >
152159 <div v-if =" !!slots.header || (title || !!slots.title) || (description || !!slots.description) || (close || !!slots.close)" :class =" ui.header({ class: props.ui?.header })" >
153- <slot name =" header" >
160+ <slot name =" header" :close = " closeModal " >
154161 <div :class =" ui.wrapper({ class: props.ui?.wrapper })" >
155162 <DialogTitle v-if =" title || !!slots.title" :class =" ui.title({ class: props.ui?.title })" >
156- <slot name =" title" >
163+ <slot name =" title" :close = " closeModal " >
157164 {{ title }}
158165 </slot >
159166 </DialogTitle >
160167
161168 <DialogDescription v-if =" description || !!slots.description" :class =" ui.description({ class: props.ui?.description })" >
162- <slot name =" description" >
169+ <slot name =" description" :close = " closeModal " >
163170 {{ description }}
164171 </slot >
165172 </DialogDescription >
@@ -183,11 +190,11 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.modal || {})
183190 </div >
184191
185192 <div v-if =" !!slots.body" :class =" ui.body({ class: props.ui?.body })" >
186- <slot name =" body" />
193+ <slot name =" body" :close = " closeModal " />
187194 </div >
188195
189196 <div v-if =" !!slots.footer" :class =" ui.footer({ class: props.ui?.footer })" >
190- <slot name =" footer" />
197+ <slot name =" footer" :close = " closeModal " />
191198 </div >
192199 </slot >
193200 </DialogContent >
0 commit comments