Skip to content

Commit c801e60

Browse files
authored
feat: Expose focus, blur events ✨ (#124)
1 parent 09067f0 commit c801e60

File tree

7 files changed

+80
-66
lines changed

7 files changed

+80
-66
lines changed

README.md

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
[travis-url]: https://travis-ci.org/dowjones/react-dropdown-tree-select
1313
[coveralls-image]: https://img.shields.io/coveralls/dowjones/react-dropdown-tree-select.svg?style=flat-square
1414
[coveralls-url]: https://coveralls.io/r/dowjones/react-dropdown-tree-select?branch=master
15-
[download-image]: https://img.shields.io/npm/dm/react-dropdown-tree-select.svg?style=flat-square
15+
[download-image]: https://img.shields.io/npm/dt/react-dropdown-tree-select.svg?style=flat-square
1616
[semantic-release]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square
1717
[semantic-release-url]: https://github.com/semantic-release/semantic-release
1818
[commitizen]: https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square
@@ -28,40 +28,40 @@ A lightweight and fast control to render a select component that can display hie
2828

2929
## Table of Contents
3030

31-
* [Screenshot](#screenshot)
32-
* [Demo](#example)
33-
* [Vanilla (no framework)](#vanilla-no-framework)
34-
* [With Bootstrap](#with-bootstrap)
35-
* [With Material Design](#with-material-design)
36-
* [As Single Select](#as-single-select)
37-
* [Install](#install)
38-
* [As NPM package](#as-npm-package)
39-
* [Using a CDN](#using-a-cdn)
40-
* [Peer Dependencies](#peer-dependencies)
41-
* [Usage](#usage)
42-
* [Props](#props)
43-
* [className](#classname)
44-
* [clearSearchOnChange](#clearsearchonchange)
45-
* [onChange](#onchange)
46-
* [onNodeToggle](#onnodetoggle)
47-
* [data](#data)
48-
* [placeholderText](#placeholdertext)
49-
* [noMatchesText](#nomatchestext)
50-
* [keepTreeOnSearch](#keeptreeonsearch)
51-
* [simpleSelect](#simpleselect)
52-
* [showPartiallySelected](#showpartiallyselected)
53-
* [Styling and Customization](#styling-and-customization)
54-
* [Using default styles](#default-styles)
55-
* [Customizing with Bootstrap, Material Design styles](#customizing-styles)
56-
* [Performance](#performance)
57-
* [Search optimizations](#search-optimizations)
58-
* [Search debouncing](#search-debouncing)
59-
* [Virtualized rendering](#virtualized-rendering)
60-
* [Reducing costly DOM manipulations](#reducing-costly-dom-manipulations)
61-
* [FAQ](#faq)
62-
* [Doing more with HOCs](/docs/HOC.md)
63-
* [Development](#development)
64-
* [License](#license)
31+
- [Screenshot](#screenshot)
32+
- [Demo](#example)
33+
- [Vanilla (no framework)](#vanilla-no-framework)
34+
- [With Bootstrap](#with-bootstrap)
35+
- [With Material Design](#with-material-design)
36+
- [As Single Select](#as-single-select)
37+
- [Install](#install)
38+
- [As NPM package](#as-npm-package)
39+
- [Using a CDN](#using-a-cdn)
40+
- [Peer Dependencies](#peer-dependencies)
41+
- [Usage](#usage)
42+
- [Props](#props)
43+
- [className](#classname)
44+
- [clearSearchOnChange](#clearsearchonchange)
45+
- [onChange](#onchange)
46+
- [onNodeToggle](#onnodetoggle)
47+
- [data](#data)
48+
- [placeholderText](#placeholdertext)
49+
- [noMatchesText](#nomatchestext)
50+
- [keepTreeOnSearch](#keeptreeonsearch)
51+
- [simpleSelect](#simpleselect)
52+
- [showPartiallySelected](#showpartiallyselected)
53+
- [Styling and Customization](#styling-and-customization)
54+
- [Using default styles](#default-styles)
55+
- [Customizing with Bootstrap, Material Design styles](#customizing-styles)
56+
- [Performance](#performance)
57+
- [Search optimizations](#search-optimizations)
58+
- [Search debouncing](#search-debouncing)
59+
- [Virtualized rendering](#virtualized-rendering)
60+
- [Reducing costly DOM manipulations](#reducing-costly-dom-manipulations)
61+
- [FAQ](#faq)
62+
- [Doing more with HOCs](/docs/HOC.md)
63+
- [Development](#development)
64+
- [License](#license)
6565

6666
## Screenshot
6767

@@ -178,8 +178,8 @@ Type: `function`
178178

179179
Fires when a node change event occurs. Currently the following actions trigger a node change:
180180

181-
* Checkbox click which checks/unchecks the item
182-
* Closing of pill (which unchecks the corresponding checkbox item)
181+
- Checkbox click which checks/unchecks the item
182+
- Closing of pill (which unchecks the corresponding checkbox item)
183183

184184
Calls the handler with the current node object and all selected nodes (if any). Example:
185185

@@ -208,6 +208,18 @@ function onNodeToggle(currentNode) {
208208
return <DropdownTreeSelect data={data} onNodeToggle={onNodeToggle} />
209209
```
210210

211+
### onFocus
212+
213+
Type: `function`
214+
215+
Fires when input box receives focus or the dropdown arrow is clicked. This is helpful for setting `dirty` or `touched` flags with forms.
216+
217+
### onBlur
218+
219+
Type: `function`
220+
221+
Fires when input box loses focus or the dropdown arrow is clicked again (and the dropdown collapses). This is helpful for setting `dirty` or `touched` flags with forms.
222+
211223
### data
212224

213225
Type: `Object` or `Array`
@@ -323,16 +335,16 @@ You can reference the files from `node_modules/react-dropdown-tree-select/dist/s
323335

324336
Once you import default styles, it is easy to add/override the provided styles to match popular frameworks. Checkout `/docs` folder for some examples.
325337

326-
* [With Bootstrap](/docs/examples/bootstrap)
327-
* [With Material Design ](/docs/examples/material)
338+
- [With Bootstrap](/docs/examples/bootstrap)
339+
- [With Material Design ](/docs/examples/material)
328340

329341
## Performance
330342

331343
### Search optimizations
332344

333-
* The tree creates a flat list of nodes from hierarchical tree data to perform searches that are linear in time irrespective of the tree depth or size.
334-
* It also memoizes each search term, so subsequent searches are instantaneous (almost).
335-
* Last but not the least, the search employs progressive filtering technique where subsequent searches are performed on the previous search set. E.g., say the tree has 4000 nodes altogether and the user wants to filter nodes that contain the text: "2002". As the user enters each key press the search goes like this:
345+
- The tree creates a flat list of nodes from hierarchical tree data to perform searches that are linear in time irrespective of the tree depth or size.
346+
- It also memoizes each search term, so subsequent searches are instantaneous (almost).
347+
- Last but not the least, the search employs progressive filtering technique where subsequent searches are performed on the previous search set. E.g., say the tree has 4000 nodes altogether and the user wants to filter nodes that contain the text: "2002". As the user enters each key press the search goes like this:
336348

337349
```
338350
key press : 2-----20-----200-----2002

__snapshots__/src/index.test.js.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ Generated by [AVA](https://ava.li).
7171
},
7272
]
7373
}
74+
onBlur={Function onBlur {}}
75+
onChange={Function onChange {}}
76+
onFocus={Function onFocus {}}
7477
>
7578
<div
7679
className="react-dropdown-tree-select"

__snapshots__/src/index.test.js.snap

66 Bytes
Binary file not shown.

docs/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/src/stories/Simple/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ const onNodeToggle = curNode => {
1515
console.log('onNodeToggle::', curNode)
1616
}
1717

18+
const onFocus = () => {
19+
console.log('onFocus')
20+
}
21+
22+
const onBlur = () => {
23+
console.log('onBlur')
24+
}
25+
26+
1827
const Simple = () => (
1928
<div>
2029
<h1>Basic component</h1>
@@ -30,7 +39,7 @@ const Simple = () => (
3039
As a side effect, it also helps rule out issues arising out of using custom frameworks (if something doesn&apos;t look right in your app but
3140
looks OK here, you know what is messing things up).
3241
</p>
33-
<DropdownTreeSelect data={data} onChange={onChange} onAction={onAction} onNodeToggle={onNodeToggle} className="demo" />
42+
<DropdownTreeSelect data={data} onChange={onChange} onAction={onAction} onNodeToggle={onNodeToggle} onFocus={onFocus} onBlur={onBlur} className="demo" />
3443
</div>
3544
)
3645

src/index.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,19 @@ class DropdownTreeSelect extends Component {
3030
onChange: PropTypes.func,
3131
onAction: PropTypes.func,
3232
onNodeToggle: PropTypes.func,
33+
onFocus: PropTypes.func,
34+
onBlur: PropTypes.func,
3335
simpleSelect: PropTypes.bool,
3436
noMatchesText: PropTypes.string,
3537
showPartiallySelected: PropTypes.bool
3638
}
3739

40+
static defaultProps = {
41+
onFocus: () => {},
42+
onBlur: () => {},
43+
onChange: () => {}
44+
}
45+
3846
constructor(props) {
3947
super(props)
4048
this.state = {
@@ -43,10 +51,6 @@ class DropdownTreeSelect extends Component {
4351
}
4452
}
4553

46-
notifyChange = (...args) => {
47-
typeof this.props.onChange === 'function' && this.props.onChange(...args)
48-
}
49-
5054
createList = (tree, simple, showPartial) => {
5155
this.treeManager = new TreeManager(tree, simple, showPartial)
5256
return this.treeManager.tree
@@ -88,6 +92,9 @@ class DropdownTreeSelect extends Component {
8892
}
8993
}
9094

95+
if (showDropdown) this.props.onFocus()
96+
else this.props.onBlur()
97+
9198
return !showDropdown ? { showDropdown, ...this.resetSearchState() } : { showDropdown }
9299
})
93100
}
@@ -111,8 +118,6 @@ class DropdownTreeSelect extends Component {
111118
})
112119
}
113120

114-
// isOutSideClick = e =>
115-
116121
onTagRemove = id => {
117122
this.onCheckboxChange(id, false)
118123
}
@@ -148,7 +153,7 @@ class DropdownTreeSelect extends Component {
148153
}
149154

150155
this.setState(nextState)
151-
this.notifyChange(this.treeManager.getNodeById(id), tags)
156+
this.props.onChange(this.treeManager.getNodeById(id), tags)
152157
}
153158

154159
onAction = (actionId, nodeId) => {

src/index.test.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,6 @@ test('shows dropdown', t => {
6363
t.snapshot(toJson(wrapper))
6464
})
6565

66-
test('notifies on change', t => {
67-
const handler = spy()
68-
const dummyNode = {
69-
_id: '0',
70-
_parent: null,
71-
_children: ['0-0', '0-1'],
72-
label: 'item1',
73-
value: 'value1'
74-
}
75-
const { tree } = t.context
76-
const wrapper = shallow(<DropdownTreeSelect data={tree} onChange={handler} />)
77-
wrapper.instance().notifyChange(dummyNode, [dummyNode])
78-
t.true(handler.calledWithExactly(dummyNode, [dummyNode]))
79-
})
80-
8166
test('notifies on action', t => {
8267
const handler = spy()
8368
const { tree } = t.context

0 commit comments

Comments
 (0)