@@ -107,6 +107,23 @@ interface ContextProps extends CDropdownProps {
107107 portal : boolean
108108}
109109
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+
110127const getPlacement = (
111128 placement : Placements ,
112129 direction : CDropdownProps [ 'direction' ] ,
@@ -206,21 +223,33 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
206223 } , [ visible ] )
207224
208225 useEffect ( ( ) => {
209- if ( _visible && dropdownToggleRef . current && dropdownMenuRef . current ) {
226+ if ( _visible && dropdownRef . current && dropdownToggleRef . current && dropdownMenuRef . current ) {
227+ dropdownToggleRef . current . focus ( )
210228 popper && initPopper ( dropdownToggleRef . current , dropdownMenuRef . current , popperConfig )
211229 window . addEventListener ( 'mouseup' , handleMouseUp )
212230 window . addEventListener ( 'keyup' , handleKeyup )
231+ dropdownRef . current . addEventListener ( 'keydown' , handleKeydown )
213232 onShow && onShow ( )
214233 }
215234
216235 return ( ) => {
217236 popper && destroyPopper ( )
218237 window . removeEventListener ( 'mouseup' , handleMouseUp )
219238 window . removeEventListener ( 'keyup' , handleKeyup )
239+ dropdownRef . current && dropdownRef . current . removeEventListener ( 'keydown' , handleKeydown )
220240 onHide && onHide ( )
221241 }
222242 } , [ _visible ] )
223243
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+
224253 const handleKeyup = ( event : KeyboardEvent ) => {
225254 if ( autoClose === false ) {
226255 return
0 commit comments