Skip to content

Commit 5198501

Browse files
committed
Make tree more accessible and semantic
1 parent 47bd4a7 commit 5198501

File tree

9 files changed

+95
-8
lines changed

9 files changed

+95
-8
lines changed

.eslintrc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
"rules": {
55
"class-methods-use-this": 0,
66
"indent": [2, "tab"],
7-
"jsx-a11y/label-has-for": 0,
8-
"jsx-a11y/no-static-element-interactions": 0,
97
"no-tabs": 0,
108
"react/jsx-indent": [2, "tab"],
119
"react/jsx-indent-props" : [2, "tab"],

gulpfile.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ gulp.task('test-mocha', ['test-script-format'], () =>
2828
compilers: {
2929
js: babel,
3030
},
31+
require: [
32+
'./test/setup.js',
33+
],
3134
}))
3235
);
3336

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"gulp-mocha": "^3.0.1",
4646
"gulp-sass": "^3.0.0",
4747
"gulp-scss-lint": "^0.4.0",
48+
"jsdom": "^9.11.0",
4849
"mocha": "^3.0.2",
4950
"react": "^15.4.2",
5051
"react-addons-test-utils": "^15.4.2",

src/js/Tree.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22

33
import TreeNode from './TreeNode';
44
import nodeShape from './nodeShape';
5+
import uniqueDomId from './uniqueDomId';
56

67
class Tree extends React.Component {
78
static propTypes = {
@@ -38,6 +39,8 @@ class Tree extends React.Component {
3839

3940
this.onCheck = this.onCheck.bind(this);
4041
this.onExpand = this.onExpand.bind(this);
42+
43+
this.id = uniqueDomId('rct');
4144
}
4245

4346
onCheck(node) {
@@ -147,6 +150,7 @@ class Tree extends React.Component {
147150
optimisticToggle={this.props.optimisticToggle}
148151
rawChildren={node.children}
149152
title={node.title}
153+
treeId={this.id}
150154
value={node.value}
151155
onCheck={this.onCheck}
152156
onExpand={this.onExpand}

src/js/TreeNode.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class TreeNode extends React.Component {
88
expanded: React.PropTypes.bool.isRequired,
99
optimisticToggle: React.PropTypes.bool.isRequired,
1010
title: React.PropTypes.string.isRequired,
11+
treeId: React.PropTypes.string.isRequired,
1112
value: React.PropTypes.string.isRequired,
1213
onCheck: React.PropTypes.func.isRequired,
1314
onExpand: React.PropTypes.func.isRequired,
@@ -100,21 +101,25 @@ class TreeNode extends React.Component {
100101
}
101102

102103
render() {
104+
const { checked, treeId, title, value } = this.props;
105+
const inputId = `${treeId}-${value}`;
106+
103107
return (
104108
<li className="rct-node">
105109
<span className="rct-text">
106-
<span className="rct-collapse" title="Toggle" onClick={this.onExpand}>
110+
<button className="rct-collapse" title="Toggle" onClick={this.onExpand}>
107111
{this.renderCollapseIcon()}
108-
</span>
109-
<label onClick={this.onCheck}>
112+
</button>
113+
<label htmlFor={inputId}>
114+
<input checked={checked === 1} id={inputId} type="checkbox" onChange={this.onCheck} />
110115
<span className="rct-checkbox">
111116
{this.renderCheckboxIcon()}
112117
</span>
113118
<span className="rct-icon">
114119
{this.renderNodeIcon()}
115120
</span>
116121
<span className="rct-title">
117-
{this.props.title}
122+
{title}
118123
</span>
119124
</label>
120125
</span>

src/js/uniqueDomId.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
let autoId = 0;
2+
3+
/**
4+
* Return a unique DOM ID for an element on the document.
5+
*
6+
* @param {string} prefix
7+
*
8+
* @return {string}
9+
*/
10+
function uniqueDomId(prefix = 'unique') {
11+
let findingId = true;
12+
let id = '';
13+
14+
while (findingId) {
15+
id = `${prefix}-${autoId}`;
16+
17+
if (document.getElementById(id) === null) {
18+
findingId = false;
19+
}
20+
21+
autoId += 1;
22+
}
23+
24+
return id;
25+
}
26+
27+
export default uniqueDomId;

src/less/react-checkbox-tree.less

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@
1414
}
1515
}
1616

17+
button {
18+
line-height: normal;
19+
color: inherit;
20+
21+
&:focus {
22+
outline: none;
23+
}
24+
}
25+
1726
label {
1827
margin-bottom: 0;
1928
cursor: pointer;
@@ -23,6 +32,10 @@
2332
}
2433
}
2534

35+
input {
36+
display: none;
37+
}
38+
2639
.fa {
2740
margin: 0 5px;
2841
width: 14px;
@@ -41,11 +54,16 @@
4154
}
4255

4356
.rct-collapse {
57+
border: 0;
58+
background: none;
59+
cursor: pointer;
60+
padding: 0;
61+
line-height: normal;
62+
color: inherit;
4463
font-size: 12px;
4564

4665
.fa-chevron-right,
4766
.fa-chevron-down {
48-
cursor: pointer;
4967
text-align: center;
5068
}
5169

src/sass/react-checkbox-tree.scss

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ $rct-label-hover: rgba($rct-icon-color, .1) !default;
1414
}
1515
}
1616

17+
button {
18+
line-height: normal;
19+
color: inherit;
20+
21+
&:focus {
22+
outline: none;
23+
}
24+
}
25+
1726
label {
1827
margin-bottom: 0;
1928
cursor: pointer;
@@ -23,6 +32,10 @@ $rct-label-hover: rgba($rct-icon-color, .1) !default;
2332
}
2433
}
2534

35+
input {
36+
display: none;
37+
}
38+
2639
.fa {
2740
margin: 0 5px;
2841
width: 14px;
@@ -41,11 +54,16 @@ $rct-label-hover: rgba($rct-icon-color, .1) !default;
4154
}
4255

4356
.rct-collapse {
57+
border: 0;
58+
background: none;
59+
cursor: pointer;
60+
padding: 0;
61+
line-height: normal;
62+
color: inherit;
4463
font-size: 12px;
4564

4665
.fa-chevron-right,
4766
.fa-chevron-down {
48-
cursor: pointer;
4967
text-align: center;
5068
}
5169

test/setup.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { jsdom } from 'jsdom';
2+
3+
global.document = jsdom('');
4+
global.window = document.defaultView;
5+
Object.keys(document.defaultView).forEach((property) => {
6+
if (typeof global[property] === 'undefined') {
7+
global[property] = document.defaultView[property];
8+
}
9+
});
10+
11+
global.navigator = {
12+
userAgent: 'node.js',
13+
};

0 commit comments

Comments
 (0)