Skip to content

Commit 39cc255

Browse files
committed
fix: Trigger onFocus/onBlur
1 parent 0b8d9b7 commit 39cc255

File tree

2 files changed

+49
-23
lines changed

2 files changed

+49
-23
lines changed

src/index.js

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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(' ')}

types/react-dropdown-tree-select.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ declare module 'react-dropdown-tree-select' {
114114
searchInput: HTMLInputElement
115115
keepDropdownActive: boolean
116116
handleClick(): void
117+
_timeoutID: number
117118
}
118119

119120
export interface TreeNode {

0 commit comments

Comments
 (0)