@@ -107,6 +107,23 @@ interface ContextProps extends CDropdownProps {
107
107
portal : boolean
108
108
}
109
109
110
+ export const getNextActiveElement = ( list : HTMLElement [ ] , activeElement : HTMLElement , shouldGetNext : boolean , isCycleAllowed : boolean ) => {
111
+ const listLength = list . length
112
+ let index = list . indexOf ( activeElement )
113
+
114
+ if ( index === - 1 ) {
115
+ return ! shouldGetNext && isCycleAllowed ? list [ listLength - 1 ] : list [ 0 ]
116
+ }
117
+
118
+ index += shouldGetNext ? 1 : - 1
119
+
120
+ if ( isCycleAllowed ) {
121
+ index = ( index + listLength ) % listLength
122
+ }
123
+
124
+ return list [ Math . max ( 0 , Math . min ( index , listLength - 1 ) ) ]
125
+ }
126
+
110
127
const getPlacement = (
111
128
placement : Placements ,
112
129
direction : CDropdownProps [ 'direction' ] ,
@@ -206,21 +223,33 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
206
223
} , [ visible ] )
207
224
208
225
useEffect ( ( ) => {
209
- if ( _visible && dropdownToggleRef . current && dropdownMenuRef . current ) {
226
+ if ( _visible && dropdownRef . current && dropdownToggleRef . current && dropdownMenuRef . current ) {
227
+ dropdownToggleRef . current . focus ( )
210
228
popper && initPopper ( dropdownToggleRef . current , dropdownMenuRef . current , popperConfig )
211
229
window . addEventListener ( 'mouseup' , handleMouseUp )
212
230
window . addEventListener ( 'keyup' , handleKeyup )
231
+ dropdownRef . current . addEventListener ( 'keydown' , handleKeydown )
213
232
onShow && onShow ( )
214
233
}
215
234
216
235
return ( ) => {
217
236
popper && destroyPopper ( )
218
237
window . removeEventListener ( 'mouseup' , handleMouseUp )
219
238
window . removeEventListener ( 'keyup' , handleKeyup )
239
+ dropdownRef . current && dropdownRef . current . removeEventListener ( 'keydown' , handleKeydown )
220
240
onHide && onHide ( )
221
241
}
222
242
} , [ _visible ] )
223
243
244
+ const handleKeydown = ( event : KeyboardEvent ) => {
245
+ if ( _visible && ( event . key === 'ArrowDown' || event . key === 'ArrowUp' ) ) {
246
+ const target = event . target as HTMLElement
247
+ event . preventDefault ( )
248
+ const items = [ ] . concat ( ...Element . prototype . querySelectorAll . call ( dropdownRef . current , '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' ) )
249
+ getNextActiveElement ( items , target , event . key === 'ArrowDown' , true ) . focus ( )
250
+ }
251
+ }
252
+
224
253
const handleKeyup = ( event : KeyboardEvent ) => {
225
254
if ( autoClose === false ) {
226
255
return
0 commit comments