1
- import { defineComponent , h , ref , provide , watch , PropType } from 'vue'
1
+ import { defineComponent , h , ref , provide , watch , PropType , onUnmounted , nextTick } from 'vue'
2
2
import type { Placement } from '@popperjs/core'
3
3
4
4
import { usePopper } from '../../composables'
@@ -158,6 +158,7 @@ const CDropdown = defineComponent({
158
158
setup ( props , { slots, emit } ) {
159
159
const dropdownToggleRef = ref ( )
160
160
const dropdownMenuRef = ref ( )
161
+ const pendingKeyDownEventRef = ref < KeyboardEvent | null > ( null )
161
162
const popper = ref ( typeof props . alignment === 'object' ? false : props . popper )
162
163
const visible = ref ( props . visible )
163
164
@@ -176,35 +177,50 @@ const CDropdown = defineComponent({
176
177
props . placement ,
177
178
props . direction ,
178
179
props . alignment ,
179
- isRTL ( dropdownMenuRef . value ) ,
180
+ isRTL ( dropdownMenuRef . value )
180
181
) as Placement ,
181
182
}
182
183
183
184
watch (
184
185
( ) => props . visible ,
185
186
( ) => {
186
187
visible . value = props . visible
187
- } ,
188
+ }
188
189
)
189
190
190
191
watch ( visible , ( ) => {
191
192
if ( visible . value && dropdownToggleRef . value && dropdownMenuRef . value ) {
192
- popper . value && initPopper ( dropdownToggleRef . value , dropdownMenuRef . value , popperConfig )
193
+ if ( popper . value ) {
194
+ initPopper ( dropdownToggleRef . value , dropdownMenuRef . value , popperConfig )
195
+ }
196
+
193
197
window . addEventListener ( 'mouseup' , handleMouseUp )
194
198
window . addEventListener ( 'keyup' , handleKeyup )
195
199
dropdownToggleRef . value . addEventListener ( 'keydown' , handleKeydown )
196
200
dropdownMenuRef . value . addEventListener ( 'keydown' , handleKeydown )
201
+
202
+ if ( pendingKeyDownEventRef . value ) {
203
+ nextTick ( ( ) => {
204
+ handleKeydown ( pendingKeyDownEventRef . value as KeyboardEvent )
205
+ pendingKeyDownEventRef . value = null
206
+ } )
207
+ }
208
+
197
209
emit ( 'show' )
198
210
return
199
211
}
200
212
201
213
popper . value && destroyPopper ( )
202
214
window . removeEventListener ( 'mouseup' , handleMouseUp )
203
215
window . removeEventListener ( 'keyup' , handleKeyup )
216
+ dropdownMenuRef . value && dropdownMenuRef . value . removeEventListener ( 'keydown' , handleKeydown )
217
+ emit ( 'hide' )
218
+ } )
219
+
220
+ onUnmounted ( ( ) => {
204
221
dropdownToggleRef . value &&
205
222
dropdownToggleRef . value . removeEventListener ( 'keydown' , handleKeydown )
206
223
dropdownMenuRef . value && dropdownMenuRef . value . removeEventListener ( 'keydown' , handleKeydown )
207
- emit ( 'hide' )
208
224
} )
209
225
210
226
provide ( 'config' , {
@@ -219,18 +235,14 @@ const CDropdown = defineComponent({
219
235
provide ( 'visible' , visible )
220
236
provide ( 'dropdownToggleRef' , dropdownToggleRef )
221
237
provide ( 'dropdownMenuRef' , dropdownMenuRef )
238
+ provide ( 'pendingKeyDownEventRef' , pendingKeyDownEventRef )
222
239
223
240
const handleKeydown = ( event : KeyboardEvent ) => {
224
- if (
225
- visible . value &&
226
- dropdownMenuRef . value &&
227
- ( event . key === 'ArrowDown' || event . key === 'ArrowUp' )
228
- ) {
241
+ if ( dropdownMenuRef . value && ( event . key === 'ArrowDown' || event . key === 'ArrowUp' ) ) {
229
242
event . preventDefault ( )
230
243
const target = event . target as HTMLElement
231
- // eslint-disable-next-line unicorn/prefer-spread
232
244
const items : HTMLElement [ ] = Array . from (
233
- dropdownMenuRef . value . querySelectorAll ( '.dropdown-item:not(.disabled):not(:disabled)' ) ,
245
+ dropdownMenuRef . value . querySelectorAll ( '.dropdown-item:not(.disabled):not(:disabled)' )
234
246
)
235
247
getNextActiveElement ( items , target , event . key === 'ArrowDown' , true ) . focus ( )
236
248
}
@@ -243,6 +255,7 @@ const CDropdown = defineComponent({
243
255
244
256
if ( event . key === 'Escape' ) {
245
257
setVisible ( false )
258
+ dropdownToggleRef . value ?. focus ( )
246
259
}
247
260
}
248
261
@@ -267,22 +280,20 @@ const CDropdown = defineComponent({
267
280
}
268
281
}
269
282
270
- const setVisible = ( _visible ?: boolean ) => {
283
+ const setVisible = ( _visible ?: boolean , event ?: KeyboardEvent ) => {
271
284
if ( props . disabled ) {
272
285
return
273
286
}
274
287
275
- if ( typeof _visible == 'boolean' ) {
288
+ if ( typeof _visible === 'boolean' ) {
289
+ if ( event ) {
290
+ pendingKeyDownEventRef . value = event || null
291
+ }
292
+
276
293
visible . value = _visible
277
- return
278
- }
279
294
280
- if ( visible . value === true ) {
281
- visible . value = false
282
295
return
283
296
}
284
-
285
- visible . value = true
286
297
}
287
298
288
299
provide ( 'setVisible' , setVisible )
@@ -298,11 +309,11 @@ const CDropdown = defineComponent({
298
309
props . direction === 'center'
299
310
? 'dropdown-center'
300
311
: props . direction === 'dropup-center'
301
- ? 'dropup dropup-center'
302
- : props . direction ,
312
+ ? 'dropup dropup-center'
313
+ : props . direction ,
303
314
] ,
304
315
} ,
305
- slots . default && slots . default ( ) ,
316
+ slots . default && slots . default ( )
306
317
)
307
318
} ,
308
319
} )
0 commit comments