Skip to content

Commit ece8fe9

Browse files
committed
fix: Incremental updates (#153)
* fix: Do not toggle dropwdown on pill removal (#141) 🐛 * fix: Show partial select with empty children (#139) 🐛 * fix: Fix outside click in case of multiple dropdowns * docs: Add showDropdown prop description to readme (#152) Closes #144
1 parent c0ee452 commit ece8fe9

File tree

9 files changed

+191
-79
lines changed

9 files changed

+191
-79
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ A lightweight and fast control to render a select component that can display hie
5050
- [keepTreeOnSearch](#keeptreeonsearch)
5151
- [simpleSelect](#simpleselect)
5252
- [showPartiallySelected](#showpartiallyselected)
53+
- [showDropdown](#showDropdown)
5354
- [Styling and Customization](#styling-and-customization)
5455
- [Using default styles](#default-styles)
5556
- [Customizing with Bootstrap, Material Design styles](#customizing-styles)
@@ -287,6 +288,12 @@ Type: `bool` (default: `false`)
287288

288289
If set to true, shows checkboxes in a partial state when one, but not all of their children are selected. Allows styling of partially selected nodes as well, by using [:indeterminate](https://developer.mozilla.org/en-US/docs/Web/CSS/:indeterminate) pseudo class. Simply add desired styles to `.node.partial .checkbox-item:indeterminate { ... }` in your CSS.
289290

291+
### showDropdown
292+
293+
Type: `bool` (default: `false`)
294+
295+
If set to true, shows the dropdown when rendered. This can be used to render the component with the dropdown open as its initial state.
296+
290297
## Styling and Customization
291298

292299
### Default styles

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.

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class DropdownTreeSelect extends Component {
100100
}
101101

102102
handleOutsideClick = e => {
103-
if (!isOutsideClick(e)) {
103+
if (!isOutsideClick(e, this.props.className)) {
104104
return
105105
}
106106

src/tag/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ class Tag extends PureComponent {
1313
onDelete: PropTypes.func
1414
}
1515

16-
handleClick = () => {
16+
handleClick = e => {
1717
const { id, onDelete } = this.props
18-
18+
e.stopPropagation()
19+
e.nativeEvent.stopImmediatePropagation()
1920
onDelete(id)
2021
}
2122

src/tag/index.test.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,33 @@ import toJson from 'enzyme-to-json'
66

77
import Tag from './index'
88

9+
const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => {} } }
10+
911
test('renders label when passed in', t => {
1012
const wrapper = toJson(shallow(<Tag label="hello" id="abc" />))
1113
t.snapshot(wrapper)
1214
})
1315

16+
test('call stopPropagation and stopImmediatePropagation when pill is closed', t => {
17+
const onDelete = spy()
18+
const wrapper = mount(<Tag label="hello" id="abc" onDelete={onDelete} />)
19+
const event = {
20+
type: 'click',
21+
stopPropagation: spy(),
22+
nativeEvent: {
23+
stopImmediatePropagation: spy()
24+
}
25+
}
26+
wrapper.find('.tag-remove').prop('onClick')(event)
27+
t.true(event.stopPropagation.called)
28+
t.true(event.nativeEvent.stopImmediatePropagation.called)
29+
})
30+
31+
1432
test('call onDelete handler when pill is closed', t => {
1533
const onDelete = spy()
1634
const wrapper = mount(<Tag label="hello" id="abc" onDelete={onDelete} />)
17-
wrapper.find('.tag-remove').simulate('click')
35+
wrapper.find('.tag-remove').simulate('click', nativeEvent)
1836
t.true(onDelete.calledWith('abc'))
1937
})
2038

@@ -24,6 +42,6 @@ test('should not cause form submit', t => {
2442
const wrapper = mount(<form onSubmit={onSubmit}>
2543
<Tag label="hello" id="abc" onDelete={onDelete} />
2644
</form>)
27-
wrapper.find('.tag-remove').simulate('click')
45+
wrapper.find('.tag-remove').simulate('click', nativeEvent)
2846
t.false(onSubmit.called)
2947
})

src/tree-manager/flatten-tree.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import getPartialState from './getPartialState'
22

3+
import { isEmpty } from '../utils'
4+
35
/**
46
* Converts a nested node into an associative array with pointers to child and parent nodes
57
* Given:
@@ -159,7 +161,7 @@ function walkNodes({ nodes, list = new Map(), parent, depth = 0, simple, showPar
159161
node.partial = getPartialState(node)
160162

161163
// re-check if all children are checked. if so, check thyself
162-
if (node.children.every(c => c.checked)) {
164+
if (!isEmpty(node.children) && node.children.every(c => c.checked)) {
163165
node.checked = true
164166
}
165167
}

src/tree-manager/tests/flatten-tree.test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,56 @@ test('sets default values', t => {
347347
t.deepEqual(defaultValues, expectedDefaultValues)
348348
t.deepEqual(mapToObject(list), expectedTree)
349349
})
350+
351+
test('does not check parent with empty children when showing partial state', t => {
352+
const tree = [
353+
{
354+
name: 'item1',
355+
value: 'value1',
356+
children: []
357+
},
358+
{
359+
name: 'item2',
360+
value: 'value2',
361+
children: []
362+
},
363+
{
364+
name: 'item3',
365+
value: 'value3',
366+
children: []
367+
}
368+
]
369+
370+
const expectedTree = {
371+
0: {
372+
_id: '0',
373+
_children: [],
374+
_depth: 0,
375+
children: undefined,
376+
name: 'item1',
377+
value: 'value1',
378+
partial: false
379+
},
380+
1: {
381+
_id: '1',
382+
_children: [],
383+
_depth: 0,
384+
children: undefined,
385+
name: 'item2',
386+
value: 'value2',
387+
partial: false
388+
},
389+
2: {
390+
_id: '2',
391+
_children: [],
392+
_depth: 0,
393+
children: undefined,
394+
name: 'item3',
395+
value: 'value3',
396+
partial: false
397+
},
398+
}
399+
400+
const { list } = flattenTree(tree, false, true)
401+
t.deepEqual(mapToObject(list), expectedTree)
402+
})

src/utils/isOutsideClick.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const getPath = e => {
1212
return path
1313
}
1414

15-
export default e => {
15+
export default (e, className) => {
1616
if (!(e instanceof Event)) return false
17-
return !getPath(e).some(node => node.className && node.className.indexOf('react-dropdown-tree-select') >= 0)
17+
const completeClassName = className ? `${className} react-dropdown-tree-select` : 'react-dropdown-tree-select'
18+
return !getPath(e).some(node => node.className && node.className.indexOf(completeClassName) >= 0)
1819
}

0 commit comments

Comments
 (0)