Skip to content

Commit 5ff1c95

Browse files
committed
updated custom icons interface
previously custom icons only know the path, which requires user to manage state outside to find all data about this node. So the custom icon OnClick() call back takes all nodeData as param, so user can provide more powerful onClick() to custom icons without syncing state outside.
1 parent 2c3a565 commit 5ff1c95

File tree

5 files changed

+74
-55
lines changed

5 files changed

+74
-55
lines changed

README.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ A powerful and customizable react treeview library. It supports:
77
## Quick Preview
88
![folder-tree-demo](/assets/folder-tree-demo.gif)
99

10-
## Demos & Code Examples
11-
[HERE](https://shunjizhan.github.io/react-folder-tree-demos/)
10+
live demos and code examples can be found [HERE](https://shunjizhan.github.io/react-folder-tree-demos/)
1211

1312
---
1413
## Basic Usage
@@ -34,7 +33,7 @@ const BasicTree = () => {
3433
```
3534

3635
### 🌀 custom initial state
37-
tree state is an object that look like:
36+
tree state is an object that looks like:
3837
```jsx
3938
{
4039
// reserved keys
@@ -135,13 +134,11 @@ there are 9 icons and all of them are customizable.
135134
import { FaBitcoin } from 'react-icons/fa';
136135

137136
const BitcoinApp = () => {
138-
const FileIcon = ({ onClick: defaultOnClick, className, path, name }) => {
139-
/*
140-
`path` is an array of indexes from root to the node that was clicked.
141-
It can be used with the synced tree state outside to find all data about the clicked node.
142-
*/
137+
const FileIcon = ({ onClick: defaultOnClick, nodeData }) => {
138+
const { path, name, ...restData } = nodeData;
139+
143140
const handleClick = () => {
144-
doSthBad({ className, path, name });
141+
doSthBad({ path, name });
145142
defaultOnClick();
146143
};
147144

src/components/EditableName/EditableName.jsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import {
77
} from '../../utils/iconUtils';
88

99
const EditableName = ({
10-
name,
1110
isEditing,
1211
setIsEditing,
1312
onNameChange,
1413
OKIcon,
1514
CancelIcon,
16-
path,
15+
nodeData,
1716
}) => {
17+
const { name } = nodeData;
1818
const [inputVal, setInputVal] = useState(name);
1919

2020
const onInputChange = e => setInputVal(e.target.value);
@@ -40,14 +40,12 @@ const EditableName = ({
4040
<OKIcon
4141
className={ iconClassName('OKIcon') }
4242
onClick={ handleNameChange }
43-
path={ path }
44-
name={ name }
43+
nodeData={ nodeData }
4544
/>
4645
<CancelIcon
4746
className={ iconClassName('CancelIcon') }
4847
onClick={ cancelEditing }
49-
path={ path }
50-
name={ name }
48+
nodeData={ nodeData }
5149
/>
5250
</span>
5351
</span>
@@ -67,13 +65,12 @@ const EditableName = ({
6765
};
6866

6967
EditableName.propTypes = {
70-
name: PropTypes.string.isRequired,
7168
isEditing: PropTypes.bool.isRequired,
7269
setIsEditing: PropTypes.func.isRequired,
7370
onNameChange: PropTypes.func.isRequired,
7471
OKIcon: PropTypes.func.isRequired,
7572
CancelIcon: PropTypes.func.isRequired,
76-
path: PropTypes.array.isRequired,
73+
nodeData: PropTypes.object.isRequired,
7774
};
7875

7976
export default EditableName;

src/components/EditableName/EditableName.test.jsx

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,45 @@
11
import React from 'react';
22
import { mount } from 'enzyme';
3-
import EditableName from './EditableName';
3+
import {
4+
AiOutlineClose,
5+
AiOutlineCheck,
6+
} from 'react-icons/ai';
47

5-
const onNameChange = jest.fn;
6-
const setIsEditing = jest.fn;
8+
import EditableName from './EditableName';
9+
import { getDefaultIcon } from '../../utils/iconUtils';
710

811
describe('EditableName', () => {
12+
const _OKIcon = getDefaultIcon(AiOutlineCheck);
13+
const _CancelIcon = getDefaultIcon(AiOutlineClose);
14+
15+
const _onNameChange = jest.fn;
16+
const _setIsEditing = jest.fn;
17+
const _nodeData = {
18+
name: 'bitcoin',
19+
path: [0, 1],
20+
url: '/btc/eth',
21+
};
22+
923
let editableName;
1024
// let input;
1125
// let inputDOM;
1226

13-
const render = (name, isEditing) => {
27+
const render = ({
28+
isEditing = false,
29+
setIsEditing = _setIsEditing,
30+
onNameChange = _onNameChange,
31+
OKIcon = _OKIcon,
32+
CancelIcon = _CancelIcon,
33+
nodeData = _nodeData,
34+
} = {}) => {
1435
editableName = mount((
1536
<EditableName
16-
name={ name }
1737
onNameChange={ onNameChange }
1838
isEditing={ isEditing }
1939
setIsEditing={ setIsEditing }
40+
nodeData={ nodeData }
41+
OKIcon={ OKIcon }
42+
CancelIcon={ CancelIcon }
2043
/>
2144
));
2245
// input = editableName.find('input.editingName');
@@ -33,7 +56,7 @@ describe('EditableName', () => {
3356
afterEach(clean);
3457

3558
it('renders', () => {
36-
render('bitcoin', false);
59+
render();
3760
expect(editableName.exists()).toEqual(true);
3861
});
3962

src/components/TreeNode/TreeNode.jsx

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import EditableName from '../EditableName/EditableName';
2323
import {
2424
iconContainerClassName,
2525
iconClassName,
26+
getDefaultIcon,
2627
} from '../../utils/iconUtils';
2728

2829
const TreeNode = ({
@@ -33,6 +34,10 @@ const TreeNode = ({
3334
children,
3435
...restData
3536
}) => {
37+
const nodeData = {
38+
path, name, checked, isOpen, ...restData,
39+
};
40+
3641
const {
3742
handleCheck,
3843
handleRename,
@@ -56,17 +61,17 @@ const TreeNode = ({
5661
const [isEditing, setIsEditing] = useState(false);
5762

5863
const {
59-
FileIcon = AiOutlineFile,
60-
FolderIcon = AiOutlineFolder,
61-
FolderOpenIcon = AiOutlineFolderOpen,
62-
EditIcon = AiOutlineEdit,
63-
DeleteIcon = AiOutlineDelete,
64-
CancelIcon = AiOutlineClose,
65-
AddFileIcon = AiOutlineFileAdd,
66-
AddFolderIcon = AiOutlineFolderAdd,
67-
CaretRightIcon = AiFillCaretRight,
68-
CaretDownIcon = AiFillCaretDown,
69-
OKIcon = AiOutlineCheck,
64+
FileIcon = getDefaultIcon(AiOutlineFile),
65+
FolderIcon = getDefaultIcon(AiOutlineFolder),
66+
FolderOpenIcon = getDefaultIcon(AiOutlineFolderOpen),
67+
EditIcon = getDefaultIcon(AiOutlineEdit),
68+
DeleteIcon = getDefaultIcon(AiOutlineDelete),
69+
CancelIcon = getDefaultIcon(AiOutlineClose),
70+
AddFileIcon = getDefaultIcon(AiOutlineFileAdd),
71+
AddFolderIcon = getDefaultIcon(AiOutlineFolderAdd),
72+
CaretRightIcon = getDefaultIcon(AiFillCaretRight),
73+
CaretDownIcon = getDefaultIcon(AiFillCaretDown),
74+
OKIcon = getDefaultIcon(AiOutlineCheck),
7075
} = iconComponents;
7176

7277
let TypeIcon = FileIcon;
@@ -107,9 +112,6 @@ const TreeNode = ({
107112
const handleNameClick = () => {
108113
const defaultOnClick = selectMe;
109114
if (onNameClick && typeof onNameClick === 'function') {
110-
const nodeData = {
111-
path, name, checked, isOpen, ...restData,
112-
};
113115
!isEditing && onNameClick(defaultOnClick, nodeData);
114116
} else {
115117
defaultOnClick();
@@ -121,29 +123,25 @@ const TreeNode = ({
121123
<EditIcon
122124
className={ iconClassName('EditIcon') }
123125
onClick={ editMe }
124-
path={ path }
125-
name={ name }
126+
nodeData={ nodeData }
126127
/>
127128
<DeleteIcon
128129
className={ iconClassName('DeleteIcon') }
129130
onClick={ deleteMe }
130-
path={ path }
131-
name={ name }
131+
nodeData={ nodeData }
132132
/>
133133
{
134134
isFolder && (
135135
<>
136136
<AddFileIcon
137137
className={ iconClassName('AddFileIcon') }
138138
onClick={ addFile }
139-
path={ path }
140-
name={ name }
139+
nodeData={ nodeData }
141140
/>
142141
<AddFolderIcon
143142
className={ iconClassName('AddFolderIcon') }
144143
onClick={ addFolder }
145-
path={ path }
146-
name={ name }
144+
nodeData={ nodeData }
147145
/>
148146
</>
149147
)
@@ -152,8 +150,7 @@ const TreeNode = ({
152150
<CancelIcon
153151
className={ iconClassName('CancelIcon') }
154152
onClick={ unSelectMe }
155-
path={ path }
156-
name={ name }
153+
nodeData={ nodeData }
157154
/>
158155
</span>
159156
);
@@ -168,16 +165,14 @@ const TreeNode = ({
168165
<CaretDownIcon
169166
className={ iconClassName('CaretDownIcon') }
170167
onClick={ closeMe }
171-
path={ path }
172-
name={ name }
168+
nodeData={ nodeData }
173169
/>
174170
)
175171
: (
176172
<CaretRightIcon
177173
className={ iconClassName('CaretRightIcon') }
178174
onClick={ openMe }
179-
path={ path }
180-
name={ name }
175+
nodeData={ nodeData }
181176
/>
182177
)
183178
}
@@ -200,8 +195,7 @@ const TreeNode = ({
200195
<TypeIcon
201196
className={ iconClassName(TypeIconType) }
202197
onClick={ selectMe }
203-
path={ path }
204-
name={ name }
198+
nodeData={ nodeData }
205199
/>
206200
</span>
207201

@@ -210,13 +204,12 @@ const TreeNode = ({
210204
onClick={ handleNameClick }
211205
>
212206
<EditableName
213-
name={ name }
214207
isEditing={ isEditing }
215208
setIsEditing={ setIsEditing }
216209
onNameChange={ onNameChange }
217210
OKIcon={ OKIcon }
218211
CancelIcon={ CancelIcon }
219-
path={ path }
212+
nodeData={ nodeData }
220213
/>
221214
</span>
222215
{ isSelected && TreeNodeToolBar }

src/utils/iconUtils.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
1+
import React from 'react';
2+
13
export const iconContainerClassName = className => `iconContainer ${className}`;
24
export const iconClassName = className => `icon ${className}`;
5+
6+
export const getDefaultIcon = Icon => ({ className, onClick }) => ( // eslint-disable-line
7+
<Icon
8+
className={ className }
9+
onClick={ onClick }
10+
/>
11+
);

0 commit comments

Comments
 (0)