@@ -150,13 +150,14 @@ const reducer = (state: IState, action: IAction) => {
150150
151151interface IProps {
152152 handleHomeEnd ?: boolean ;
153+ handleUpDown ?: boolean ;
153154 children ( renderProps : {
154155 onKeyDownHandler ( ev : React . KeyboardEvent ) ;
155156 } ) ;
156157 onKeyDown ?( ev : React . KeyboardEvent , state : IState ) ;
157158}
158159
159- export const RovingTabIndexProvider : React . FC < IProps > = ( { children, handleHomeEnd, onKeyDown } ) => {
160+ export const RovingTabIndexProvider : React . FC < IProps > = ( { children, handleHomeEnd, handleUpDown , onKeyDown } ) => {
160161 const [ state , dispatch ] = useReducer < Reducer < IState , IAction > > ( reducer , {
161162 activeRef : null ,
162163 refs : [ ] ,
@@ -167,21 +168,50 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({ children, handleHomeE
167168 const onKeyDownHandler = useCallback ( ( ev ) => {
168169 let handled = false ;
169170 // Don't interfere with input default keydown behaviour
170- if ( handleHomeEnd && ev . target . tagName !== "INPUT" && ev . target . tagName !== "TEXTAREA" ) {
171+ if ( ev . target . tagName !== "INPUT" && ev . target . tagName !== "TEXTAREA" ) {
171172 // check if we actually have any items
172173 switch ( ev . key ) {
173174 case Key . HOME :
174- handled = true ;
175- // move focus to first item
176- if ( context . state . refs . length > 0 ) {
177- context . state . refs [ 0 ] . current . focus ( ) ;
175+ if ( handleHomeEnd ) {
176+ handled = true ;
177+ // move focus to first item
178+ if ( context . state . refs . length > 0 ) {
179+ context . state . refs [ 0 ] . current . focus ( ) ;
180+ }
178181 }
179182 break ;
183+
180184 case Key . END :
181- handled = true ;
182- // move focus to last item
183- if ( context . state . refs . length > 0 ) {
184- context . state . refs [ context . state . refs . length - 1 ] . current . focus ( ) ;
185+ if ( handleHomeEnd ) {
186+ handled = true ;
187+ // move focus to last item
188+ if ( context . state . refs . length > 0 ) {
189+ context . state . refs [ context . state . refs . length - 1 ] . current . focus ( ) ;
190+ }
191+ }
192+ break ;
193+
194+ case Key . ARROW_UP :
195+ if ( handleUpDown ) {
196+ handled = true ;
197+ if ( context . state . refs . length > 0 ) {
198+ const idx = context . state . refs . indexOf ( context . state . activeRef ) ;
199+ if ( idx > 0 ) {
200+ context . state . refs [ idx - 1 ] . current . focus ( ) ;
201+ }
202+ }
203+ }
204+ break ;
205+
206+ case Key . ARROW_DOWN :
207+ if ( handleUpDown ) {
208+ handled = true ;
209+ if ( context . state . refs . length > 0 ) {
210+ const idx = context . state . refs . indexOf ( context . state . activeRef ) ;
211+ if ( idx < context . state . refs . length - 1 ) {
212+ context . state . refs [ idx + 1 ] . current . focus ( ) ;
213+ }
214+ }
185215 }
186216 break ;
187217 }
@@ -193,7 +223,7 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({ children, handleHomeE
193223 } else if ( onKeyDown ) {
194224 return onKeyDown ( ev , context . state ) ;
195225 }
196- } , [ context . state , onKeyDown , handleHomeEnd ] ) ;
226+ } , [ context . state , onKeyDown , handleHomeEnd , handleUpDown ] ) ;
197227
198228 return < RovingTabIndexContext . Provider value = { context } >
199229 { children ( { onKeyDownHandler } ) }
0 commit comments