@@ -17,6 +17,28 @@ export type Breakpoints =
1717
1818export type Alignments = Directions | Breakpoints
1919
20+ export const getNextActiveElement = (
21+ list : HTMLElement [ ] ,
22+ activeElement : HTMLElement ,
23+ shouldGetNext : boolean ,
24+ isCycleAllowed : boolean ,
25+ ) => {
26+ const listLength = list . length
27+ let index = list . indexOf ( activeElement )
28+
29+ if ( index === - 1 ) {
30+ return ! shouldGetNext && isCycleAllowed ? list [ listLength - 1 ] : list [ 0 ]
31+ }
32+
33+ index += shouldGetNext ? 1 : - 1
34+
35+ if ( isCycleAllowed ) {
36+ index = ( index + listLength ) % listLength
37+ }
38+
39+ return list [ Math . max ( 0 , Math . min ( index , listLength - 1 ) ) ]
40+ }
41+
2042const getPlacement = (
2143 placement : Placement ,
2244 direction : string | undefined ,
@@ -214,13 +236,19 @@ const CDropdown = defineComponent({
214236 popper . value && initPopper ( dropdownToggleRef . value , dropdownMenuRef . value , popperConfig )
215237 window . addEventListener ( 'mouseup' , handleMouseUp )
216238 window . addEventListener ( 'keyup' , handleKeyup )
239+ dropdownToggleRef . value . addEventListener ( 'keydown' , handleKeydown )
240+ dropdownMenuRef . value . addEventListener ( 'keydown' , handleKeydown )
217241 emit ( 'show' )
218242 return
219243 }
220244
221245 popper . value && destroyPopper ( )
222246 window . removeEventListener ( 'mouseup' , handleMouseUp )
223247 window . removeEventListener ( 'keyup' , handleKeyup )
248+ dropdownToggleRef . value &&
249+ dropdownToggleRef . value . removeEventListener ( 'keydown' , handleKeydown )
250+ dropdownMenuRef . value &&
251+ dropdownMenuRef . value . removeEventListener ( 'keydown' , handleKeydown )
224252 emit ( 'hide' )
225253 } )
226254
@@ -235,6 +263,15 @@ const CDropdown = defineComponent({
235263 provide ( 'dropdownToggleRef' , dropdownToggleRef )
236264 provide ( 'dropdownMenuRef' , dropdownMenuRef )
237265
266+ const handleKeydown = ( event : KeyboardEvent ) => {
267+ if ( visible . value && dropdownMenuRef . value && ( event . key === 'ArrowDown' || event . key === 'ArrowUp' ) ) {
268+ event . preventDefault ( )
269+ const target = event . target as HTMLElement
270+ const items : HTMLElement [ ] = Array . from ( dropdownMenuRef . value . querySelectorAll ( '.dropdown-item:not(.disabled):not(:disabled)' ) )
271+ getNextActiveElement ( items , target , event . key === 'ArrowDown' , true ) . focus ( )
272+ }
273+ }
274+
238275 const handleKeyup = ( event : KeyboardEvent ) => {
239276 if ( props . autoClose === false ) {
240277 return
0 commit comments