@@ -57,24 +57,25 @@ export interface ModalEmits extends DialogRootEmits {
57
57
' after:leave' : []
58
58
' after:enter' : []
59
59
' close:prevent' : []
60
+ ' close' : []
60
61
}
61
62
62
63
export interface ModalSlots {
63
64
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
68
69
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
71
72
}
72
73
</script >
73
74
74
75
<script setup lang="ts">
75
76
import { computed , toRef } from ' vue'
76
77
import { 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'
78
79
import { useAppConfig } from ' #imports'
79
80
import { useLocale } from ' ../composables/useLocale'
80
81
import { usePortal } from ' ../composables/usePortal'
@@ -95,7 +96,8 @@ const slots = defineSlots<ModalSlots>()
95
96
const { t } = useLocale ()
96
97
const appConfig = useAppConfig () as Modal [' AppConfig' ]
97
98
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 )
99
101
const portalProps = usePortal (toRef (() => props .portal ))
100
102
const contentProps = toRef (() => props .content )
101
103
const contentEvents = computed (() => {
@@ -122,10 +124,15 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.modal || {})
122
124
transition: props .transition ,
123
125
fullscreen: props .fullscreen
124
126
}))
127
+
128
+ function closeModal() {
129
+ open .value = false
130
+ emits (' close' )
131
+ }
125
132
</script >
126
133
127
134
<template >
128
- <DialogRoot v-slot = " { open } " v-bind =" rootProps" >
135
+ <DialogRoot v-model:open = " open" v-bind =" rootProps" >
129
136
<DialogTrigger v-if =" !!slots.default" as-child :class =" props.class" >
130
137
<slot :open =" open" />
131
138
</DialogTrigger >
@@ -136,30 +143,30 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.modal || {})
136
143
<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" >
137
144
<VisuallyHidden v-if =" !!slots.content && ((title || !!slots.title) || (description || !!slots.description))" >
138
145
<DialogTitle v-if =" title || !!slots.title" >
139
- <slot name =" title" >
146
+ <slot name =" title" :close = " closeModal " >
140
147
{{ title }}
141
148
</slot >
142
149
</DialogTitle >
143
150
144
151
<DialogDescription v-if =" description || !!slots.description" >
145
- <slot name =" description" >
152
+ <slot name =" description" :close = " closeModal " >
146
153
{{ description }}
147
154
</slot >
148
155
</DialogDescription >
149
156
</VisuallyHidden >
150
157
151
- <slot name =" content" >
158
+ <slot name =" content" :close = " closeModal " >
152
159
<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 " >
154
161
<div :class =" ui.wrapper({ class: props.ui?.wrapper })" >
155
162
<DialogTitle v-if =" title || !!slots.title" :class =" ui.title({ class: props.ui?.title })" >
156
- <slot name =" title" >
163
+ <slot name =" title" :close = " closeModal " >
157
164
{{ title }}
158
165
</slot >
159
166
</DialogTitle >
160
167
161
168
<DialogDescription v-if =" description || !!slots.description" :class =" ui.description({ class: props.ui?.description })" >
162
- <slot name =" description" >
169
+ <slot name =" description" :close = " closeModal " >
163
170
{{ description }}
164
171
</slot >
165
172
</DialogDescription >
@@ -183,11 +190,11 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.modal || {})
183
190
</div >
184
191
185
192
<div v-if =" !!slots.body" :class =" ui.body({ class: props.ui?.body })" >
186
- <slot name =" body" />
193
+ <slot name =" body" :close = " closeModal " />
187
194
</div >
188
195
189
196
<div v-if =" !!slots.footer" :class =" ui.footer({ class: props.ui?.footer })" >
190
- <slot name =" footer" />
197
+ <slot name =" footer" :close = " closeModal " />
191
198
</div >
192
199
</slot >
193
200
</DialogContent >
0 commit comments