@@ -6,10 +6,14 @@ import ButtonGroup from './ButtonGroup';
6
6
import DropdownToggle from './DropdownToggle' ;
7
7
import DropdownMenu from './DropdownMenu' ;
8
8
import CustomPropTypes from './utils/CustomPropTypes' ;
9
+ import ValidComponentChildren from './utils/ValidComponentChildren' ;
9
10
import createChainedFunction from './utils/createChainedFunction' ;
10
11
import find from 'lodash/collection/find' ;
11
12
import omit from 'lodash/object/omit' ;
12
13
14
+ import activeElement from 'dom-helpers/activeElement' ;
15
+ import contains from 'dom-helpers/query/contains' ;
16
+
13
17
const TOGGLE_REF = 'toggle-btn' ;
14
18
15
19
export const TOGGLE_ROLE = DropdownToggle . defaultProps . bsRole ;
@@ -52,11 +56,30 @@ class Dropdown extends React.Component {
52
56
}
53
57
}
54
58
55
- componentDidUpdate ( prevProps , prevState ) {
59
+ componentWillUpdate ( nextProps ) {
60
+ if ( ! nextProps . open && this . props . open ) {
61
+ this . _focusInDropdown = contains (
62
+ React . findDOMNode ( this . refs . menu ) ,
63
+ activeElement ( document )
64
+ ) ;
65
+ }
66
+ }
67
+
68
+ componentDidUpdate ( prevProps ) {
56
69
let menu = this . refs . menu ;
70
+
57
71
if ( this . props . open && ! prevProps . open && menu . focusNext ) {
58
72
menu . focusNext ( ) ;
59
73
}
74
+
75
+ if ( ! this . props . open && prevProps . open ) {
76
+ // if focus hasn't already moved from the menu lets return it
77
+ // to the toggle
78
+ if ( this . _focusInDropdown ) {
79
+ this . _focusInDropdown = false ;
80
+ this . focus ( ) ;
81
+ }
82
+ }
60
83
}
61
84
62
85
render ( ) {
@@ -74,6 +97,7 @@ class Dropdown extends React.Component {
74
97
return (
75
98
< Component
76
99
{ ...props }
100
+ tabIndex = '-1'
77
101
className = { classNames ( this . props . className , rootClasses ) }
78
102
>
79
103
{ children }
@@ -84,7 +108,7 @@ class Dropdown extends React.Component {
84
108
toggleOpen ( ) {
85
109
let open = ! this . props . open ;
86
110
87
- if ( this . props . onToggle ) {
111
+ if ( this . props . onToggle ) {
88
112
this . props . onToggle ( open ) ;
89
113
}
90
114
}
@@ -115,9 +139,7 @@ class Dropdown extends React.Component {
115
139
break ;
116
140
case keycode . codes . esc :
117
141
case keycode . codes . tab :
118
- if ( this . props . open ) {
119
- this . handleClose ( event ) ;
120
- }
142
+ this . handleClose ( event ) ;
121
143
break ;
122
144
default :
123
145
}
@@ -128,19 +150,13 @@ class Dropdown extends React.Component {
128
150
return ;
129
151
}
130
152
131
- // we need to let the current event finish before closing the menu.
132
- // otherwise the menu may close, shifting focus to document.body, before focus has moved
133
- // to the next focusable input
134
- if ( event && event . keyCode === keycode . codes . tab ) {
135
- setTimeout ( this . toggleOpen ) ;
136
- } else {
137
- this . toggleOpen ( ) ;
138
- }
153
+ this . toggleOpen ( ) ;
154
+ }
139
155
140
- if ( event && event . type === 'keydown' && event . keyCode === keycode . codes . esc ) {
141
- let toggle = React . findDOMNode ( this . refs [ TOGGLE_REF ] ) ;
142
- event . preventDefault ( ) ;
143
- event . stopPropagation ( ) ;
156
+ focus ( ) {
157
+ let toggle = React . findDOMNode ( this . refs [ TOGGLE_REF ] ) ;
158
+
159
+ if ( toggle && toggle . focus ) {
144
160
toggle . focus ( ) ;
145
161
}
146
162
}
@@ -149,7 +165,7 @@ class Dropdown extends React.Component {
149
165
let open = ! ! this . props . open ;
150
166
let seen = { } ;
151
167
152
- return React . Children . map ( this . props . children , child => {
168
+ return ValidComponentChildren . map ( this . props . children , child => {
153
169
let extractor = find ( this . childExtractors , x => x . matches ( child ) ) ;
154
170
155
171
if ( extractor ) {
0 commit comments