Skip to content

Commit 2a758ee

Browse files
committed
feat: Support disabled/readOnly states ✨ (#200)
* fix: Show cursor in Edge, IE 11 properly * feat: Support readOnly state * chore: Fix lint errors * docs: Add documentation for form states * chore: Use action's id if available, otherwise fall back to array index * test: Add tests for actions * test: Updated snapshots
1 parent a080500 commit 2a758ee

24 files changed

+182
-75
lines changed

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ A lightweight and fast control to render a select component that can display hie
4949
- [simpleSelect](#simpleselect)
5050
- [showPartiallySelected](#showpartiallyselected)
5151
- [showDropdown](#showDropdown)
52+
- [form states (disabled|readOnly)](#formstates)
5253
- [Styling and Customization](#styling-and-customization)
5354
- [Using default styles](#default-styles)
5455
- [Customizing with Bootstrap, Material Design styles](#customizing-styles)
@@ -101,7 +102,7 @@ You can import the standalone UMD build from a CDN such as:
101102

102103
```html
103104
<script src="https://unpkg.com/react-dropdown-tree-select/dist/react-dropdown-tree-select.js"></script>
104-
<link href="https://unpkg.com/react-dropdown-tree-select/dist/styles.css" rel="stylesheet">
105+
<link href="https://unpkg.com/react-dropdown-tree-select/dist/styles.css" rel="stylesheet" />
105106
```
106107

107108
**Note:** Above example will always fetch the latest version. To fetch a specific version, use `https://unpkg.com/react-dropdown-tree-select@<version>/dist/...`
@@ -292,6 +293,13 @@ Type: `bool` (default: `false`)
292293

293294
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.
294295

296+
### form states (disabled|readOnly)
297+
298+
Type: `bool` (default: `false`)
299+
300+
`disabled=true` disables the dropdown completely. This is useful during form submit events.
301+
`readOnly=true` makes the dropdown read only, which means that the user can still interact with it but cannot change any of its values. This can be useful for display only forms.
302+
295303
## Styling and Customization
296304

297305
### Default styles
@@ -327,7 +335,7 @@ module: {
327335
You can import and place a style link directly by referencing it from a CDN.
328336

329337
```html
330-
<link href="https://unpkg.com/react-dropdown-tree-select/dist/styles.css" rel="stylesheet">
338+
<link href="https://unpkg.com/react-dropdown-tree-select/dist/styles.css" rel="stylesheet" />
331339
```
332340

333341
Note: Above example will always fetch the latest version. To fetch a specific version, use `https://unpkg.com/react-dropdown-tree-select@<version>/dist/styles.css`. Visit [unpkg.com](https://unpkg.com/#/) to see other options.
@@ -470,6 +478,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
470478
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
471479
| [<img src="https://avatars1.githubusercontent.com/u/13344028?v=4" width="100px;"/><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;"/><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;"/><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;"/><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;"/><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;"/><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;"/><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") |
472480
| [<img src="https://avatars1.githubusercontent.com/u/12422912?v=4" width="100px;"/><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;"/><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;"/><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;"/><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;"/><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;"/><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;"/><br /><sub><b>Dilip Gavara</b></sub>](https://github.com/dilip025)<br />[💻](https://github.com/dowjones/react-dropdown-tree-select/commits?author=dilip025 "Code") |
481+
473482
<!-- ALL-CONTRIBUTORS-LIST:END -->
474483

475484
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

__snapshots__/src/index.test.js.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,33 @@ The actual snapshot is saved in `index.test.js.snap`.
44

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

7+
## doesn't toggle dropdown if it's disabled
8+
9+
> Snapshot 1
10+
11+
<div
12+
className="react-dropdown-tree-select"
13+
>
14+
<div
15+
className="dropdown"
16+
>
17+
<a
18+
className="dropdown-trigger arrow disabled bottom"
19+
onClick={false}
20+
>
21+
<Input
22+
disabled={true}
23+
inputRef={Function inputRef {}}
24+
onBlur={Function {}}
25+
onFocus={Function {}}
26+
onInputChange={Function {}}
27+
onTagRemove={Function {}}
28+
tags={[]}
29+
/>
30+
</a>
31+
</div>
32+
</div>
33+
734
## renders default state
835

936
> Snapshot 1
@@ -261,31 +288,4 @@ Generated by [AVA](https://ava.li).
261288
/>
262289
</div>
263290
</div>
264-
</div
265-
266-
## doesn't toggle dropdown if it's disabled
267-
268-
> Snapshot 1
269-
270-
<div
271-
className="react-dropdown-tree-select"
272-
>
273-
<div
274-
className="dropdown"
275-
>
276-
<a
277-
className="dropdown-trigger arrow disabled bottom"
278-
onClick={false}
279-
>
280-
<Input
281-
disabled={true}
282-
inputRef={Function inputRef {}}
283-
onBlur={Function {}}
284-
onFocus={Function {}}
285-
onInputChange={Function {}}
286-
onTagRemove={Function {}}
287-
tags={[]}
288-
/>
289-
</a>
290-
</div>
291-
</div>
291+
</div>

__snapshots__/src/index.test.js.snap

0 Bytes
Binary file not shown.

__snapshots__/src/input/index.test.js.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Generated by [AVA](https://ava.li).
107107
type="text"
108108
/>
109109
</li>
110-
</ul
110+
</ul>
111111

112112
## should render disabled input
113113

@@ -127,4 +127,4 @@ Generated by [AVA](https://ava.li).
127127
type="text"
128128
/>
129129
</li>
130-
</ul>
130+
</ul>
0 Bytes
Binary file not shown.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Snapshot report for `src\tree-node\actions.test.js`
2+
3+
The actual snapshot is saved in `actions.test.js.snap`.
4+
5+
Generated by [AVA](https://ava.li).
6+
7+
## renders actions
8+
9+
> Snapshot 1
10+
11+
[
12+
<Action
13+
actionData={
14+
{
15+
action: 'action-0',
16+
id: undefined,
17+
}
18+
}
19+
className="cn0-0-0"
20+
junk="1"
21+
key="action-0"
22+
onAction={Function onAction {}}
23+
text="hello"
24+
title="action"
25+
/>,
26+
]
27+
28+
## returns null if actions are empty
29+
30+
> Snapshot 1
31+
32+
''
33+
34+
> Snapshot 2
35+
36+
''
415 Bytes
Binary file not shown.

__snapshots__/src/tree-node/index.test.js.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,5 @@ Generated by [AVA](https://ava.li).
3636
]
3737
}
3838
id="0-0-0"
39-
onAction={Function onAction {}}
4039
/>
4140
</li>
-37 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/Options/data.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
"label": "VP Accounting",
44
"tagClassName": "special",
5+
"checked": true,
56
"children": [
67
{
78
"label": "iWay",

docs/src/stories/Options/index.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ class WithOptions extends PureComponent {
1515
keepTreeOnSearch: false,
1616
simpleSelect: false,
1717
showPartiallySelected: false,
18-
disabled: false
18+
disabled: false,
19+
readOnly: false
1920
}
2021
}
2122

@@ -34,7 +35,7 @@ class WithOptions extends PureComponent {
3435
}
3536

3637
render() {
37-
const { clearSearchOnChange, keepTreeOnSearch, simpleSelect, showPartiallySelected, disabled } = this.state
38+
const { clearSearchOnChange, keepTreeOnSearch, simpleSelect, showPartiallySelected, disabled, readOnly } = this.state
3839

3940
return (
4041
<div>
@@ -52,7 +53,8 @@ class WithOptions extends PureComponent {
5253
<Checkbox label="Keep tree on search" value="keepTreeOnSearch" checked={keepTreeOnSearch} onChange={this.onOptionsChange} />
5354
<Checkbox label="Simple Select" value="simpleSelect" checked={simpleSelect} onChange={this.onOptionsChange} />
5455
<Checkbox label="Show Partially Selected" value="showPartiallySelected" checked={showPartiallySelected} onChange={this.onOptionsChange} />
55-
<Checkbox label="Disable Input" value="disabled" checked={disabled} onChange={this.onOptionsChange} />
56+
<Checkbox label="Disabled" value="disabled" checked={disabled} onChange={this.onOptionsChange} />
57+
<Checkbox label="Read Only" value="readOnly" checked={readOnly} onChange={this.onOptionsChange} />
5658
</div>
5759
<div>
5860
<DropdownTreeSelect
@@ -65,6 +67,7 @@ class WithOptions extends PureComponent {
6567
simpleSelect={simpleSelect}
6668
showPartiallySelected={showPartiallySelected}
6769
disabled={disabled}
70+
readOnly={readOnly}
6871
/>
6972
</div>
7073
</div>

src/checkbox/index.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ class Checkbox extends PureComponent {
1212
static propTypes = {
1313
checked: PropTypes.bool,
1414
indeterminate: PropTypes.bool,
15-
onChange: PropTypes.func
15+
onChange: PropTypes.func,
16+
disabled: PropTypes.bool,
17+
readOnly: PropTypes.bool
1618
}
1719

1820
// this (stopPropagation) is needed since FireFox wrongly detects inside clicks
@@ -25,9 +27,11 @@ class Checkbox extends PureComponent {
2527
}
2628

2729
render() {
28-
const { checked, indeterminate = false, onChange, ...rest } = this.props
30+
const { checked, indeterminate = false, onChange, disabled, readOnly, ...rest } = this.props
2931

30-
return <input type="checkbox" ref={refUpdater({ checked, indeterminate })} onChange={this.handleChange} {...rest} />
32+
const isDisabled = disabled || readOnly
33+
34+
return <input type="checkbox" ref={refUpdater({ checked, indeterminate })} onChange={this.handleChange} disabled={isDisabled} {...rest} />
3135
}
3236
}
3337

src/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class DropdownTreeSelect extends Component {
3535
simpleSelect: PropTypes.bool,
3636
noMatchesText: PropTypes.string,
3737
showPartiallySelected: PropTypes.bool,
38-
disabled: PropTypes.bool
38+
disabled: PropTypes.bool,
39+
readOnly: PropTypes.bool
3940
}
4041

4142
static defaultProps = {
@@ -180,6 +181,7 @@ class DropdownTreeSelect extends Component {
180181
'dropdown-trigger': true,
181182
arrow: true,
182183
disabled: this.props.disabled,
184+
readOnly: this.props.readOnly,
183185
top: this.state.showDropdown,
184186
bottom: !this.state.showDropdown
185187
})
@@ -204,6 +206,7 @@ class DropdownTreeSelect extends Component {
204206
onBlur={this.onInputBlur}
205207
onTagRemove={this.onTagRemove}
206208
disabled={this.props.disabled}
209+
readOnly={this.props.readOnly}
207210
/>
208211
</a>
209212
{this.state.showDropdown && (
@@ -220,6 +223,7 @@ class DropdownTreeSelect extends Component {
220223
onNodeToggle={this.onNodeToggle}
221224
simpleSelect={this.props.simpleSelect}
222225
showPartiallySelected={this.props.showPartiallySelected}
226+
readOnly={this.props.readOnly}
223227
/>
224228
)}
225229
</div>

src/input/index.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { getDataset, debounce } from '../utils'
77

88
const cx = cn.bind(styles)
99

10-
const getTags = (tags = [], onDelete) =>
10+
const getTags = (tags = [], onDelete, readOnly) =>
1111
tags.map(tag => {
1212
const { _id, label, tagClassName, dataset } = tag
1313
return (
1414
<li className={cx('tag-item', tagClassName)} key={`tag-item-${_id}`} {...getDataset(dataset)}>
15-
<Tag label={label} id={_id} onDelete={onDelete} />
15+
<Tag label={label} id={_id} onDelete={onDelete} readOnly={readOnly} />
1616
</li>
1717
)
1818
})
@@ -26,7 +26,8 @@ class Input extends PureComponent {
2626
onBlur: PropTypes.func,
2727
onTagRemove: PropTypes.func,
2828
inputRef: PropTypes.func,
29-
disabled: PropTypes.bool
29+
disabled: PropTypes.bool,
30+
readOnly: PropTypes.bool
3031
}
3132

3233
constructor(props) {
@@ -40,11 +41,11 @@ class Input extends PureComponent {
4041
}
4142

4243
render() {
43-
const { tags, onTagRemove, inputRef, placeholderText = 'Choose...', onFocus, onBlur, disabled } = this.props
44+
const { tags, onTagRemove, inputRef, placeholderText = 'Choose...', onFocus, onBlur, disabled, readOnly } = this.props
4445

4546
return (
4647
<ul className={cx('tag-list')}>
47-
{getTags(tags, onTagRemove)}
48+
{getTags(tags, onTagRemove, readOnly)}
4849
<li className={cx('tag-item')}>
4950
<input
5051
type="text"
@@ -55,6 +56,7 @@ class Input extends PureComponent {
5556
onChange={this.handleInputChange}
5657
onFocus={onFocus}
5758
onBlur={onBlur}
59+
readOnly={readOnly}
5860
/>
5961
</li>
6062
</ul>

src/tag/index.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@
1414
background-color: transparent;
1515
border: none;
1616
outline: none;
17+
18+
&.readOnly {
19+
cursor: not-allowed;
20+
}
1721
}

src/tag/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ class Tag extends PureComponent {
1010
static propTypes = {
1111
id: PropTypes.string.isRequired,
1212
label: PropTypes.string.isRequired,
13-
onDelete: PropTypes.func
13+
onDelete: PropTypes.func,
14+
readOnly: PropTypes.bool
1415
}
1516

1617
handleClick = e => {
@@ -21,12 +22,12 @@ class Tag extends PureComponent {
2122
}
2223

2324
render() {
24-
const { label } = this.props
25+
const { label, readOnly } = this.props
2526

2627
return (
2728
<span className={cx('tag')}>
2829
{label}
29-
<button onClick={this.handleClick} className={cx('tag-remove')} type="button">
30+
<button onClick={!readOnly && this.handleClick} className={cx('tag-remove', { readOnly })} type="button">
3031
x
3132
</button>
3233
</span>

src/tree-node/action.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ class Action extends PureComponent {
77
text: PropTypes.string,
88
className: PropTypes.string,
99
actionData: PropTypes.object,
10-
onAction: PropTypes.func
10+
onAction: PropTypes.func,
11+
readOnly: PropTypes.bool
1112
}
1213

1314
static defaultProps = {
@@ -19,10 +20,10 @@ class Action extends PureComponent {
1920
}
2021

2122
render() {
22-
const { title, className, text } = this.props
23+
const { title, className, text, readOnly } = this.props
2324

2425
return (
25-
<i title={title} className={className} onClick={this.handleClick}>
26+
<i title={title} className={className} onClick={!readOnly && this.handleClick}>
2627
{text}
2728
</i>
2829
)

0 commit comments

Comments
 (0)