Skip to content

Commit

Permalink
feat: Added support for single select in tree dropdown (#217)
Browse files Browse the repository at this point in the history
## What does it do?

Adds support for single select in the tree dropdown. Simple select ignores any children so this is a hybrid between the two.

Also ignores clicks for simple select when labels are disabled (only checked readonly)

The middle dropdown is radioSelect and the last one a simpleSelect
https://ellinge.github.io/react-dropdown-tree-select-test/#DevelopTemp-checkeddefault

Fixes #119 

## Type of change
- [x] Bug fix
- [x] New feature
  • Loading branch information
ellinge authored and mrchief committed Apr 18, 2019
1 parent d7604e7 commit 85b07ea
Show file tree
Hide file tree
Showing 25 changed files with 538 additions and 135 deletions.
6 changes: 6 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ plugins:
eslint:
enabled: true
channel: 'eslint-5'
duplication:
enabled: true
config:
languages:
javascript:
mass_threshold : 50
exclude_patterns:
- 'docs/'
- 'snapshots/'
Expand Down
50 changes: 37 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ A lightweight and fast control to render a select component that can display hie
- [noMatchesText](#nomatchestext)
- [keepTreeOnSearch](#keeptreeonsearch)
- [keepChildrenOnSearch](#keepchildrenonsearch)
- [keepOpenOnSelect](#keepopenonselect)
- [simpleSelect](#simpleselect)
- [radioSelect](#radioSelect)
- [showPartiallySelected](#showpartiallyselected)
- [showDropdown](#showDropdown)
- [form states (disabled|readOnly)](#formstates)
Expand Down Expand Up @@ -142,11 +144,11 @@ const data = {
children: [
{
label: 'No one can get me',
value: 'anonymous'
}
]
}
]
value: 'anonymous',
},
],
},
],
}

const onChange = (currentNode, selectedNodes) => {
Expand All @@ -159,7 +161,10 @@ const onNodeToggle = currentNode => {
console.log('onNodeToggle::', currentNode)
}

ReactDOM.render(<DropdownTreeSelect data={data} onChange={onChange} onAction={onAction} onNodeToggle={onNodeToggle} />, document.body) // in real world, you'd want to render to an element, instead of body.
ReactDOM.render(
<DropdownTreeSelect data={data} onChange={onChange} onAction={onAction} onNodeToggle={onNodeToggle} />,
document.body
) // in real world, you'd want to render to an element, instead of body.
```

## Props
Expand Down Expand Up @@ -219,7 +224,7 @@ Type: `function`
Fires when a action is triggered. Example:

```jsx
function onAction({action, id}) {
function onAction({ action, id }) {
console.log(`onAction:: [${action}]`, id)
}

Expand Down Expand Up @@ -298,14 +303,32 @@ Type: `bool`

Displays children of found nodes to allow searching for a parent node on then selecting any child node of the found node. Defaults to `false`

*NOTE* this works only in combination with `keepTreeOnSearch`
_NOTE_ this works only in combination with `keepTreeOnSearch`

### keepOpenOnSelect

Type: `bool` (default: 'false')

Keeps single selects open after selection. Defaults to `false`

_NOTE_ this works only in combination with `simpleSelect` or `radioSelect`

### simpleSelect

Type: `bool` (default: `false`)

Turns the dropdown into a simple, single select dropdown. If you pass tree data, only immediate children are picked, grandchildren nodes are ignored. Defaults to `false`.

_NOTE_ if multiple nodes in data are selected, `checked` or `isDefaultValue`, only the first visited node is selected

### radioSelect

Type: `bool` (default: `false`)

Turns the dropdown into radio select dropdown. Similar to simpleSelect but keeps tree/children. Defaults to `false`.

_NOTE_ if multiple nodes in data are selected, `checked` or `isDefaultValue`, only the first visited node is selected

### showPartiallySelected

Type: `bool` (default: `false`)
Expand Down Expand Up @@ -353,12 +376,12 @@ module: {
fallback: 'style-loader',
use: [
{
loader: 'css-loader'
}
]
loader: 'css-loader',
},
],
}),
include: /node_modules[/\\]react-dropdown-tree-select/
}
include: /node_modules[/\\]react-dropdown-tree-select/,
},
]
}
```
Expand Down Expand Up @@ -512,6 +535,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
| [<img src="https://avatars1.githubusercontent.com/u/13344028?v=4" width="100px;" alt="BaarishRain"/><br /><sub><b>BaarishRain</b></sub>](https://github.com/BaarishRain)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3ABaarishRain "Bug reports") | [<img src="https://avatars0.githubusercontent.com/u/32507174?v=4" width="100px;" alt="Kovacs Alexandru Robert"/><br /><sub><b>Kovacs Alexandru Robert</b></sub>](http://kovacsalexandrurobert.ro)<br />[🤔](#ideas-akovacspentalog "Ideas, Planning, & Feedback") | [<img src="https://avatars2.githubusercontent.com/u/11201133?v=4" width="100px;" alt="Alexis Mondragon"/><br /><sub><b>Alexis Mondragon</b></sub>](https://github.com/amondragon)<br />[🤔](#ideas-amondragon "Ideas, Planning, & Feedback") | [<img src="https://avatars2.githubusercontent.com/u/13438795?v=4" width="100px;" alt="Charlie91"/><br /><sub><b>Charlie91</b></sub>](https://github.com/Charlie91)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3ACharlie91 "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/1930681?v=4" width="100px;" alt="Dhirendrasinh"/><br /><sub><b>Dhirendrasinh</b></sub>](https://github.com/dhirendrarathod2000)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3Adhirendrarathod2000 "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/7006862?v=4" width="100px;" alt="JKapostins"/><br /><sub><b>JKapostins</b></sub>](https://github.com/JKapostins)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3AJKapostins "Bug reports") | [<img src="https://avatars0.githubusercontent.com/u/24354568?v=4" width="100px;" alt="josvegit"/><br /><sub><b>josvegit</b></sub>](https://github.com/josvegit)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3Ajosvegit "Bug reports") |
| [<img src="https://avatars1.githubusercontent.com/u/12422912?v=4" width="100px;" alt="Luis Locon"/><br /><sub><b>Luis Locon</b></sub>](https://twitter.com/LoconLuis)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3Aloconluis "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/10121255?v=4" width="100px;" alt="Mikdat DOĞRU"/><br /><sub><b>Mikdat DOĞRU</b></sub>](https://github.com/mikdatdogru)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3Amikdatdogru "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/7553535?v=4" width="100px;" alt="Will Izard"/><br /><sub><b>Will Izard</b></sub>](https://github.com/will-izard)<br />[🤔](#ideas-will-izard "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/4504265?v=4" width="100px;" alt="Nikola Peric"/><br /><sub><b>Nikola Peric</b></sub>](https://gitlab.com/nikperic)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3Anikolap "Bug reports") | [<img src="https://avatars2.githubusercontent.com/u/6119839?v=4" width="100px;" alt="Ramón Alejandro Reyes Fajardo"/><br /><sub><b>Ramón Alejandro Reyes Fajardo</b></sub>](https://github.com/ramonrf)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3Aramonrf "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/10716099?v=4" width="100px;" alt="Sarada Cherukupalli"/><br /><sub><b>Sarada Cherukupalli</b></sub>](https://github.com/sarada-Cheukupalli)<br />[🤔](#ideas-sarada-Cheukupalli "Ideas, Planning, & Feedback") | [<img src="https://avatars1.githubusercontent.com/u/45608461?v=4" width="100px;" alt="Dilip Gavara"/><br /><sub><b>Dilip Gavara</b></sub>](https://github.com/dilip025)<br />[💻](https://github.com/dowjones/react-dropdown-tree-select/commits?author=dilip025 "Code") |
| [<img src="https://avatars3.githubusercontent.com/u/491877?v=4" width="100px;" alt="Lutz Lengemann"/><br /><sub><b>Lutz Lengemann</b></sub>](http://www.dealzeit.de)<br />[💻](https://github.com/dowjones/react-dropdown-tree-select/commits?author=mobilutz "Code") | [<img src="https://avatars0.githubusercontent.com/u/26381655?v=4" width="100px;" alt="Akshay Dipta"/><br /><sub><b>Akshay Dipta</b></sub>](https://github.com/Eainde)<br />[🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3AEainde "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/137158?v=4" width="100px;" alt="Ian Langworth ☠"/><br /><sub><b>Ian Langworth ☠</b></sub>](https://langworth.com/)<br />[🤔](#ideas-statico "Ideas, Planning, & Feedback") | [<img src="https://avatars1.githubusercontent.com/u/5932031?v=4" width="100px;" alt="Stoyan Berov"/><br /><sub><b>Stoyan Berov</b></sub>](https://github.com/stoberov)<br />[💻](https://github.com/dowjones/react-dropdown-tree-select/commits?author=stoberov "Code") [🐛](https://github.com/dowjones/react-dropdown-tree-select/issues?q=author%3Astoberov "Bug reports") | [<img src="https://avatars0.githubusercontent.com/u/17863113?v=4" width="100px;" alt="ellinge"/><br /><sub><b>ellinge</b></sub>](https://github.com/ellinge)<br />[💻](https://github.com/dowjones/react-dropdown-tree-select/commits?author=ellinge "Code") [🤔](#ideas-ellinge "Ideas, Planning, & Feedback") [🚧](#maintenance-ellinge "Maintenance") |

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
2 changes: 0 additions & 2 deletions __snapshots__/src/checkbox/index.test.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Generated by [AVA](https://ava.li).
<input
className="sample"
onChange={Function {}}
type="checkbox"
/>

Expand All @@ -20,6 +19,5 @@ Generated by [AVA](https://ava.li).
<input
disabled={true}
onChange={Function {}}
type="checkbox"
/>
Binary file modified __snapshots__/src/checkbox/index.test.js.snap
Binary file not shown.
115 changes: 115 additions & 0 deletions __snapshots__/src/index.test.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,120 @@ Generated by [AVA](https://ava.li).
</div>
</div>

## renders default radio select state

> Snapshot 1
<DropdownTreeSelect
data={
[
{
children: [
{
children: [
{
label: 'item1-1-1',
value: 'value1-1-1',
},
{
label: 'item1-1-2',
value: 'value1-1-2',
},
],
label: 'item1-1',
value: 'value1-1',
},
{
label: 'item1-2',
value: 'value1-2',
},
],
label: 'item1',
value: 'value1',
},
{
children: [
{
children: [
{
label: 'item2-1-1',
value: 'value2-1-1',
},
{
label: 'item2-1-2',
value: 'value2-1-2',
},
{
children: [
{
label: 'item2-1-3-1',
value: 'value2-1-3-1',
},
],
label: 'item2-1-3',
value: 'value2-1-3',
},
],
label: 'item2-1',
value: 'value2-1',
},
{
label: 'item2-2',
value: 'value2-2',
},
],
label: 'item2',
value: 'value2',
},
]
}
id="rdts"
onBlur={Function onBlur {}}
onChange={Function onChange {}}
onFocus={Function onFocus {}}
radioSelect={true}
>
<div
className="react-dropdown-tree-select"
id="rdts"
>
<div
className="dropdown radio-select"
>
<a
className="dropdown-trigger arrow bottom"
onClick={Function {}}
>
<Input
inputRef={Function inputRef {}}
onBlur={Function {}}
onFocus={Function {}}
onInputChange={Function {}}
onTagRemove={Function {}}
tags={[]}
>
<ul
className="tag-list"
>
<li
className="tag-item"
>
<input
className="search"
onBlur={Function {}}
onChange={Function {}}
onFocus={Function {}}
placeholder="Choose..."
type="text"
/>
</li>
</ul>
</Input>
</a>
</div>
</div>
</DropdownTreeSelect>

## renders default state

> Snapshot 1
Expand Down Expand Up @@ -173,6 +287,7 @@ Generated by [AVA](https://ava.li).
className="dropdown-content"
>
<Tree
clientId="rdts"
data={
Map {
'rdts-0' => {
Expand Down
Binary file modified __snapshots__/src/index.test.js.snap
Binary file not shown.
25 changes: 25 additions & 0 deletions __snapshots__/src/radio/index.test.js.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Snapshot report for `src\radio\index.test.js`

The actual snapshot is saved in `index.test.js.snap`.

Generated by [AVA](https://ava.li).

## Radio component

> Snapshot 1
<input
className="sample"
name="sample"
type="radio"
/>

## renders disabled state

> Snapshot 1
<input
disabled={true}
name="sample"
type="radio"
/>
Binary file added __snapshots__/src/radio/index.test.js.snap
Binary file not shown.
14 changes: 14 additions & 0 deletions docs/src/stories/Options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class WithOptions extends PureComponent {
this.state = {
clearSearchOnChange: false,
keepTreeOnSearch: false,
keepOpenOnSelect: false,
simpleSelect: false,
radioSelect: false,
showPartiallySelected: false,
disabled: false,
readOnly: false,
Expand All @@ -39,7 +41,9 @@ class WithOptions extends PureComponent {
const {
clearSearchOnChange,
keepTreeOnSearch,
keepOpenOnSelect,
simpleSelect,
radioSelect,
showPartiallySelected,
disabled,
readOnly,
Expand Down Expand Up @@ -70,7 +74,14 @@ class WithOptions extends PureComponent {
checked={keepTreeOnSearch}
onChange={this.onOptionsChange}
/>
<Checkbox
label="Keep tree open on select"
value="keepOpenOnSelect"
checked={keepOpenOnSelect}
onChange={this.onOptionsChange}
/>
<Checkbox label="Simple Select" value="simpleSelect" checked={simpleSelect} onChange={this.onOptionsChange} />
<Checkbox label="Radio Select" value="radioSelect" checked={radioSelect} onChange={this.onOptionsChange} />
<Checkbox
label="Show Partially Selected"
value="showPartiallySelected"
Expand All @@ -83,13 +94,16 @@ class WithOptions extends PureComponent {
</div>
<div>
<DropdownTreeSelect
id="rdts"
data={data}
onChange={this.onChange}
onAction={this.onAction}
onNodeToggle={this.onNodeToggle}
clearSearchOnChange={clearSearchOnChange}
keepTreeOnSearch={keepTreeOnSearch}
keepOpenOnSelect={keepOpenOnSelect}
simpleSelect={simpleSelect}
radioSelect={radioSelect}
showPartiallySelected={showPartiallySelected}
disabled={disabled}
readOnly={readOnly}
Expand Down
11 changes: 1 addition & 10 deletions src/checkbox/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,6 @@ class Checkbox extends PureComponent {
readOnly: PropTypes.bool,
}

// this (stopPropagation) is needed since FireFox wrongly detects inside clicks
// See https://github.com/dowjones/react-dropdown-tree-select/pull/154
// and https://github.com/dowjones/react-dropdown-tree-select/issues/148
handleChange = e => {
e.stopPropagation()
e.nativeEvent.stopImmediatePropagation()
this.props.onChange(e)
}

render() {
const { checked, indeterminate = false, onChange, disabled, readOnly, ...rest } = this.props

Expand All @@ -35,7 +26,7 @@ class Checkbox extends PureComponent {
<input
type="checkbox"
ref={refUpdater({ checked, indeterminate })}
onChange={this.handleChange}
onChange={onChange}
disabled={isDisabled}
{...rest}
/>
Expand Down
14 changes: 0 additions & 14 deletions src/checkbox/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { shallow } from 'enzyme'
import React from 'react'
import test from 'ava'
import toJson from 'enzyme-to-json'
import { spy } from 'sinon'

import Checkbox, { refUpdater } from './index'

Expand All @@ -27,16 +26,3 @@ test('renders disabled state', t => {
const tree = toJson(shallow(<Checkbox disabled />))
t.snapshot(tree)
})

test('call stopPropagation and stopImmediatePropagation when clicked', t => {
const onChange = spy()
const wrapper = shallow(<Checkbox className="sample" onChange={onChange} />)
const event = {
stopPropagation: spy(),
nativeEvent: { stopImmediatePropagation: spy() },
}
wrapper.simulate('change', event)
t.true(onChange.called)
t.true(event.stopPropagation.called)
t.true(event.nativeEvent.stopImmediatePropagation.called)
})
Loading

0 comments on commit 85b07ea

Please sign in to comment.