Skip to content

Commit f651a57

Browse files
authored
Update README.md
1 parent 397bf62 commit f651a57

File tree

1 file changed

+169
-168
lines changed

1 file changed

+169
-168
lines changed

README.md

Lines changed: 169 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -27,185 +27,186 @@ npm install --save react-infinite-tree
2727

2828
## Example
2929

30-
#### Tree.jsx
30+
### Tree
31+
3132
```jsx
32-
<InfiniteTree
33-
ref={node => {
34-
this.tree = node ? node.tree : null;
35-
}}
36-
style={{
37-
border: '1px solid #ccc'
38-
}}
39-
data={this.data}
40-
width="100%"
41-
height={400}
42-
rowHeight={30}
43-
autoOpen={true}
44-
loadNodes={(parentNode, done) => {
45-
const suffix = parentNode.id.replace(/(\w)+/, '');
46-
const nodes = [
47-
{
48-
id: 'node1' + suffix,
49-
name: 'Node 1'
50-
},
51-
{
52-
id: 'node2' + suffix,
53-
name: 'Node 2'
54-
}
55-
];
56-
setTimeout(() => {
57-
done(null, nodes);
58-
}, 1000);
59-
}}
60-
selectable={true} // Defaults to true
61-
shouldSelectNode={(node) => { // Defaults to null
62-
if (!node || (node === this.tree.getSelectedNode())) {
63-
return false; // Prevent from deselecting the current node
64-
}
65-
return true;
66-
}}
67-
onKeyDown={(event) => {
68-
const target = event.target || event.srcElement; // IE8
69-
console.log('onKeyDown', target);
70-
event.preventDefault();
71-
72-
const node = this.tree.getSelectedNode();
73-
const nodeIndex = this.tree.getSelectedIndex();
74-
75-
if (event.keyCode === 37) { // Left
76-
this.tree.closeNode(node);
77-
} else if (event.keyCode === 38) { // Up
78-
const prevNode = this.tree.nodes[nodeIndex - 1] || node;
79-
this.tree.selectNode(prevNode);
80-
} else if (event.keyCode === 39) { // Right
81-
this.tree.openNode(node);
82-
} else if (event.keyCode === 40) { // Down
83-
const nextNode = this.tree.nodes[nodeIndex + 1] || node;
84-
this.tree.selectNode(nextNode);
33+
import PropTypes from 'prop-types';
34+
import React, { PureComponent } from 'react';
35+
import InfiniteTree from '../src';
36+
import TreeNode from './components/TreeNode';
37+
import Toggler from './components/Toggler';
38+
import Icon from './components/Icon';
39+
import Clickable from './components/Clickable';
40+
import Text from './components/Text';
41+
import Label from './components/Label';
42+
import Loading from './components/Loading';
43+
import { generate } from './tree-generator';
44+
45+
const renderTreeNode = ({ node, tree, toggleState }) => (
46+
<TreeNode
47+
selected={node.state.selected}
48+
depth={node.state.depth}
49+
onClick={event => {
50+
tree.selectNode(node);
51+
}}
52+
>
53+
<Toggler
54+
state={toggleState}
55+
onClick={() => {
56+
if (toggleState === 'closed') {
57+
tree.openNode(node);
58+
} else if (toggleState === 'opened') {
59+
tree.closeNode(node);
60+
}
61+
}}
62+
/>
63+
<Clickable>
64+
<Icon state={toggleState} />
65+
<Text>{node.name}</Text>
66+
</Clickable>
67+
{(node.loadOnDemand && node.children.length === 0 && !node.state.loading) &&
68+
<i className="fa fa-fw fa-ellipsis-v" />
8569
}
86-
}}
87-
>
88-
{({ node, tree }) => {
89-
const { id, name, loadOnDemand = false, children, state, props = {} } = node;
90-
const { depth, open, path, total, loading = false, selected = false } = state;
91-
const childrenLength = Object.keys(children).length;
92-
const more = node.hasChildren();
93-
94-
let togglerState = '';
95-
if ((!more && loadOnDemand) || (more && !open)) {
96-
togglerState = 'collapsed';
97-
}
98-
if (more && open) {
99-
togglerState = 'expanded';
100-
}
70+
{node.state.loading && <Loading />}
71+
<Label style={{ position: 'absolute', right: 5, top: 6 }}>
72+
{node.children.length}
73+
</Label>
74+
</TreeNode>
75+
);
10176

102-
let iconState = '';
103-
if (more && open) {
104-
iconState = 'folder-open';
105-
}
106-
if (more && !open) {
107-
iconState = 'folder';
108-
}
109-
if (!more) {
110-
iconState = 'file';
111-
}
77+
class Tree extends PureComponent {
78+
tree = null;
79+
data = generate(1000);
11280

113-
return (
114-
<TreeNode
115-
selected={selected}
116-
depth={depth}
117-
onClick={event => {
118-
tree.selectNode(node);
119-
}}
120-
>
121-
<Toggler
122-
state={togglerState}
123-
onClick={() => {
124-
if (togglerState === 'collapsed') {
125-
tree.openNode(node);
126-
} else if (togglerState === 'expanded') {
127-
tree.closeNode(node);
81+
componentDidMount() {
82+
// Select the first node
83+
this.tree.selectNode(this.tree.getChildNodes()[0]);
84+
}
85+
render() {
86+
return (
87+
<InfiniteTree
88+
ref={node => {
89+
this.tree = node ? node.tree : null;
90+
}}
91+
style={{
92+
border: '1px solid #ccc'
93+
}}
94+
autoOpen
95+
selectable
96+
tabIndex={0}
97+
data={this.data}
98+
width="100%"
99+
height={400}
100+
rowHeight={30}
101+
rowRenderer={({ node, tree }) => {
102+
const hasChildren = node.hasChildren();
103+
let toggleState = '';
104+
if ((!hasChildren && node.loadOnDemand) || (hasChildren && !node.state.open)) {
105+
toggleState = 'closed';
106+
}
107+
if (hasChildren && node.state.open) {
108+
toggleState = 'opened';
109+
}
110+
return renderTreeNode({ node, tree, toggleState });
111+
}}
112+
loadNodes={(parentNode, done) => {
113+
const suffix = parentNode.id.replace(/(\w)+/, '');
114+
const nodes = [
115+
{
116+
id: 'node1' + suffix,
117+
name: 'Node 1'
118+
},
119+
{
120+
id: 'node2' + suffix,
121+
name: 'Node 2'
122+
}
123+
];
124+
setTimeout(() => {
125+
done(null, nodes);
126+
}, 1000);
127+
}}
128+
shouldSelectNode={(node) => { // Defaults to null
129+
if (!node || (node === this.tree.getSelectedNode())) {
130+
return false; // Prevent from deselecting the current node
128131
}
132+
return true;
129133
}}
134+
onKeyUp={(event) => {
135+
console.log('onKeyUp', event.target);
136+
}}
137+
onKeyDown={(event) => {
138+
console.log('onKeyDown', event.target);
139+
event.preventDefault();
140+
const node = this.tree.getSelectedNode();
141+
const nodeIndex = this.tree.getSelectedIndex();
142+
if (event.keyCode === 37) { // Left
143+
this.tree.closeNode(node);
144+
} else if (event.keyCode === 38) { // Up
145+
const prevNode = this.tree.nodes[nodeIndex - 1] || node;
146+
this.tree.selectNode(prevNode);
147+
} else if (event.keyCode === 39) { // Right
148+
this.tree.openNode(node);
149+
} else if (event.keyCode === 40) { // Down
150+
const nextNode = this.tree.nodes[nodeIndex + 1] || node;
151+
this.tree.selectNode(nextNode);
152+
}
153+
}}
154+
onScroll={(scrollOffset, event) => {}}
155+
onContentWillUpdate={() => {}}
156+
onContentDidUpdate={() => {}}
157+
onOpenNode={(node) => {}}
158+
onCloseNode={(node) => {}}
159+
onSelectNode={(node) => {}}
160+
onWillOpenNode={(node) => {}}
161+
onWillCloseNode={(node) => {}}
162+
onWillSelectNode={(node) => {}}
130163
/>
131-
<PointerCursor>
132-
<Icon state={iconState} />
133-
<Text>{name}</Text>
134-
</PointerCursor>
135-
</TreeNode>
136-
);
137-
}}
138-
</InfiniteTree>
139-
```
140-
141-
#### render.jsx
142-
```jsx
143-
import React from 'react';
144-
import styled from 'styled-components';
145-
146-
const rowHeight = 30;
147-
148-
export const TreeNode = styled.div`
149-
cursor: default;
150-
position: relative;
151-
line-height: ${rowHeight - 2}px;
152-
background: ${props => props.selected ? '#deecfd' : 'transparent'};
153-
border: ${props => props.selected ? '1px solid #06c' : '1px solid transparent'};
154-
&:hover {
155-
background: #f2fdff;
164+
);
156165
}
157-
padding-left: ${props => props.depth * 18}px;
158-
`;
159-
160-
export const Toggler = styled(({ state, ...props }) => (
161-
<a {...props}>
162-
{(state === 'expanded') &&
163-
<i className="fa fa-fw fa-chevron-right" />
164-
}
165-
{(state === 'collapsed') &&
166-
<i className="fa fa-fw fa-chevron-down" />
167-
}
168-
</a>
169-
))`
170-
color: #333;
171-
display: inine-block;
172-
text-align: center;
173-
margin-right: 2px;
174-
`;
175-
176-
export const Icon = ({ state, ...props }) => (
177-
<span {...props}>
178-
{(state === 'folder-open') &&
179-
<i className="fa fa-fw fa-folder-open-o" />
180-
}
181-
{(state === 'folder') &&
182-
<i className="fa fa-fw fa-folder-o" />
183-
}
184-
{(state === 'file') &&
185-
<i className="fa fa-fw fa-file-o" />
186-
}
187-
</span>
188-
);
189-
190-
export const PointerCursor = styled.div`
191-
display: inline-block;
192-
cursor: pointer;
193-
`;
166+
}
194167

195-
export const Text = styled.span`
196-
margin-left: 0 2px;
197-
user-select: none;
198-
`;
168+
export default Tree;
199169
```
200170

