Skip to content

Commit 698c3c5

Browse files
committed
Rework React Infinite Tree component (#7)
1 parent 1c2f302 commit 698c3c5

19 files changed

+2161
-21425
lines changed

README.md

Lines changed: 108 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -21,145 +21,120 @@ Demo: http://cheton.github.io/react-infinite-tree
2121
Yes | Yes | Yes| 9+ | Yes | Yes |
2222

2323
## Installation
24-
```bash
25-
npm install --save react react-dom infinite-tree
24+
```sh
2625
npm install --save react-infinite-tree
2726
```
2827

2928
## Example
29+
3030
```jsx
31-
import React from 'react';
32-
import classNames from 'classnames';
33-
import InfiniteTree from 'react-infinite-tree';
34-
import 'react-infinite-tree/dist/react-infinite-tree.css';
35-
36-
const data = {
37-
id: 'fruit',
38-
name: 'Fruit',
39-
children: [{
40-
id: 'apple',
41-
name: 'Apple'
42-
}, {
43-
id: 'banana',
44-
name: 'Banana',
45-
children: [{
46-
id: 'cherry',
47-
name: 'Cherry',
48-
loadOnDemand: true
49-
}]
50-
}]
51-
};
52-
53-
class App extends React.Component {
54-
tree = null;
55-
56-
componentDidMount() {
57-
this.tree.loadData(data);
58-
59-
// Select the first node
60-
this.tree.selectNode(this.tree.getChildNodes()[0]);
31+
<InfiniteTree
32+
ref={node => {
33+
this.tree = node ? node.tree : null;
34+
}}
35+
style={{
36+
border: '1px solid #ccc'
37+
}}
38+
data={this.data}
39+
width="100%"
40+
height={400}
41+
rowHeight={30}
42+
autoOpen={true}
43+
loadNodes={(parentNode, done) => {
44+
const suffix = parentNode.id.replace(/(\w)+/, '');
45+
const nodes = [
46+
{
47+
id: 'node1' + suffix,
48+
name: 'Node 1'
49+
},
50+
{
51+
id: 'node2' + suffix,
52+
name: 'Node 2'
53+
}
54+
];
55+
setTimeout(() => {
56+
done(null, nodes);
57+
}, 1000);
58+
}}
59+
selectable={true} // Defaults to true
60+
shouldSelectNode={(node) => { // Defaults to null
61+
if (!node || (node === this.tree.getSelectedNode())) {
62+
return false; // Prevent from deselecting the current node
63+
}
64+
return true;
65+
}}
66+
onKeyDown={(event) => {
67+
const target = event.target || event.srcElement; // IE8
68+
console.log('onKeyDown', target);
69+
event.preventDefault();
70+
71+
const node = this.tree.getSelectedNode();
72+
const nodeIndex = this.tree.getSelectedIndex();
73+
74+
if (event.keyCode === 37) { // Left
75+
this.tree.closeNode(node);
76+
} else if (event.keyCode === 38) { // Up
77+
const prevNode = this.tree.nodes[nodeIndex - 1] || node;
78+
this.tree.selectNode(prevNode);
79+
} else if (event.keyCode === 39) { // Right
80+
this.tree.openNode(node);
81+
} else if (event.keyCode === 40) { // Down
82+
const nextNode = this.tree.nodes[nodeIndex + 1] || node;
83+
this.tree.selectNode(nextNode);
84+
}
85+
}}
86+
>
87+
{({ node, tree }) => {
88+
const { id, name, loadOnDemand = false, children, state, props = {} } = node;
89+
const { depth, open, path, total, loading = false, selected = false } = state;
90+
const childrenLength = Object.keys(children).length;
91+
const more = node.hasChildren();
92+
93+
let togglerState = '';
94+
if ((!more && loadOnDemand) || (more && !open)) {
95+
togglerState = 'collapsed';
96+
}
97+
if (more && open) {
98+
togglerState = 'expanded';
99+
}
100+
101+
let iconState = '';
102+
if (more && open) {
103+
iconState = 'folder-open';
61104
}
62-
render() {
63-
return (
64-
<div>
65-
<InfiniteTree
66-
ref={(c) => this.tree = c.tree}
67-
autoOpen={true}
68-
loadNodes={(parentNode, done) => {
69-
const suffix = parentNode.id.replace(/(\w)+/, '');
70-
const nodes = [
71-
{
72-
id: 'node1' + suffix,
73-
name: 'Node 1'
74-
},
75-
{
76-
id: 'node2' + suffix,
77-
name: 'Node 2'
78-
}
79-
];
80-
setTimeout(() => {
81-
done(null, nodes);
82-
}, 1000);
83-
}}
84-
rowRenderer={(node, treeOptions) => {
85-
const { id, name, loadOnDemand = false, children, state, props = {} } = node;
86-
const droppable = treeOptions.droppable;
87-
const { depth, open, path, total, selected = false } = state;
88-
const more = node.hasChildren();
89-
90-
return (
91-
<div
92-
className={classNames(
93-
'infinite-tree-item',
94-
{ 'infinite-tree-selected': selected }
95-
)}
96-
data-id={id}
97-
droppable={droppable}
98-
>
99-
<div
100-
className="infinite-tree-node"
101-
style={{ marginLeft: depth * 18 }}
102-
>
103-
{!more && loadOnDemand &&
104-
<a className={classNames(treeOptions.togglerClass, 'infinite-tree-closed')}></a>
105-
}
106-
{more && open &&
107-
<a className={classNames(treeOptions.togglerClass)}></a>
108-
}
109-
{more && !open &&
110-
<a className={classNames(treeOptions.togglerClass, 'infinite-tree-closed')}></a>
111-
}
112-
<span className="infinite-tree-title">{name}</span>
113-
</div>
114-
</div>
115-
);
116-
}}
117-
selectable={true}
118-
shouldSelectNode={(node) => {
119-
if (!node || (node === this.tree.getSelectedNode())) {
120-
return false; // Prevent from deselecting the current node
121-
}
122-
return true;
123-
}}
124-
onClick={(event) => {
125-
// click event
126-
const target = event.target || event.srcElement; // IE8
127-
console.log('click:', target);
128-
}}
129-
onDoubleClick={(event) => {
130-
// dblclick event
131-
}}
132-
onKeyDown={(event) => {
133-
// keydown event
134-
}}
135-
onKeyUp={(event) => {
136-
// keyup event
137-
}}
138-
onCloseNode={(node) => {
139-
}}
140-
onOpenNode={(node) => {
141-
}}
142-
onSelectNode={(node) => {
143-
}}
144-
onWillCloseNode={(node) => {
145-
}}
146-
onWillOpenNode={(node) => {
147-
}}
148-
onWillSelectNode={(node) => {
149-
}}
150-
onClusterWillChange={() => {
151-
}}
152-
onClusterDidChange={() => {
153-
}}
154-
onContentWillUpdate={() => {
155-
}}
156-
onContentDidUpdate={() => {
157-
}}
158-
/>
159-
</div>
160-
);
105+
if (more && !open) {
106+
iconState = 'folder';
161107
}
162-
}
108+
if (!more) {
109+
iconState = 'file';
110+
}
111+
112+
return (
113+
<TreeNode
114+
selected={selected}
115+
depth={depth}
116+
onClick={event => {
117+
tree.selectNode(node);
118+
}}
119+
>
120+
<Toggler
121+
state={togglerState}
122+
onClick={() => {
123+
if (togglerState === 'collapsed') {
124+
tree.openNode(node);
125+
} else if (togglerState === 'expanded') {
126+
tree.closeNode(node);
127+
}
128+
}}
129+
/>
130+
<PointerCursor>
131+
<Icon state={iconState} />
132+
<Text>{name}</Text>
133+
</PointerCursor>
134+
</TreeNode>
135+
);
136+
}}
137+
</InfiniteTree>
163138
```
164139

165140
## API Documentation
@@ -173,6 +148,4 @@ Check out API documentation at [infinite-tree](https://github.com/cheton/infinit
173148

174149
## License
175150

176-
Copyright (c) 2016 Cheton Wu
177-
178-
Licensed under the [MIT License](LICENSE).
151+
MIT

0 commit comments

Comments
 (0)