1- import { defineComponent , h , ref , provide , watch , PropType } from 'vue'
1+ import { defineComponent , h , ref , provide , watch , PropType , onUnmounted , nextTick } from 'vue'
22import type { Placement } from '@popperjs/core'
33
44import { usePopper } from '../../composables'
@@ -158,6 +158,7 @@ const CDropdown = defineComponent({
158158 setup ( props , { slots, emit } ) {
159159 const dropdownToggleRef = ref ( )
160160 const dropdownMenuRef = ref ( )
161+ const pendingKeyDownEventRef = ref < KeyboardEvent | null > ( null )
161162 const popper = ref ( typeof props . alignment === 'object' ? false : props . popper )
162163 const visible = ref ( props . visible )
163164
@@ -176,35 +177,50 @@ const CDropdown = defineComponent({
176177 props . placement ,
177178 props . direction ,
178179 props . alignment ,
179- isRTL ( dropdownMenuRef . value ) ,
180+ isRTL ( dropdownMenuRef . value )
180181 ) as Placement ,
181182 }
182183
183184 watch (
184185 ( ) => props . visible ,
185186 ( ) => {
186187 visible . value = props . visible
187- } ,
188+ }
188189 )
189190
190191 watch ( visible , ( ) => {
191192 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+
193197 window . addEventListener ( 'mouseup' , handleMouseUp )
194198 window . addEventListener ( 'keyup' , handleKeyup )
195199 dropdownToggleRef . value . addEventListener ( 'keydown' , handleKeydown )
196200 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+
197209 emit ( 'show' )
198210 return
199211 }
200212
201213 popper . value && destroyPopper ( )
202214 window . removeEventListener ( 'mouseup' , handleMouseUp )
203215 window . removeEventListener ( 'keyup' , handleKeyup )
216+ dropdownMenuRef . value && dropdownMenuRef . value . removeEventListener ( 'keydown' , handleKeydown )
217+ emit ( 'hide' )
218+ } )
219+
220+ onUnmounted ( ( ) => {
204221 dropdownToggleRef . value &&
205222 dropdownToggleRef . value . removeEventListener ( 'keydown' , handleKeydown )
206223 dropdownMenuRef . value && dropdownMenuRef . value . removeEventListener ( 'keydown' , handleKeydown )
207- emit ( 'hide' )
208224 } )
209225
210226 provide ( 'config' , {
@@ -219,18 +235,14 @@ const CDropdown = defineComponent({
219235 provide ( 'visible' , visible )
220236 provide ( 'dropdownToggleRef' , dropdownToggleRef )
221237 provide ( 'dropdownMenuRef' , dropdownMenuRef )
238+ provide ( 'pendingKeyDownEventRef' , pendingKeyDownEventRef )
222239
223240 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' ) ) {
229242 event . preventDefault ( )
230243 const target = event . target as HTMLElement
231- // eslint-disable-next-line unicorn/prefer-spread
232244 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)' )
234246 )
235247 getNextActiveElement ( items , target , event . key === 'ArrowDown' , true ) . focus ( )
236248 }
@@ -243,6 +255,7 @@ const CDropdown = defineComponent({
243255
244256 if ( event . key === 'Escape' ) {
245257 setVisible ( false )
258+ dropdownToggleRef . value ?. focus ( )
246259 }
247260 }
248261
@@ -267,22 +280,20 @@ const CDropdown = defineComponent({
267280 }
268281 }
269282
270- const setVisible = ( _visible ?: boolean ) => {
283+ const setVisible = ( _visible ?: boolean , event ?: KeyboardEvent ) => {
271284 if ( props . disabled ) {
272285 return
273286 }
274287
275- if ( typeof _visible == 'boolean' ) {
288+ if ( typeof _visible === 'boolean' ) {
289+ if ( event ) {
290+ pendingKeyDownEventRef . value = event || null
291+ }
292+
276293 visible . value = _visible
277- return
278- }
279294
280- if ( visible . value === true ) {
281- visible . value = false
282295 return
283296 }
284-
285- visible . value = true
286297 }
287298
288299 provide ( 'setVisible' , setVisible )
@@ -298,11 +309,11 @@ const CDropdown = defineComponent({
298309 props . direction === 'center'
299310 ? 'dropdown-center'
300311 : props . direction === 'dropup-center'
301- ? 'dropup dropup-center'
302- : props . direction ,
312+ ? 'dropup dropup-center'
313+ : props . direction ,
303314 ] ,
304315 } ,
305- slots . default && slots . default ( ) ,
316+ slots . default && slots . default ( )
306317 )
307318 } ,
308319} )
0 commit comments