@@ -25,153 +25,147 @@ Demo: http://cheton.github.io/react-infinite-tree
25
25
npm install --save react-infinite-tree
26
26
```
27
27
28
- ## Example
28
+ ## Usage
29
+
30
+ ### Tree Structure
31
+
32
+ A tree structure can either be a node object or an array of node objects, and each node should have a unique ` id ` . Note that ` id ` , ` state ` , ` children ` , and ` parent ` are reserved keys for defining a node. See below for a basic tree structure:
33
+
34
+ ``` js
35
+ {
36
+ id: ' fruit' ,
37
+ name: ' Fruit' ,
38
+ children: [{
39
+ id: ' apple' ,
40
+ name: ' Apple'
41
+ }, {
42
+ id: ' banana' ,
43
+ name: ' Banana' ,
44
+ children: [{
45
+ id: ' cherry' ,
46
+ name: ' Cherry' ,
47
+ loadOnDemand: true
48
+ }]
49
+ }]
50
+ }
51
+ ```
29
52
30
- ### Components
53
+ ### Rendering Tree Nodes
54
+
55
+ You can use ` rowRenderer ` or pass a child function for rendering tree nodes. The child function will be supplied with the following properties:
31
56
32
- https://github.com/cheton/react-infinite-tree/tree/master/examples/components
57
+ * ` tree ` - https://github.com/cheton/infinite-tree/wiki/Functions:-Tree
58
+ * ` node ` - https://github.com/cheton/infinite-tree/wiki/Functions:-Node
33
59
34
- ### Tree
35
60
36
61
``` jsx
37
- import PropTypes from ' prop-types' ;
38
- import React , { PureComponent } from ' react' ;
62
+ import React from ' react' ;
39
63
import InfiniteTree from ' react-infinite-tree' ;
40
- import TreeNode from ' ./components/TreeNode' ;
41
- import Toggler from ' ./components/Toggler' ;
42
- import Icon from ' ./components/Icon' ;
43
- import Clickable from ' ./components/Clickable' ;
44
- import Text from ' ./components/Text' ;
45
- import Label from ' ./components/Label' ;
46
- import Loading from ' ./components/Loading' ;
47
- import { generate } from ' ./tree-generator' ;
48
-
49
- const renderTreeNode = ({ node, tree, toggleState }) => (
50
- < TreeNode
51
- selected= {node .state .selected }
52
- depth= {node .state .depth }
53
- onClick= {event => {
54
- tree .selectNode (node);
55
- }}
64
+
65
+ export default (props ) => (
66
+ < InfiniteTree
67
+ width= " 100%"
68
+ height= {400 }
69
+ rowHeight= {30 }
70
+ data= {props .data }
56
71
>
57
- < Toggler
58
- state= {toggleState}
59
- onClick= {() => {
60
- if (toggleState === ' closed' ) {
61
- tree .openNode (node);
62
- } else if (toggleState === ' opened' ) {
63
- tree .closeNode (node);
64
- }
65
- }}
66
- / >
67
- < Clickable>
68
- < Icon state= {toggleState} / >
69
- < Text > {node .name }< / Text >
70
- < / Clickable>
71
- {(node .loadOnDemand && node .children .length === 0 && ! node .state .loading ) &&
72
- < i className= " fa fa-fw fa-ellipsis-v" / >
72
+ {({ tree, node }) => {
73
+ // Determine the toggle state
74
+ let toggleState = ' ' ;
75
+ const hasChildren = node .hasChildren ();
76
+ if ((! hasChildren && node .loadOnDemand ) || (hasChildren && ! node .state .open )) {
77
+ toggleState = ' closed' ;
73
78
}
74
- {node .state .loading && < Loading / > }
75
- < Label style= {{ position: ' absolute' , right: 5 , top: 6 }}>
76
- {node .children .length }
77
- < / Label>
78
- < / TreeNode>
79
- );
80
-
81
- class Tree extends PureComponent {
82
- tree = null ;
83
- data = generate (1000 );
84
-
85
- componentDidMount () {
86
- // Select the first node
87
- this .tree .selectNode (this .tree .getChildNodes ()[0 ]);
88
- }
89
- render () {
79
+ if (hasChildren && node .state .open ) {
80
+ toggleState = ' opened' ;
81
+ }
82
+
90
83
return (
91
- < InfiniteTree
92
- ref= {node => {
93
- this .tree = node ? node .tree : null ;
94
- }}
95
- style= {{
96
- border: ' 1px solid #ccc'
97
- }}
98
- autoOpen
99
- selectable
100
- tabIndex= {0 }
101
- data= {this .data }
102
- width= " 100%"
103
- height= {400 }
104
- rowHeight= {30 }
105
- rowRenderer= {({ node, tree }) => {
106
- const hasChildren = node .hasChildren ();
107
- let toggleState = ' ' ;
108
- if ((! hasChildren && node .loadOnDemand ) || (hasChildren && ! node .state .open )) {
109
- toggleState = ' closed' ;
110
- }
111
- if (hasChildren && node .state .open ) {
112
- toggleState = ' opened' ;
113
- }
114
- return renderTreeNode ({ node, tree, toggleState });
84
+ < TreeNode
85
+ selected= {node .state .selected }
86
+ depth= {node .state .depth }
87
+ onClick= {event => {
88
+ tree .selectNode (node);
115
89
}}
116
- loadNodes= {(parentNode , done ) => {
117
- const suffix = parentNode .id .replace (/ (\w )+ / , ' ' );
118
- const nodes = [
119
- {
120
- id: ' node1' + suffix,
121
- name: ' Node 1'
122
- },
123
- {
124
- id: ' node2' + suffix,
125
- name: ' Node 2'
90
+ >
91
+ < Toggler
92
+ state= {toggleState}
93
+ onClick= {() => {
94
+ if (toggleState === ' closed' ) {
95
+ tree .openNode (node);
96
+ } else if (toggleState === ' opened' ) {
97
+ tree .closeNode (node);
126
98
}
127
- ];
128
- setTimeout (() => {
129
- done (null , nodes);
130
- }, 1000 );
131
- }}
132
- shouldSelectNode= {(node ) => { // Defaults to null
133
- if (! node || (node === this .tree .getSelectedNode ())) {
134
- return false ; // Prevent from deselecting the current node
135
- }
136
- return true ;
137
- }}
138
- onKeyUp= {(event ) => {
139
- console .log (' onKeyUp' , event .target );
140
- }}
141
- onKeyDown= {(event ) => {
142
- console .log (' onKeyDown' , event .target );
143
- event .preventDefault ();
144
- const node = this .tree .getSelectedNode ();
145
- const nodeIndex = this .tree .getSelectedIndex ();
146
- if (event .keyCode === 37 ) { // Left
147
- this .tree .closeNode (node);
148
- } else if (event .keyCode === 38 ) { // Up
149
- const prevNode = this .tree .nodes [nodeIndex - 1 ] || node;
150
- this .tree .selectNode (prevNode);
151
- } else if (event .keyCode === 39 ) { // Right
152
- this .tree .openNode (node);
153
- } else if (event .keyCode === 40 ) { // Down
154
- const nextNode = this .tree .nodes [nodeIndex + 1 ] || node;
155
- this .tree .selectNode (nextNode);
156
- }
157
- }}
158
- onScroll= {(scrollOffset , event ) => {}}
159
- onContentWillUpdate= {() => {}}
160
- onContentDidUpdate= {() => {}}
161
- onOpenNode= {(node ) => {}}
162
- onCloseNode= {(node ) => {}}
163
- onSelectNode= {(node ) => {}}
164
- onWillOpenNode= {(node ) => {}}
165
- onWillCloseNode= {(node ) => {}}
166
- onWillSelectNode= {(node ) => {}}
167
- / >
99
+ }}
100
+ / >
101
+ < span> {node .name }< / span>
102
+ < / TreeNode>
168
103
);
104
+ }}
105
+ < / InfiniteTree>
106
+ );
107
+ ```
108
+
109
+ ### Components
110
+
111
+ #### TreeNode Component
112
+
113
+ ``` jsx
114
+ import React from ' react' ;
115
+ import styled from ' styled-components' ;
116
+
117
+ const defaultRowHeight = 30 ;
118
+
119
+ const TreeNode = styled .div `
120
+ cursor: default;
121
+ position: relative;
122
+ line-height: ${ ({ rowHeight = defaultRowHeight }) => rowHeight - 2 } px;
123
+ background: ${ props => props .selected ? ' #deecfd' : ' transparent' } ;
124
+ border: ${ props => props .selected ? ' 1px solid #06c' : ' 1px solid transparent' } ;
125
+ padding-left: ${ props => props .depth * 18 } px;
126
+ .dropdown {
127
+ visibility: hidden;
169
128
}
170
- }
129
+ &:hover {
130
+ background: #f2fdff;
131
+ .dropdown {
132
+ visibility: inherit;
133
+ }
134
+ }
135
+ ` ;
136
+
137
+ export default TreeNode ;
138
+ ```
139
+
140
+ #### Toggler Component
171
141
172
- export default Tree ;
142
+ ``` jsx
143
+ import React from ' react' ;
144
+ import styled from ' styled-components' ;
145
+
146
+ const Toggler = styled (({ state, ... props }) => (
147
+ < a {... props}>
148
+ {(state === ' closed' ) &&
149
+ < i className= " fa fa-fw fa-chevron-right" / >
150
+ }
151
+ {(state === ' opened' ) &&
152
+ < i className= " fa fa-fw fa-chevron-down" / >
153
+ }
154
+ < / a>
155
+ ))`
156
+ color: #333;
157
+ display: inline-block;
158
+ text-align: center;
159
+ margin-right: 2px;
160
+ ` ;
161
+
162
+ export default Toggler ;
173
163
```
174
164
165
+ ## Example
166
+
167
+ See https://github.com/cheton/react-infinite-tree/blob/master/examples/Tree.jsx for a complete example.
168
+
175
169
# API
176
170
177
171
### Properties
0 commit comments