Skip to content

Commit bce6691

Browse files
committed
Use contexts and restructure into components folder
Also split the expand button rendering into its own component
1 parent 6a423a0 commit bce6691

File tree

9 files changed

+120
-75
lines changed

9 files changed

+120
-75
lines changed

src/js/CheckboxTree.jsx

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ import { nanoid } from 'nanoid';
55
import PropTypes from 'prop-types';
66
import React from 'react';
77

8-
import Button from './Button';
9-
import NodeModel from './NodeModel';
10-
import TreeNode from './TreeNode';
8+
import Button from './components/Button';
9+
import TreeNode from './components/TreeNode';
1110
import defaultLang from './lang/default';
1211
import iconsShape from './shapes/iconsShape';
1312
import languageShape from './shapes/languageShape';
1413
import listShape from './shapes/listShape';
1514
import nodeShape from './shapes/nodeShape';
1615
import { CHECK_MODEL, KEYS } from './constants';
16+
import { IconContext, LanguageContext } from './contexts';
17+
import NodeModel from './NodeModel';
1718

1819
class CheckboxTree extends React.Component {
1920
static propTypes = {
@@ -222,8 +223,6 @@ class CheckboxTree extends React.Component {
222223
checkKeys,
223224
expandDisabled,
224225
expandOnClick,
225-
icons,
226-
lang,
227226
noCascade,
228227
onClick,
229228
onlyLeafCheckboxes,
@@ -232,7 +231,6 @@ class CheckboxTree extends React.Component {
232231
showNodeIcon,
233232
} = this.props;
234233
const { id, model } = this.state;
235-
const { icons: defaultIcons } = CheckboxTree.defaultProps;
236234

237235
const treeNodes = nodes.map((node) => {
238236
const key = node.value;
@@ -265,11 +263,9 @@ class CheckboxTree extends React.Component {
265263
expandOnClick={expandOnClick}
266264
expanded={flatNode.expanded}
267265
icon={node.icon}
268-
icons={this.combineMemorized(defaultIcons, icons)}
269266
isLeaf={flatNode.isLeaf}
270267
isParent={flatNode.isParent}
271268
label={node.label}
272-
lang={lang}
273269
optimisticToggle={optimisticToggle}
274270
showCheckbox={showCheckbox}
275271
showNodeIcon={showNodeIcon}
@@ -293,7 +289,11 @@ class CheckboxTree extends React.Component {
293289
}
294290

295291
renderExpandAll() {
296-
const { icons: { expandAll, collapseAll }, lang, showExpandAll } = this.props;
292+
const {
293+
icons: { expandAll, collapseAll },
294+
lang,
295+
showExpandAll,
296+
} = this.props;
297297

298298
if (!showExpandAll) {
299299
return null;
@@ -351,14 +351,18 @@ class CheckboxTree extends React.Component {
351351
}
352352

353353
render() {
354+
const { icons: defaultIcons } = CheckboxTree.defaultProps;
354355
const {
355356
direction,
356357
disabled,
358+
icons,
357359
iconsClass,
360+
lang,
358361
nodes,
359362
nativeCheckboxes,
360363
} = this.props;
361364
const { id } = this.state;
365+
const mergedIcons = this.combineMemorized(defaultIcons, icons);
362366
const treeNodes = this.renderTreeNodes(nodes);
363367

364368
const className = classNames({
@@ -371,9 +375,13 @@ class CheckboxTree extends React.Component {
371375

372376
return (
373377
<div className={className} id={id}>
374-
{this.renderExpandAll()}
375-
{this.renderHiddenInput()}
376-
{treeNodes}
378+
<LanguageContext.Provider value={lang}>
379+
<IconContext.Provider value={mergedIcons}>
380+
{this.renderExpandAll()}
381+
{this.renderHiddenInput()}
382+
{treeNodes}
383+
</IconContext.Provider>
384+
</LanguageContext.Provider>
377385
</div>
378386
);
379387
}
File renamed without changes.

src/js/components/ExpandButton.jsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import PropTypes from 'prop-types';
2+
import React, { useContext } from 'react';
3+
4+
import { IconContext, LanguageContext } from '../contexts';
5+
import Button from './Button';
6+
7+
const propTypes = {
8+
disabled: PropTypes.bool.isRequired,
9+
expanded: PropTypes.bool.isRequired,
10+
isLeaf: PropTypes.bool.isRequired,
11+
onClick: PropTypes.func.isRequired,
12+
};
13+
14+
function ExpandButton({
15+
disabled,
16+
expanded,
17+
isLeaf,
18+
onClick,
19+
}) {
20+
if (isLeaf) {
21+
return (
22+
<span className="rct-collapse">
23+
<span className="rct-icon" />
24+
</span>
25+
);
26+
}
27+
28+
const icons = useContext(IconContext);
29+
const { toggle } = useContext(LanguageContext);
30+
const { expandClose, expandOpen } = icons;
31+
const collapseIcon = expanded ? expandOpen : expandClose;
32+
33+
return (
34+
<Button
35+
className="rct-collapse rct-collapse-btn"
36+
disabled={disabled}
37+
title={toggle}
38+
onClick={onClick}
39+
>
40+
{collapseIcon}
41+
</Button>
42+
);
43+
}
44+
45+
ExpandButton.propTypes = propTypes;
46+
47+
export default ExpandButton;
File renamed without changes.

src/js/TreeNode.jsx renamed to src/js/components/TreeNode.jsx

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,23 @@ import classNames from 'classnames';
22
import PropTypes from 'prop-types';
33
import React from 'react';
44

5-
import Button from './Button';
6-
import { KEYS } from './constants';
5+
import { KEYS } from '../constants';
6+
import { IconContext } from '../contexts';
7+
import ExpandButton from './ExpandButton';
78
import NativeCheckbox from './NativeCheckbox';
8-
import iconsShape from './shapes/iconsShape';
9-
import languageShape from './shapes/languageShape';
109

1110
class TreeNode extends React.PureComponent {
11+
static contextType = IconContext;
12+
1213
static propTypes = {
1314
checkKeys: PropTypes.arrayOf(PropTypes.string).isRequired,
1415
checked: PropTypes.number.isRequired,
1516
disabled: PropTypes.bool.isRequired,
1617
expandDisabled: PropTypes.bool.isRequired,
1718
expanded: PropTypes.bool.isRequired,
18-
icons: iconsShape.isRequired,
1919
isLeaf: PropTypes.bool.isRequired,
2020
isParent: PropTypes.bool.isRequired,
2121
label: PropTypes.node.isRequired,
22-
lang: languageShape.isRequired,
2322
optimisticToggle: PropTypes.bool.isRequired,
2423
showNodeIcon: PropTypes.bool.isRequired,
2524
treeId: PropTypes.string.isRequired,
@@ -130,41 +129,22 @@ class TreeNode extends React.PureComponent {
130129
return false;
131130
}
132131

133-
renderCollapseButton() {
134-
const { expandDisabled, isLeaf, lang } = this.props;
135-
136-
if (isLeaf) {
137-
return (
138-
<span className="rct-collapse">
139-
<span className="rct-icon" />
140-
</span>
141-
);
142-
}
132+
renderExpandButton() {
133+
const { expandDisabled, expanded, isLeaf } = this.props;
143134

144135
return (
145-
<Button
146-
className="rct-collapse rct-collapse-btn"
136+
<ExpandButton
147137
disabled={expandDisabled}
148-
title={lang.toggle}
138+
expanded={expanded}
139+
isLeaf={isLeaf}
149140
onClick={this.onExpand}
150-
>
151-
{this.renderCollapseIcon()}
152-
</Button>
141+
/>
153142
);
154143
}
155144

156-
renderCollapseIcon() {
157-
const { expanded, icons: { expandClose, expandOpen } } = this.props;
158-
159-
if (!expanded) {
160-
return expandClose;
161-
}
162-
163-
return expandOpen;
164-
}
165-
166145
renderCheckboxIcon() {
167-
const { checked, icons: { uncheck, check, halfCheck } } = this.props;
146+
const { uncheck, check, halfCheck } = this.context;
147+
const { checked } = this.props;
168148

169149
if (checked === 0) {
170150
return uncheck;
@@ -178,10 +158,10 @@ class TreeNode extends React.PureComponent {
178158
}
179159

180160
renderNodeIcon() {
161+
const { leaf, parentClose, parentOpen } = this.context;
181162
const {
182163
expanded,
183164
icon,
184-
icons: { leaf, parentClose, parentOpen },
185165
isLeaf,
186166
} = this.props;
187167

@@ -326,7 +306,7 @@ class TreeNode extends React.PureComponent {
326306
return (
327307
<li className={nodeClass}>
328308
<span className="rct-text">
329-
{this.renderCollapseButton()}
309+
{this.renderExpandButton()}
330310
{this.renderLabel()}
331311
</span>
332312
{this.renderChildren()}

src/js/contexts.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { createContext } from 'react';
2+
3+
const IconContext = createContext({});
4+
const LanguageContext = createContext({});
5+
6+
export {
7+
IconContext,
8+
LanguageContext,
9+
};

test/Button.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { assert } from 'chai';
33
import { render, screen } from '@testing-library/react';
44

5-
import Button from '../src/js/Button';
5+
import Button from '../src/js/components/Button';
66

77
describe('<Button />', () => {
88
describe('title', () => {

test/NativeCheckbox.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { assert } from 'chai';
33
import { render, screen } from '@testing-library/react';
44

5-
import NativeCheckbox from '../src/js/NativeCheckbox';
5+
import NativeCheckbox from '../src/js/components/NativeCheckbox';
66

77
describe('<NativeCheckbox />', () => {
88
describe('indeterminate', () => {

test/TreeNode.jsx

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,31 @@ import { fireEvent } from '@testing-library/dom';
44
import { render, screen } from '@testing-library/react';
55
import userEvent from '@testing-library/user-event';
66

7-
import TreeNode from '../src/js/TreeNode';
7+
import BaseTreeNode from '../src/js/components/TreeNode';
8+
import { IconContext, LanguageContext } from '../src/js/contexts';
9+
10+
const icons = {
11+
check: <span className="rct-icon rct-icon-check" />,
12+
uncheck: <span className="rct-icon rct-icon-uncheck" />,
13+
halfCheck: <span className="rct-icon rct-icon-half-check" />,
14+
expandClose: <span className="rct-icon rct-icon-expand-close" />,
15+
expandOpen: <span className="rct-icon rct-icon-expand-open" />,
16+
parentClose: <span className="rct-icon rct-icon-parent-close" />,
17+
parentOpen: <span className="rct-icon rct-icon-parent-open" />,
18+
leaf: <span className="rct-icon rct-icon-leaf" />,
19+
};
20+
const lang = {
21+
collapseAll: 'Collapse',
22+
expandAll: 'Expand',
23+
toggle: 'Toggle',
24+
};
825

926
const baseProps = {
1027
checkKeys: [' ', 'Enter'],
1128
checked: 0,
1229
disabled: false,
1330
expandDisabled: false,
1431
expanded: false,
15-
lang: {
16-
collapseAll: 'Collapse',
17-
expandAll: 'Expand',
18-
toggle: 'Toggle',
19-
},
20-
icons: {
21-
check: <span className="rct-icon rct-icon-check" />,
22-
uncheck: <span className="rct-icon rct-icon-uncheck" />,
23-
halfCheck: <span className="rct-icon rct-icon-half-check" />,
24-
expandClose: <span className="rct-icon rct-icon-expand-close" />,
25-
expandOpen: <span className="rct-icon rct-icon-expand-open" />,
26-
parentClose: <span className="rct-icon rct-icon-parent-close" />,
27-
parentOpen: <span className="rct-icon rct-icon-parent-open" />,
28-
leaf: <span className="rct-icon rct-icon-leaf" />,
29-
},
3032
isLeaf: true,
3133
isParent: false,
3234
label: 'Jupiter',
@@ -37,6 +39,15 @@ const baseProps = {
3739
onCheck: () => {},
3840
onExpand: () => {},
3941
};
42+
function TreeNode(props) {
43+
return (
44+
<LanguageContext.Provider value={lang}>
45+
<IconContext.Provider value={icons}>
46+
<BaseTreeNode {...props} />
47+
</IconContext.Provider>
48+
</LanguageContext.Provider>
49+
);
50+
}
4051

4152
describe('<TreeNode />', () => {
4253
describe('component', () => {
@@ -223,16 +234,6 @@ describe('<TreeNode />', () => {
223234
});
224235
});
225236

226-
describe('icons', () => {
227-
it('should replace the default set of icons with the provided values', () => {
228-
const { container } = render(
229-
<TreeNode {...baseProps} icons={{ uncheck: <span className="other-uncheck" /> }} />,
230-
);
231-
232-
assert.isNotNull(container.querySelector('.rct-checkbox .other-uncheck'));
233-
});
234-
});
235-
236237
describe('label', () => {
237238
it('should render the node\'s label', async () => {
238239
render(

0 commit comments

Comments
 (0)