1
- import type { Component } from 'vue' ;
1
+ import type { Component , VNode } from 'vue' ;
2
2
3
3
import type { Recordable } from '@vben-core/typings' ;
4
4
5
- import type { AlertProps , BeforeCloseScope } from './alert' ;
5
+ import type { AlertProps , BeforeCloseScope , PromptProps } from './alert' ;
6
6
7
- import { h , ref , render } from 'vue' ;
7
+ import { h , nextTick , ref , render } from 'vue' ;
8
8
9
9
import { useSimpleLocale } from '@vben-core/composables' ;
10
10
import { Input } from '@vben-core/shadcn-ui' ;
@@ -130,40 +130,58 @@ export function vbenConfirm(
130
130
}
131
131
132
132
export async function vbenPrompt < T = any > (
133
- options : Omit < AlertProps , 'beforeClose' > & {
134
- beforeClose ?: ( scope : {
135
- isConfirm : boolean ;
136
- value : T | undefined ;
137
- } ) => boolean | Promise < boolean | undefined > | undefined ;
138
- component ?: Component ;
139
- componentProps ?: Recordable < any > ;
140
- defaultValue ?: T ;
141
- modelPropName ?: string ;
142
- } ,
133
+ options : PromptProps < T > ,
143
134
) : Promise < T | undefined > {
144
135
const {
145
136
component : _component ,
146
137
componentProps : _componentProps ,
138
+ componentSlots,
147
139
content,
148
140
defaultValue,
149
141
modelPropName : _modelPropName ,
150
142
...delegated
151
143
} = options ;
152
- const contents : Component [ ] = [ ] ;
144
+
153
145
const modelValue = ref < T | undefined > ( defaultValue ) ;
146
+ const inputComponentRef = ref < null | VNode > ( null ) ;
147
+ const staticContents : Component [ ] = [ ] ;
148
+
154
149
if ( isString ( content ) ) {
155
- contents . push ( h ( 'span' , content ) ) ;
156
- } else {
157
- contents . push ( content ) ;
150
+ staticContents . push ( h ( 'span' , content ) ) ;
151
+ } else if ( content ) {
152
+ staticContents . push ( content as Component ) ;
158
153
}
159
- const componentProps = _componentProps || { } ;
154
+
160
155
const modelPropName = _modelPropName || 'modelValue' ;
161
- componentProps [ modelPropName ] = modelValue . value ;
162
- componentProps [ `onUpdate:${ modelPropName } ` ] = ( val : any ) => {
163
- modelValue . value = val ;
156
+ const componentProps = { ..._componentProps } ;
157
+
158
+ // 每次渲染时都会重新计算的内容函数
159
+ const contentRenderer = ( ) => {
160
+ const currentProps = { ...componentProps } ;
161
+
162
+ // 设置当前值
163
+ currentProps [ modelPropName ] = modelValue . value ;
164
+
165
+ // 设置更新处理函数
166
+ currentProps [ `onUpdate:${ modelPropName } ` ] = ( val : T ) => {
167
+ modelValue . value = val ;
168
+ } ;
169
+
170
+ // 创建输入组件
171
+ inputComponentRef . value = h (
172
+ _component || Input ,
173
+ currentProps ,
174
+ componentSlots ,
175
+ ) ;
176
+
177
+ // 返回包含静态内容和输入组件的数组
178
+ return h (
179
+ 'div' ,
180
+ { class : 'flex flex-col gap-2' } ,
181
+ { default : ( ) => [ ...staticContents , inputComponentRef . value ] } ,
182
+ ) ;
164
183
} ;
165
- const componentRef = h ( _component || Input , componentProps ) ;
166
- contents . push ( componentRef ) ;
184
+
167
185
const props : AlertProps & Recordable < any > = {
168
186
...delegated ,
169
187
async beforeClose ( scope : BeforeCloseScope ) {
@@ -174,23 +192,46 @@ export async function vbenPrompt<T = any>(
174
192
} ) ;
175
193
}
176
194
} ,
177
- content : h (
178
- 'div' ,
179
- { class : 'flex flex-col gap-2' } ,
180
- { default : ( ) => contents } ,
181
- ) ,
182
- onOpened ( ) {
183
- // 组件挂载完成后,自动聚焦到输入组件
184
- if (
185
- componentRef . component ?. exposed &&
186
- isFunction ( componentRef . component . exposed . focus )
187
- ) {
188
- componentRef . component . exposed . focus ( ) ;
189
- } else if ( componentRef . el && isFunction ( componentRef . el . focus ) ) {
190
- componentRef . el . focus ( ) ;
195
+ // 使用函数形式,每次渲染都会重新计算内容
196
+ content : contentRenderer ,
197
+ contentMasking : true ,
198
+ async onOpened ( ) {
199
+ await nextTick ( ) ;
200
+ const componentRef : null | VNode = inputComponentRef . value ;
201
+ if ( componentRef ) {
202
+ if (
203
+ componentRef . component ?. exposed &&
204
+ isFunction ( componentRef . component . exposed . focus )
205
+ ) {
206
+ componentRef . component . exposed . focus ( ) ;
207
+ } else {
208
+ if ( componentRef . el ) {
209
+ if (
210
+ isFunction ( componentRef . el . focus ) &&
211
+ [ 'BUTTON' , 'INPUT' , 'SELECT' , 'TEXTAREA' ] . includes (
212
+ componentRef . el . tagName ,
213
+ )
214
+ ) {
215
+ componentRef . el . focus ( ) ;
216
+ } else if ( isFunction ( componentRef . el . querySelector ) ) {
217
+ const focusableElement = componentRef . el . querySelector (
218
+ 'input, select, textarea, button' ,
219
+ ) ;
220
+ if ( focusableElement && isFunction ( focusableElement . focus ) ) {
221
+ focusableElement . focus ( ) ;
222
+ }
223
+ } else if (
224
+ componentRef . el . nextElementSibling &&
225
+ isFunction ( componentRef . el . nextElementSibling . focus )
226
+ ) {
227
+ componentRef . el . nextElementSibling . focus ( ) ;
228
+ }
229
+ }
230
+ }
191
231
}
192
232
} ,
193
233
} ;
234
+
194
235
await vbenConfirm ( props ) ;
195
236
return modelValue . value ;
196
237
}
0 commit comments