Skip to content

Commit 4b411b7

Browse files
committed
Add support for onlyLeafCheckboxes and showCheckbox properties
Resolves #80.
1 parent d57883e commit 4b411b7

File tree

12 files changed

+298
-54
lines changed

12 files changed

+298
-54
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
### New Features
66

77
* [#53]: Add `nativeCheckboxes` property to allow use of native browser checkboxes instead of pseudo-checkbox icons
8-
* [#72]: Add the node that triggers `onCheck` or `onExpand` as a second parameter
8+
* [#72]: Add the node that triggers `onCheck` or `onExpand` as a second parameter to the callback functions
9+
* [#80]: Add `onlyLeafCheckboxes` property and support `showCheckbox` on the node-level
910

1011
## [v1.0.2](https://github.com/jakezatecky/react-checkbox-tree/compare/v1.0.1...v1.0.2) (2017-10-24)
1112

README.md

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,31 +89,33 @@ All node objects **must** have a unique `value`. This value is serialized into t
8989

9090
### Properties
9191

92-
| Property | Type | Description | Default |
93-
| ------------------ | -------- | ------------------------------------------------------------------------------------------------ | ----------- |
94-
| `nodes` | array | **Required**. Specifies the tree nodes and their children. | |
95-
| `checked` | array | An array of checked node values. | `[]` |
96-
| `disabled` | bool | If true, the component will be disabled and nodes cannot be checked. | `false` |
97-
| `expandDisabled` | bool | If true, the ability to expand nodes will be disabled. | `false` |
98-
| `expanded` | array | An array of expanded node values. | `[]` |
99-
| `name` | string | Optional name for the hidden `<input>` element. | `undefined` |
100-
| `nameAsArray` | bool | If true, the hidden `<input>` will encode its values as an array rather than a joined string. | `false` |
101-
| `nativeCheckboxes` | bool | If true, native browser checkboxes will be used instead of pseudo-checkbox icons. | `false` |
102-
| `noCascade` | bool | If true, toggling a parent node will **not** cascade its check state to its children. | `false` |
103-
| `optimisticToggle` | bool | If true, toggling a partially-checked node will select all children. If false, it will deselect. | `true` |
104-
| `showNodeIcon` | bool | If true, each node will show a parent or leaf icon. | `true` |
105-
| `onCheck` | function | onCheck handler: `function(checked) {}` | `() => {}` |
106-
| `onExpand` | function | onExpand handler: `function(expanded) {}` | `() => {}` |
92+
| Property | Type | Description | Default |
93+
| -------------------- | -------- | ------------------------------------------------------------------------------------------------ | ----------- |
94+
| `nodes` | array | **Required**. Specifies the tree nodes and their children. | |
95+
| `checked` | array | An array of checked node values. | `[]` |
96+
| `disabled` | bool | If true, the component will be disabled and nodes cannot be checked. | `false` |
97+
| `expandDisabled` | bool | If true, the ability to expand nodes will be disabled. | `false` |
98+
| `expanded` | array | An array of expanded node values. | `[]` |
99+
| `name` | string | Optional name for the hidden `<input>` element. | `undefined` |
100+
| `nameAsArray` | bool | If true, the hidden `<input>` will encode its values as an array rather than a joined string. | `false` |
101+
| `nativeCheckboxes` | bool | If true, native browser checkboxes will be used instead of pseudo-checkbox icons. | `false` |
102+
| `noCascade` | bool | If true, toggling a parent node will **not** cascade its check state to its children. | `false` |
103+
| `onlyLeafCheckboxes` | bool | If true, checkboxes will only be shown for leaf nodes. | `false` |
104+
| `optimisticToggle` | bool | If true, toggling a partially-checked node will select all children. If false, it will deselect. | `true` |
105+
| `showNodeIcon` | bool | If true, each node will show a parent or leaf icon. | `true` |
106+
| `onCheck` | function | onCheck handler: `function(checked) {}` | `() => {}` |
107+
| `onExpand` | function | onExpand handler: `function(expanded) {}` | `() => {}` |
107108

108109
#### Node Properties
109110

110111
Individual nodes within the `nodes` property can have the following structure:
111112

112-
| Property | Type | Description |
113-
| ----------- | ------ | ------------------------------------ |
114-
| `label` | mixed | **Required**. The node's label. |
115-
| `value` | mixed | **Required**. The node's value. |
116-
| `children` | array | An array of child nodes. |
117-
| `className` | string | A className to add to the node. |
118-
| `disabled` | bool | Whether the node should be disabled. |
119-
| `icon` | mixed | A custom icon for the node. |
113+
| Property | Type | Description | Default |
114+
| -------------- | ------ | ---------------------------------------- | ------- |
115+
| `label` | mixed | **Required**. The node's label. | |
116+
| `value` | mixed | **Required**. The node's value. | |
117+
| `children` | array | An array of child nodes. | `null` |
118+
| `className` | string | A className to add to the node. | `null` |
119+
| `disabled` | bool | Whether the node should be disabled. | `false` |
120+
| `icon` | mixed | A custom icon for the node. | `null` |
121+
| `showCheckbox` | bool | Whether the node should show a checkbox. | `true` |

examples/src/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ <h2>Pessimistic Toggle Example</h2>
5252
</p>
5353
<div id="pessimistic-toggle-example"></div>
5454

55+
<h2>Hide Checkboxes Example</h2>
56+
<p>
57+
Checkboxes can be hidden on a node-level by setting <code>showCheckbox: false</code> for any given node. They
58+
can also be more broadly hidden by the passing the <code>onlyLeafCheckboxes</code> property, which will force
59+
checkboxes to render only on leaf nodes.
60+
</p>
61+
<div id="hidden-checkboxes-example"></div>
62+
5563
<h2>Large Data Example</h2>
5664
<p>The checkbox tree is capable of supporting a large number of nodes at once.</p>
5765
<div id="large-data-example"></div>

examples/src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import ReactDOM from 'react-dom';
44
import BasicExample from './js/BasicExample';
55
import CustomIconsExample from './js/CustomIconsExample';
66
import DisabledExample from './js/DisabledExample';
7+
import HiddenCheckboxesExample from './js/HiddenCheckboxesExample';
78
import NoCascadeExample from './js/NoCascadeExample';
89
import PessimisticToggleExample from './js/PessimisticToggleExample';
910
import LargeDataExample from './js/LargeDataExample';
1011

1112
ReactDOM.render(<BasicExample />, document.getElementById('basic-example'));
1213
ReactDOM.render(<CustomIconsExample />, document.getElementById('custom-icons-example'));
1314
ReactDOM.render(<DisabledExample />, document.getElementById('disabled-example'));
15+
ReactDOM.render(<HiddenCheckboxesExample />, document.getElementById('hidden-checkboxes-example'));
1416
ReactDOM.render(<NoCascadeExample />, document.getElementById('no-cascade-example'));
1517
ReactDOM.render(<PessimisticToggleExample />, document.getElementById('pessimistic-toggle-example'));
1618
ReactDOM.render(<LargeDataExample />, document.getElementById('large-data-example'));
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import React from 'react';
2+
import CheckboxTree from 'react-checkbox-tree';
3+
4+
const nodes = [
5+
{
6+
value: 'favorite-empires',
7+
label: 'Favorite Empires',
8+
children: [
9+
{
10+
value: 'classical-era',
11+
label: 'Classical Era',
12+
children: [
13+
{
14+
value: 'persian',
15+
label: 'First Persian Empire',
16+
},
17+
{
18+
value: 'qin',
19+
label: 'Qin Dynasty',
20+
},
21+
{
22+
value: 'spqr',
23+
label: 'Roman Empire',
24+
},
25+
],
26+
},
27+
{
28+
value: 'medieval-era',
29+
label: 'Medieval Era',
30+
children: [
31+
{
32+
value: 'abbasid',
33+
label: 'Abbasid Caliphate',
34+
},
35+
{
36+
value: 'byzantine',
37+
label: 'Byzantine Empire',
38+
},
39+
{
40+
value: 'holy-roman',
41+
label: 'Holy Roman Empire',
42+
},
43+
{
44+
value: 'ming',
45+
label: 'Ming Dynasty',
46+
},
47+
{
48+
value: 'mongol',
49+
label: 'Mongol Empire',
50+
},
51+
],
52+
},
53+
{
54+
value: 'modern-era',
55+
label: 'Modern Era',
56+
children: [
57+
{
58+
value: 'aztec',
59+
label: 'Aztec Empire',
60+
},
61+
{
62+
value: 'british',
63+
label: 'British Empire',
64+
},
65+
{
66+
value: 'inca',
67+
label: 'Inca Empire',
68+
},
69+
{
70+
value: 'qing',
71+
label: 'Qing Dynasty',
72+
},
73+
{
74+
value: 'russian',
75+
label: 'Russian Empire',
76+
},
77+
{
78+
value: 'spanish',
79+
label: 'Spanish Empire',
80+
},
81+
],
82+
},
83+
],
84+
},
85+
];
86+
87+
class HiddenCheckboxesExample extends React.Component {
88+
constructor() {
89+
super();
90+
91+
this.state = {
92+
checked: [
93+
'persian',
94+
'spqr',
95+
'byzantine',
96+
'holy-roman',
97+
'inca',
98+
],
99+
expanded: [
100+
'favorite-empires',
101+
'classical-era',
102+
'medieval-era',
103+
],
104+
};
105+
106+
this.onCheck = this.onCheck.bind(this);
107+
this.onExpand = this.onExpand.bind(this);
108+
}
109+
110+
onCheck(checked) {
111+
this.setState({ checked });
112+
}
113+
114+
onExpand(expanded) {
115+
this.setState({ expanded });
116+
}
117+
118+
render() {
119+
const { checked, expanded } = this.state;
120+
121+
return (
122+
<CheckboxTree
123+
checked={checked}
124+
expanded={expanded}
125+
nodes={nodes}
126+
onlyLeafCheckboxes
127+
onCheck={this.onCheck}
128+
onExpand={this.onExpand}
129+
/>
130+
);
131+
}
132+
}
133+
134+
export default HiddenCheckboxesExample;

src/js/CheckboxTree.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class CheckboxTree extends React.Component {
1919
nameAsArray: PropTypes.bool,
2020
nativeCheckboxes: PropTypes.bool,
2121
noCascade: PropTypes.bool,
22+
onlyLeafCheckboxes: PropTypes.bool,
2223
optimisticToggle: PropTypes.bool,
2324
showNodeIcon: PropTypes.bool,
2425
onCheck: PropTypes.func,
@@ -34,6 +35,7 @@ class CheckboxTree extends React.Component {
3435
nameAsArray: false,
3536
nativeCheckboxes: false,
3637
noCascade: false,
38+
onlyLeafCheckboxes: false,
3739
optimisticToggle: true,
3840
showNodeIcon: true,
3941
onCheck: () => {},
@@ -84,6 +86,7 @@ class CheckboxTree extends React.Component {
8486

8587
formatted.checked = this.nodes[node.value].checked;
8688
formatted.expanded = this.nodes[node.value].expanded;
89+
formatted.showCheckbox = node.showCheckbox !== undefined ? node.showCheckbox : true;
8790

8891
if (Array.isArray(node.children) && node.children.length > 0) {
8992
formatted.children = this.getFormattedNodes(formatted.children);
@@ -203,14 +206,18 @@ class CheckboxTree extends React.Component {
203206
disabled,
204207
expandDisabled,
205208
noCascade,
209+
onlyLeafCheckboxes,
206210
optimisticToggle,
207211
showNodeIcon,
208212
} = this.props;
209213
const treeNodes = nodes.map((node) => {
210214
const key = `${node.value}`;
211215
const checked = this.getCheckState(node, noCascade);
216+
const isLeaf = node.children === null;
212217
const children = this.renderChildNodes(node);
213218
const nodeDisabled = this.getDisabledState(node, parent, disabled, noCascade);
219+
// Show checkbox only if this is a leaf node or showCheckbox is true
220+
const showCheckbox = onlyLeafCheckboxes ? isLeaf : node.showCheckbox;
214221

215222
return (
216223
<TreeNode
@@ -224,6 +231,7 @@ class CheckboxTree extends React.Component {
224231
label={node.label}
225232
optimisticToggle={optimisticToggle}
226233
rawChildren={node.children}
234+
showCheckbox={showCheckbox}
227235
showNodeIcon={showNodeIcon}
228236
treeId={this.id}
229237
value={node.value}

0 commit comments

Comments
 (0)