@@ -64,6 +64,7 @@ class DropdownTreeSelect extends Component {
6464 this . state = {
6565 searchModeOn : false ,
6666 currentFocus : undefined ,
67+ isManagingFocus : false ,
6768 }
6869 this . clientId = props . id || clientIdGenerator . get ( this )
6970 }
@@ -106,40 +107,59 @@ class DropdownTreeSelect extends Component {
106107 }
107108
108109 componentWillUnmount ( ) {
109- document . removeEventListener ( 'click' , this . handleOutsideClick , false )
110+ document . removeEventListener ( 'click' , this . handleDropdownCollapse , false )
110111 }
111112
112113 componentWillReceiveProps ( nextProps ) {
113114 this . initNewProps ( nextProps )
114115 }
115116
117+ onBlur = ( ) => {
118+ // setTimeout runs afterwards in the event.
119+ // If onFocus is triggered immediately in a child component, clearTimeout will stop setTimeout to run.
120+ this . _timeoutID = setTimeout ( ( ) => {
121+ if ( this . state . isManagingFocus ) {
122+ this . props . onBlur ( )
123+ this . setState ( {
124+ isManagingFocus : false ,
125+ } )
126+ }
127+ } , 0 )
128+ }
129+
130+ onFocus = ( ) => {
131+ clearTimeout ( this . _timeoutID )
132+ if ( ! this . state . isManagingFocus ) {
133+ this . props . onFocus ( )
134+ this . setState ( {
135+ isManagingFocus : true ,
136+ } )
137+ }
138+ }
139+
116140 handleClick = ( e , callback ) => {
117141 this . setState ( prevState => {
118142 // keep dropdown active when typing in search box
119143 const showDropdown = this . props . showDropdown === 'always' || this . keepDropdownActive || ! prevState . showDropdown
120144
121- // register event listeners only if there is a state change
122- if ( showDropdown !== prevState . showDropdown ) {
123- if ( showDropdown ) {
124- document . addEventListener ( 'click' , this . handleOutsideClick , false )
125- } else {
126- document . removeEventListener ( 'click' , this . handleOutsideClick , false )
127- }
145+ const searchStateReset = ! showDropdown ? this . resetSearchState ( ) : { }
146+ // adds event listener for collapsing the dropdown
147+ if ( this . state . isManagingFocus && this . props . showDropdown !== 'always' ) {
148+ document . addEventListener ( 'click' , this . handleDropdownCollapse , false )
128149 }
129150
130- if ( showDropdown ) this . props . onFocus ( )
131- else this . props . onBlur ( )
132-
133- return ! showDropdown ? { showDropdown , ... this . resetSearchState ( ) } : { showDropdown }
151+ return {
152+ showDropdown ,
153+ searchStateReset ,
154+ }
134155 } , callback )
135156 }
136157
137- handleOutsideClick = e => {
138- if ( this . props . showDropdown === 'always' || ! isOutsideClick ( e , this . node ) ) {
139- return
140- }
141-
142- this . handleClick ( )
158+ handleDropdownCollapse = e => {
159+ if ( ! isOutsideClick ( e , this . node ) ) return
160+ document . removeEventListener ( 'click' , this . handleDropdownCollapse , false )
161+ const showDropdown = this . props . showDropdown === 'always'
162+ this . setState ( { showDropdown : showDropdown } )
143163 }
144164
145165 onInputChange = value => {
@@ -157,12 +177,15 @@ class DropdownTreeSelect extends Component {
157177 } )
158178 }
159179
160- onTagRemove = ( id , isKeyboardEvent ) => {
180+ onTagRemove = id => {
161181 const { tags : prevTags } = this . state
162182 this . onCheckboxChange ( id , false , tags => {
163- if ( ! isKeyboardEvent ) return
164-
165- keyboardNavigation . getNextFocusAfterTagDelete ( id , prevTags , tags , this . searchInput ) . focus ( )
183+ const nextFocus = keyboardNavigation . getNextFocusAfterTagDelete ( id , prevTags , tags , this . searchInput )
184+ if ( nextFocus ) {
185+ nextFocus . focus ( )
186+ } else {
187+ this . onBlur ( )
188+ }
166189 } )
167190 }
168191
@@ -201,7 +224,7 @@ class DropdownTreeSelect extends Component {
201224 }
202225
203226 if ( isSingleSelect && ! showDropdown ) {
204- document . removeEventListener ( 'click' , this . handleOutsideClick , false )
227+ document . removeEventListener ( 'click' , this . handleDropdownCollapse , false )
205228 }
206229
207230 keyboardNavigation . adjustFocusedProps ( currentFocusNode , node )
@@ -311,6 +334,8 @@ class DropdownTreeSelect extends Component {
311334 return (
312335 < div
313336 id = { this . clientId }
337+ onBlur = { this . onBlur }
338+ onFocus = { this . onFocus }
314339 className = { [ this . props . className && this . props . className , 'react-dropdown-tree-select' ]
315340 . filter ( Boolean )
316341 . join ( ' ' ) }
0 commit comments