@@ -36,123 +36,125 @@ interface AbstractNavProps
36
36
parentOnSelect ?: SelectCallback ;
37
37
}
38
38
39
- const AbstractNav : BsPrefixRefForwardingComponent <
40
- 'ul' ,
41
- AbstractNavProps
42
- > = React . forwardRef < HTMLElement , AbstractNavProps > (
43
- (
44
- {
45
- // Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
46
- as : Component = 'ul' ,
47
- onSelect,
48
- activeKey,
49
- role,
50
- onKeyDown,
51
- ...props
52
- } ,
53
- ref ,
54
- ) => {
55
- // A ref and forceUpdate for refocus, b/c we only want to trigger when needed
56
- // and don't want to reset the set in the effect
57
- const forceUpdate = useForceUpdate ( ) ;
58
- const needsRefocusRef = useRef ( false ) ;
59
-
60
- const parentOnSelect = useContext ( SelectableContext ) ;
61
- const tabContext = useContext ( TabContext ) ;
62
-
63
- let getControlledId , getControllerId ;
64
-
65
- if ( tabContext ) {
66
- role = role || 'tablist' ;
67
- activeKey = tabContext . activeKey ;
68
- getControlledId = tabContext . getControlledId ;
69
- getControllerId = tabContext . getControllerId ;
70
- }
71
-
72
- const listNode = useRef < HTMLElement > ( null ) ;
73
-
74
- const getNextActiveChild = ( offset : number ) => {
75
- const currentListNode = listNode . current ;
76
- if ( ! currentListNode ) return null ;
77
-
78
- const items = qsa ( currentListNode , '[data-rb-event-key]:not(.disabled)' ) ;
79
- const activeChild = currentListNode . querySelector < HTMLElement > ( '.active' ) ;
80
- if ( ! activeChild ) return null ;
81
-
82
- const index = items . indexOf ( activeChild ) ;
83
- if ( index === - 1 ) return null ;
84
-
85
- let nextIndex = index + offset ;
86
- if ( nextIndex >= items . length ) nextIndex = 0 ;
87
- if ( nextIndex < 0 ) nextIndex = items . length - 1 ;
88
- return items [ nextIndex ] ;
89
- } ;
90
-
91
- const handleSelect = ( key , event ) => {
92
- if ( key == null ) return ;
93
- onSelect ?.( key , event ) ;
94
- parentOnSelect ?.( key , event ) ;
95
- } ;
96
-
97
- const handleKeyDown = ( event ) => {
98
- onKeyDown ?.( event ) ;
99
-
100
- let nextActiveChild ;
101
- switch ( event . key ) {
102
- case 'ArrowLeft' :
103
- case 'ArrowUp' :
104
- nextActiveChild = getNextActiveChild ( - 1 ) ;
105
- break ;
106
- case 'ArrowRight' :
107
- case 'ArrowDown' :
108
- nextActiveChild = getNextActiveChild ( 1 ) ;
109
- break ;
110
- default :
111
- return ;
39
+ const AbstractNav : BsPrefixRefForwardingComponent < 'ul' , AbstractNavProps > =
40
+ React . forwardRef < HTMLElement , AbstractNavProps > (
41
+ (
42
+ {
43
+ // Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
44
+ as : Component = 'ul' ,
45
+ onSelect,
46
+ activeKey,
47
+ role,
48
+ onKeyDown,
49
+ ...props
50
+ } ,
51
+ ref ,
52
+ ) => {
53
+ // A ref and forceUpdate for refocus, b/c we only want to trigger when needed
54
+ // and don't want to reset the set in the effect
55
+ const forceUpdate = useForceUpdate ( ) ;
56
+ const needsRefocusRef = useRef ( false ) ;
57
+
58
+ const parentOnSelect = useContext ( SelectableContext ) ;
59
+ const tabContext = useContext ( TabContext ) ;
60
+
61
+ let getControlledId , getControllerId ;
62
+
63
+ if ( tabContext ) {
64
+ role = role || 'tablist' ;
65
+ activeKey = tabContext . activeKey ;
66
+ getControlledId = tabContext . getControlledId ;
67
+ getControllerId = tabContext . getControllerId ;
112
68
}
113
- if ( ! nextActiveChild ) return ;
114
-
115
- event . preventDefault ( ) ;
116
- handleSelect ( nextActiveChild . dataset . rbEventKey , event ) ;
117
- needsRefocusRef . current = true ;
118
- forceUpdate ( ) ;
119
- } ;
120
-
121
- useEffect ( ( ) => {
122
- if ( listNode . current && needsRefocusRef . current ) {
123
- const activeChild = listNode . current . querySelector < HTMLElement > (
124
- '[data-rb-event-key].active' ,
125
- ) ;
126
69
127
- activeChild ?. focus ( ) ;
128
- }
70
+ const listNode = useRef < HTMLElement > ( null ) ;
129
71
130
- needsRefocusRef . current = false ;
131
- } ) ;
132
-
133
- const mergedRef = useMergedRefs ( ref , listNode ) ;
134
-
135
- return (
136
- < SelectableContext . Provider value = { handleSelect } >
137
- < NavContext . Provider
138
- value = { {
139
- role, // used by NavLink to determine it's role
140
- activeKey : makeEventKey ( activeKey ) ,
141
- getControlledId : getControlledId || noop ,
142
- getControllerId : getControllerId || noop ,
143
- } }
144
- >
145
- < Component
146
- { ...props }
147
- onKeyDown = { handleKeyDown }
148
- ref = { mergedRef }
149
- role = { role }
150
- />
151
- </ NavContext . Provider >
152
- </ SelectableContext . Provider >
153
- ) ;
154
- } ,
155
- ) ;
72
+ const getNextActiveChild = ( offset : number ) => {
73
+ const currentListNode = listNode . current ;
74
+ if ( ! currentListNode ) return null ;
75
+
76
+ const items = qsa (
77
+ currentListNode ,
78
+ '[data-rb-event-key]:not(.disabled)' ,
79
+ ) ;
80
+ const activeChild =
81
+ currentListNode . querySelector < HTMLElement > ( '.active' ) ;
82
+ if ( ! activeChild ) return null ;
83
+
84
+ const index = items . indexOf ( activeChild ) ;
85
+ if ( index === - 1 ) return null ;
86
+
87
+ let nextIndex = index + offset ;
88
+ if ( nextIndex >= items . length ) nextIndex = 0 ;
89
+ if ( nextIndex < 0 ) nextIndex = items . length - 1 ;
90
+ return items [ nextIndex ] ;
91
+ } ;
92
+
93
+ const handleSelect = ( key , event ) => {
94
+ if ( key == null ) return ;
95
+ onSelect ?.( key , event ) ;
96
+ parentOnSelect ?.( key , event ) ;
97
+ } ;
98
+
99
+ const handleKeyDown = ( event ) => {
100
+ onKeyDown ?.( event ) ;
101
+
102
+ let nextActiveChild ;
103
+ switch ( event . key ) {
104
+ case 'ArrowLeft' :
105
+ case 'ArrowUp' :
106
+ nextActiveChild = getNextActiveChild ( - 1 ) ;
107
+ break ;
108
+ case 'ArrowRight' :
109
+ case 'ArrowDown' :
110
+ nextActiveChild = getNextActiveChild ( 1 ) ;
111
+ break ;
112
+ default :
113
+ return ;
114
+ }
115
+ if ( ! nextActiveChild ) return ;
116
+
117
+ event . preventDefault ( ) ;
118
+ handleSelect ( nextActiveChild . dataset . rbEventKey , event ) ;
119
+ needsRefocusRef . current = true ;
120
+ forceUpdate ( ) ;
121
+ } ;
122
+
123
+ useEffect ( ( ) => {
124
+ if ( listNode . current && needsRefocusRef . current ) {
125
+ const activeChild = listNode . current . querySelector < HTMLElement > (
126
+ '[data-rb-event-key].active' ,
127
+ ) ;
128
+
129
+ activeChild ?. focus ( ) ;
130
+ }
131
+
132
+ needsRefocusRef . current = false ;
133
+ } ) ;
134
+
135
+ const mergedRef = useMergedRefs ( ref , listNode ) ;
136
+
137
+ return (
138
+ < SelectableContext . Provider value = { handleSelect } >
139
+ < NavContext . Provider
140
+ value = { {
141
+ role, // used by NavLink to determine it's role
142
+ activeKey : makeEventKey ( activeKey ) ,
143
+ getControlledId : getControlledId || noop ,
144
+ getControllerId : getControllerId || noop ,
145
+ } }
146
+ >
147
+ < Component
148
+ { ...props }
149
+ onKeyDown = { handleKeyDown }
150
+ ref = { mergedRef }
151
+ role = { role }
152
+ />
153
+ </ NavContext . Provider >
154
+ </ SelectableContext . Provider >
155
+ ) ;
156
+ } ,
157
+ ) ;
156
158
157
159
AbstractNav . propTypes = propTypes ;
158
160
0 commit comments