201-
## API Documentation
202-
203-
Check out API documentation at [infinite-tree](https://github.com/cheton/infinite-tree/wiki):
204-
205-
* [Options](https://github.com/cheton/react-infinite-tree/wiki/Options)
206-
* [Functions: Tree](https://github.com/cheton/react-infinite-tree/wiki/Functions:-Tree)
207-
* [Functions: Node](https://github.com/cheton/react-infinite-tree/wiki/Functions:-Node)
208-
* [Events](https://github.com/cheton/react-infinite-tree/wiki/Events)
171+
### Components
172+
173+
https://github.com/cheton/react-infinite-tree/tree/master/examples/components
174+
175+
# API
176+
177+
### Properties
178+
179+
Name | Type | Default | Description
180+
:--- | :--- | :------ | :----------
181+
autoOpen | Boolean | false | Whether to open all nodes when tree is loaded.
182+
selectable | Boolean | true | Whether or not a node is selectable in the tree.
183+
tabIndex | Number | 0 | Specifies the tab order to make tree focusable.
184+
data | Array or Object | [] | Tree data structure, or a collection of tree data structures.
185+
width \* | Number or String | '100%' | Width of the tree.
186+
height \* | Number or String | | Height of the tree.
187+
rowHeight \* | Number, Array, or Function(index: Number): Number | | Either a fixed height, an array containing the heights of all the rows, or a function that returns the height of a row given its index.
188+
rowRenderer | Function({ node: Node, tree: Tree }): React Node | | A row renderer for rendering a tree node.
189+
loadNodes | Function(parentNode: Node, done: Function) | | Loads nodes on demand.
190+
shouldSelectNode | Function(node: Node): Boolean | | Provides a function to determine if a node can be selected or deselected. The function must return `true` or `false`. This function will not take effect if `selectable` is not `true`.
191+
scrollOffset | Number | | Controls the scroll offset.
192+
scrollToIndex | Number | | Node index to scroll to.
193+
onScroll | Function(scrollTop: Number, event: React.UIEvent) | | Callback invoked whenever the scroll offset changes.
194+
onContentWillUpdate | Function() | | Callback invoked before updating the tree.
195+
onContentDidUpdate | Function() | | Callback invoked when the tree is updated.
196+
onOpenNode | Function(node: Node) | | Callback invoked when a node is opened.
197+
onCloseNode | Function(node: Node) | | Callback invoked when a node is closed.
198+
onSelectNode | Function(node: Node) | | Callback invoked when a node is selected or deselected.
199+
onWillOpenNode | Function(node: Node) | | Callback invoked before opening a node.
200+
onWillCloseNode | Function(node: Node) | | Callback invoked before closing a node.
201+
onWillSelectNode | Function(node: Node) | | Callback invoked before selecting or deselecting a node.
202+
203+
### Tree Methods
204+
205+
https://github.com/cheton/react-infinite-tree/wiki/Functions:-Tree
206+
207+
### Node Methods
208+
209+
https://github.com/cheton/react-infinite-tree/wiki/Functions:-Node
209210

210211
## License
211212

0 commit comments

Comments
 (0)