react-arborist 1.2.0 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +606 -144
- package/dist/components/{drop-cursor.d.ts → cursor.d.ts} +0 -0
- package/dist/components/default-container.d.ts +7 -0
- package/dist/components/default-cursor.d.ts +3 -0
- package/dist/components/default-drag-preview.d.ts +3 -0
- package/dist/components/default-node.d.ts +4 -0
- package/dist/components/default-row.d.ts +4 -0
- package/dist/components/drag-preview-container.d.ts +2 -0
- package/dist/components/list-inner-element.d.ts +2 -0
- package/dist/components/provider.d.ts +11 -0
- package/dist/components/row-container.d.ts +8 -0
- package/dist/components/tree-container.d.ts +2 -0
- package/dist/components/tree.d.ts +5 -4
- package/dist/context.d.ts +20 -2
- package/dist/data/create-index.d.ts +5 -0
- package/dist/data/create-list.d.ts +4 -0
- package/dist/data/create-root.d.ts +5 -0
- package/dist/data/simple-tree.d.ts +43 -0
- package/dist/dnd/compute-drop.d.ts +4 -4
- package/dist/dnd/drag-hook.d.ts +3 -4
- package/dist/dnd/drop-hook.d.ts +2 -3
- package/dist/hooks/use-fresh-node.d.ts +2 -0
- package/dist/hooks/use-simple-tree.d.ts +13 -0
- package/dist/hooks/use-validated-props.d.ts +3 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +1948 -973
- package/dist/index.js.map +1 -1
- package/dist/interfaces/node-api.d.ts +67 -0
- package/dist/interfaces/tree-api.d.ts +113 -0
- package/dist/module.js +1935 -979
- package/dist/module.js.map +1 -1
- package/dist/state/dnd-slice.d.ts +20 -0
- package/dist/state/drag-slice.d.ts +7 -0
- package/dist/state/edit-slice.d.ts +8 -0
- package/dist/state/focus-slice.d.ts +12 -0
- package/dist/state/initial.d.ts +3 -0
- package/dist/state/open-slice.d.ts +30 -0
- package/dist/state/root-reducer.d.ts +13 -0
- package/dist/state/selection-slice.d.ts +36 -0
- package/dist/types/dnd.d.ts +9 -0
- package/dist/types/handlers.d.ts +24 -0
- package/dist/types/renderers.d.ts +30 -0
- package/dist/types/state.d.ts +2 -0
- package/dist/types/tree-props.d.ts +44 -0
- package/dist/types/utils.d.ts +21 -0
- package/dist/utils.d.ts +15 -6
- package/package.json +11 -7
- package/src/components/cursor.tsx +15 -0
- package/src/components/default-container.tsx +238 -0
- package/src/components/{default-drop-cursor.tsx → default-cursor.tsx} +9 -8
- package/src/components/{preview.tsx → default-drag-preview.tsx} +25 -41
- package/src/components/default-node.tsx +50 -0
- package/src/components/default-row.tsx +21 -0
- package/src/components/drag-preview-container.tsx +26 -0
- package/src/components/list-inner-element.tsx +22 -0
- package/src/components/list-outer-element.tsx +26 -15
- package/src/components/provider.tsx +97 -0
- package/src/components/row-container.tsx +82 -0
- package/src/components/tree-container.tsx +13 -0
- package/src/components/tree.tsx +16 -44
- package/src/context.ts +36 -0
- package/src/data/create-index.ts +9 -0
- package/src/data/create-list.ts +56 -0
- package/src/data/create-root.ts +54 -0
- package/src/data/simple-tree.ts +103 -0
- package/src/dnd/compute-drop.ts +16 -16
- package/src/dnd/drag-hook.ts +25 -19
- package/src/dnd/drop-hook.ts +31 -17
- package/src/dnd/outer-drop-hook.ts +1 -1
- package/src/hooks/use-fresh-node.ts +16 -0
- package/src/hooks/use-simple-tree.ts +55 -0
- package/src/hooks/use-validated-props.ts +35 -0
- package/src/index.ts +9 -19
- package/src/interfaces/node-api.ts +187 -0
- package/src/interfaces/tree-api.ts +557 -0
- package/src/state/dnd-slice.ts +36 -0
- package/src/state/drag-slice.ts +31 -0
- package/src/state/edit-slice.ts +19 -0
- package/src/state/focus-slice.ts +28 -0
- package/src/state/initial.ts +14 -0
- package/src/state/open-slice.ts +53 -0
- package/src/state/root-reducer.ts +21 -0
- package/src/state/selection-slice.ts +75 -0
- package/src/types/dnd.ts +10 -0
- package/src/types/handlers.ts +24 -0
- package/src/types/renderers.ts +34 -0
- package/src/types/state.ts +3 -0
- package/src/types/tree-props.ts +64 -0
- package/src/types/utils.ts +26 -0
- package/src/utils.ts +125 -11
- package/tsconfig.json +1 -1
- package/dist/components/default-drop-cursor.d.ts +0 -3
- package/dist/components/list.d.ts +0 -4
- package/dist/components/preview.d.ts +0 -2
- package/dist/components/row.d.ts +0 -8
- package/dist/data/enrich-tree.d.ts +0 -2
- package/dist/data/flatten-tree.d.ts +0 -2
- package/dist/provider.d.ts +0 -3
- package/dist/reducer.d.ts +0 -46
- package/dist/selection/range.d.ts +0 -13
- package/dist/selection/selection-hook.d.ts +0 -4
- package/dist/selection/selection.d.ts +0 -33
- package/dist/tree-api.d.ts +0 -50
- package/dist/types.d.ts +0 -122
- package/src/components/drop-cursor.tsx +0 -12
- package/src/components/list.tsx +0 -25
- package/src/components/row.tsx +0 -112
- package/src/context.tsx +0 -13
- package/src/data/enrich-tree.ts +0 -74
- package/src/data/flatten-tree.ts +0 -17
- package/src/provider.tsx +0 -41
- package/src/reducer.ts +0 -161
- package/src/selection/range.ts +0 -41
- package/src/selection/selection-hook.ts +0 -25
- package/src/selection/selection.test.ts +0 -111
- package/src/selection/selection.ts +0 -186
- package/src/tree-api.ts +0 -230
- package/src/types.ts +0 -148
package/README.md
CHANGED
|
@@ -2,15 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
<h1>React Arborist</h1>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The tree view is ubiquitous in software applications. This library provides the React ecosystem with complete solution to build the equivalent of the VSCode sidebar, the Mac Finder, the Windows Explorer, or the Sketch/Figma layers panel.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
_New Link To Demo_
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Features
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- Drag and drop sorting
|
|
12
|
+
- Open/close folders
|
|
13
|
+
- Inline renaming
|
|
14
|
+
- Virtualized rendering
|
|
15
|
+
- Custom styling
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
**New Features in Version 2**
|
|
18
|
+
|
|
19
|
+
- Keyboard navigation
|
|
20
|
+
- Aria attributes
|
|
21
|
+
- Tree filtering
|
|
22
|
+
- Selection synchronization
|
|
23
|
+
- More callbacks (onScroll, onActivate, onSelect)
|
|
24
|
+
- Controlled or uncontrolled trees
|
|
25
|
+
|
|
26
|
+
_NEW DEMO GIF HERE_
|
|
27
|
+
|
|
28
|
+
> These docs are for version 2. It contains breaking changes. Here is the [v1.2.0 README](https://github.com/brimdata/react-arborist/tree/4fe9659d2c4cbd57582294330863d4fd7e7af74b).
|
|
14
29
|
|
|
15
30
|
## Installation
|
|
16
31
|
|
|
@@ -22,200 +37,647 @@ yarn add react-arborist
|
|
|
22
37
|
npm install react-arborist
|
|
23
38
|
```
|
|
24
39
|
|
|
25
|
-
##
|
|
40
|
+
## Examples
|
|
41
|
+
|
|
42
|
+
Assume our data is this:
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
const data = [
|
|
46
|
+
{ id: "1", name: "Unread" },
|
|
47
|
+
{ id: "2", name: "Threads" },
|
|
48
|
+
{
|
|
49
|
+
id: "3",
|
|
50
|
+
name: "Chat Rooms",
|
|
51
|
+
children: [
|
|
52
|
+
{ id: "c1", name: "General" },
|
|
53
|
+
{ id: "c2", name: "Random" },
|
|
54
|
+
{ id: "c3", name: "Open Source Projects" },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "4",
|
|
59
|
+
name: "Direct Messages",
|
|
60
|
+
children: [
|
|
61
|
+
{ id: "d1", name: "Alice" },
|
|
62
|
+
{ id: "d2", name: "Bob" },
|
|
63
|
+
{ id: "d3", name: "Charlie" },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
```
|
|
26
68
|
|
|
27
|
-
|
|
69
|
+
### The Simplest Tree
|
|
70
|
+
|
|
71
|
+
Use all the defaults. The _initialData_ prop makes the tree an uncontrolled component. Create, move, rename, and delete will be handled internally.
|
|
28
72
|
|
|
29
73
|
```jsx
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
74
|
+
function App() {
|
|
75
|
+
return <Tree initialData={data} />;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Customize the Appearance
|
|
80
|
+
|
|
81
|
+
We provide our own dimensions and our own `Node` component.
|
|
38
82
|
|
|
83
|
+
```jsx
|
|
39
84
|
function App() {
|
|
40
|
-
return
|
|
85
|
+
return (
|
|
86
|
+
<Tree
|
|
87
|
+
initialData={data}
|
|
88
|
+
openByDefault={false}
|
|
89
|
+
width={600}
|
|
90
|
+
height={1000}
|
|
91
|
+
indent={24}
|
|
92
|
+
rowHeight={36}
|
|
93
|
+
paddingTop={30}
|
|
94
|
+
paddingBottom={10}
|
|
95
|
+
padding={25 /* sets both */}
|
|
96
|
+
>
|
|
97
|
+
{Node}
|
|
98
|
+
</Tree>
|
|
99
|
+
);
|
|
41
100
|
}
|
|
42
101
|
|
|
43
|
-
function Node({
|
|
102
|
+
function Node({ node, style, dragHandle }) {
|
|
103
|
+
/* This node instance can do many things. See the API reference. */
|
|
44
104
|
return (
|
|
45
|
-
<div
|
|
46
|
-
|
|
105
|
+
<div style={style} ref={dragHandle}>
|
|
106
|
+
{node.isLeaf ? "🍁" : "🗀"}
|
|
107
|
+
{node.data.name}
|
|
47
108
|
</div>
|
|
48
109
|
);
|
|
49
110
|
}
|
|
50
111
|
```
|
|
51
112
|
|
|
52
|
-
|
|
113
|
+
### Control the Tree data
|
|
53
114
|
|
|
54
|
-
|
|
55
|
-
- [Tree Component API](#tree-component)
|
|
56
|
-
- [Node Renderer API](#node-renderer-component)
|
|
57
|
-
- [Styles Prop](#styles-prop)
|
|
58
|
-
- [State Prop](#state-prop)
|
|
59
|
-
- [Handlers Prop](#handlers-prop)
|
|
60
|
-
- [Tree Prop](#tree-prop)
|
|
61
|
-
- [Accessing the Tree Api from the Parent](#accessing-the-tree-api-from-the-parent)
|
|
115
|
+
Here we use the _data_ prop to make the tree a controlled component. We must handle all the data modifications ourselves using the props below.
|
|
62
116
|
|
|
63
|
-
|
|
117
|
+
```jsx
|
|
118
|
+
function App() {
|
|
119
|
+
/* Handle the data modifications outside the tree component */
|
|
120
|
+
const onCreate = ({ parentId, index, type }) => {};
|
|
121
|
+
const onRename = ({ id, name }) => {};
|
|
122
|
+
const onMove = ({ dragIds, parentId, index }) => {};
|
|
123
|
+
const onDelete = ({ ids }) => {};
|
|
64
124
|
|
|
65
|
-
|
|
125
|
+
return (
|
|
126
|
+
<Tree
|
|
127
|
+
data={data}
|
|
128
|
+
onCreate={onCreate}
|
|
129
|
+
onRename={onRename}
|
|
130
|
+
onMove={onMove}
|
|
131
|
+
onDelete={onDelete}
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
66
136
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
137
|
+
### Tree Filtering
|
|
138
|
+
|
|
139
|
+
Providing a non-empty _searchTerm_ will only show nodes that match. If a child matches, all its parents also match. Internal nodes are opened when filtering. You can provide your own _searchMatch_ function, or use the default.
|
|
140
|
+
|
|
141
|
+
```jsx
|
|
142
|
+
function App() {
|
|
143
|
+
const term = useSearchTermString()
|
|
144
|
+
<Tree
|
|
145
|
+
data={data}
|
|
146
|
+
searchTerm={term}
|
|
147
|
+
searchMatch={
|
|
148
|
+
(node, term) => node.data.name.toLowerCase().includes(term.toLowerCase())
|
|
149
|
+
}
|
|
150
|
+
/>
|
|
73
151
|
}
|
|
74
152
|
```
|
|
75
153
|
|
|
76
|
-
|
|
154
|
+
### Sync the Selection
|
|
77
155
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<Tree childrenAccessor={(node) => node.items} ...
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Tree Component
|
|
85
|
-
|
|
86
|
-
Unlike other Tree Components, react-arborist is designed as a [controlled component](https://reactjs.org/docs/forms.html#controlled-components). This means the consumer will provide the tree data and the handlers to update it. The only state managed internally is for drag and drop, selection, and editing.
|
|
87
|
-
|
|
88
|
-
| Prop | Default | Description |
|
|
89
|
-
| ---------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
90
|
-
| data | (required) | The tree data structure to render as described above. |
|
|
91
|
-
| width | 300 | The width of the tree. |
|
|
92
|
-
| height | 500 | The height of the tree. To dynamically fill it's container, use a [hook](https://github.com/ZeeCoder/use-resize-observer) or [component](https://github.com/bvaughn/react-virtualized-auto-sizer) to gather the width and height of the Tree's parent. |
|
|
93
|
-
| rowHeight | 24 | The height of each row. |
|
|
94
|
-
| indent | 24 | The number of pixels to indent child nodes. |
|
|
95
|
-
| hideRoot | false | Hide the root node so that the first set of children appear as the roots. |
|
|
96
|
-
| onToggle | noop | Handler called when a node is opened or closed. This and the subsequent functions should update the `data` prop for the tree to re-render. |
|
|
97
|
-
| onMove | noop | Handler called when a user moves one or more nodes by dragging and dropping. |
|
|
98
|
-
| onEdit | noop | Handler called when a user performs an inline edit of the node. |
|
|
99
|
-
| childrenAccessor | "children" | Used to get a node's children if they exist on a property other than "children". |
|
|
100
|
-
| isOpenAccessor | "isOpen" | Used to get a node's openness state if it exists on a property other than "isOpen". |
|
|
101
|
-
| openByDefault | true | Choose if the node should be open or closed when it has an undefined openness state. |
|
|
102
|
-
| className | undefined | Adds a class to the containing div. |
|
|
103
|
-
| dndRootElement | undefined | The element for react-dnd to bind it's events to. Defaults to window. See https://github.com/brimdata/react-arborist/pull/33 |
|
|
104
|
-
| dropCursor | ({top, left, indent}) => ReactElement | Provide a custom render function for the drop cursor (the line you see as you drag an item around the tree). It recieves props {left, top, indent} which are all numbers. See the [DefaultDropCursor](https://github.com/brimdata/react-arborist/blob/main/packages/react-arborist/src/components/default-drop-cursor.tsx) for an example of how to create a custom one. |
|
|
105
|
-
|
|
106
|
-
The only child of the Tree Component must be a NodeRenderer function as described below.
|
|
156
|
+
It's common to open something elsewhere in the app, but have the tree reflect the new selection.
|
|
157
|
+
|
|
158
|
+
Passing an id to the _selection_ prop will select and scroll to that node whenever that id changes.
|
|
107
159
|
|
|
108
160
|
```jsx
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}) => ...
|
|
161
|
+
function App() {
|
|
162
|
+
const chatId = useCurrentChatId();
|
|
112
163
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
164
|
+
/*
|
|
165
|
+
Whenever the currentChatRoomId changes,
|
|
166
|
+
the tree will automatically select it and scroll to it.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
return <Tree initialData={data} selection={chatId} />;
|
|
170
|
+
}
|
|
117
171
|
```
|
|
118
172
|
|
|
119
|
-
|
|
173
|
+
### Use the Tree Api Instance
|
|
174
|
+
|
|
175
|
+
You can access the Tree Api in the parent component by giving a ref to the tree.
|
|
176
|
+
|
|
177
|
+
```jsx
|
|
178
|
+
function App() {
|
|
179
|
+
const treeRef = useRef();
|
|
180
|
+
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
const tree = treeRef.current;
|
|
183
|
+
tree.selectAll();
|
|
184
|
+
/* See the Tree API reference for all you can do with it. */
|
|
185
|
+
}, []);
|
|
186
|
+
|
|
187
|
+
return <Tree initialData={data} ref={treeRef} />;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
120
190
|
|
|
121
|
-
|
|
191
|
+
### Data with Different Property Names
|
|
122
192
|
|
|
123
|
-
The
|
|
193
|
+
The _idAccessor_ and _childrenAccessor_ props allow you to specify the children and id fields in your data.
|
|
124
194
|
|
|
125
195
|
```jsx
|
|
126
|
-
function
|
|
196
|
+
function App() {
|
|
197
|
+
const data = [
|
|
198
|
+
{
|
|
199
|
+
category: "Food",
|
|
200
|
+
subCategories: [{ category: "Restaurants" }, { category: "Groceries" }],
|
|
201
|
+
},
|
|
202
|
+
];
|
|
127
203
|
return (
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
204
|
+
<Tree
|
|
205
|
+
data={data}
|
|
206
|
+
/* An accessor can provide a string property name */
|
|
207
|
+
idAccessor="category"
|
|
208
|
+
/* or a function with the data as the argument */
|
|
209
|
+
childrenAccessor={(d) => d.subCategories}
|
|
210
|
+
/>
|
|
131
211
|
);
|
|
132
212
|
}
|
|
133
213
|
```
|
|
134
214
|
|
|
135
|
-
|
|
215
|
+
### Custom Rendering
|
|
136
216
|
|
|
137
|
-
|
|
138
|
-
| -------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
139
|
-
| data | Node | A single node from the tree data structure provided. |
|
|
140
|
-
| innerRef | Ref | Must be attached to the root element returned by the NodeRenderer. This is needed for drag and drop to work. |
|
|
141
|
-
| [styles](#styles-prop) | object | This is an object that contains styles for the position of the row, and the level of indentation. Each key is described below. |
|
|
142
|
-
| [state](#state-prop) | object | An handful of boolean values that indicate the current state of this node. See below for details. |
|
|
143
|
-
| [handlers](#handlers-prop) | object | A collection of handlers to attach to the DOM, that provide selectable and toggle-able behaviors. Each handler is described below. |
|
|
144
|
-
| [tree](#tree-prop) | TreeMonitor | This object can be used to get at the internal state of the whole tree component. For example, `tree.getSelectedNodes()`. All the methods are listed below in the Tree Prop section. |
|
|
217
|
+
Render every single piece of the tree yourself. See the API reference for the props passed to each renderer.
|
|
145
218
|
|
|
146
|
-
|
|
219
|
+
```jsx
|
|
220
|
+
function App() {
|
|
221
|
+
return (
|
|
222
|
+
<Tree
|
|
223
|
+
data={data}
|
|
224
|
+
/* The outer most element in the list */
|
|
225
|
+
renderRow={MyRow}
|
|
226
|
+
/* The "ghost" element that follows the mouse as you drag */
|
|
227
|
+
renderDragPreview={MyDragPreview}
|
|
228
|
+
/* The line that shows where an element will be dropped */
|
|
229
|
+
renderCursor={MyCursor}
|
|
230
|
+
>
|
|
231
|
+
{/* The inner element that shows the indentation and data */}
|
|
232
|
+
{MyNode}
|
|
233
|
+
</Tree>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
147
237
|
|
|
148
|
-
|
|
238
|
+
## API Reference
|
|
149
239
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
240
|
+
- Components
|
|
241
|
+
- [Tree Component Props](#tree-component-props)
|
|
242
|
+
- [Row Component Props](#row-component-props)
|
|
243
|
+
- [Node Component Props](#node-component-props)
|
|
244
|
+
- [DragPreview Component Props](#dragpreview-component-props)
|
|
245
|
+
- [Cursor Component Props](#cursor-component-props)
|
|
246
|
+
- Interfaces
|
|
247
|
+
- [Node API](#node-api-reference)
|
|
248
|
+
- [Tree API](#tree-api-reference)
|
|
154
249
|
|
|
155
|
-
|
|
250
|
+
## Tree Component Props
|
|
156
251
|
|
|
157
|
-
These are the
|
|
252
|
+
These are all the props you can pass to the Tree component.
|
|
158
253
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
254
|
+
```ts
|
|
255
|
+
interface TreeProps<T extends IdObj> {
|
|
256
|
+
/* Data Options */
|
|
257
|
+
data?: T[];
|
|
258
|
+
initialData?: T[];
|
|
259
|
+
|
|
260
|
+
/* Data Handlers */
|
|
261
|
+
onCreate?: handlers.CreateHandler;
|
|
262
|
+
onMove?: handlers.MoveHandler;
|
|
263
|
+
onRename?: handlers.RenameHandler;
|
|
264
|
+
onDelete?: handlers.DeleteHandler;
|
|
265
|
+
|
|
266
|
+
/* Renderers*/
|
|
267
|
+
children?: ElementType<renderers.NodeRendererProps<T>>;
|
|
268
|
+
renderRow?: ElementType<renderers.RowRendererProps<T>>;
|
|
269
|
+
renderDragPreview?: ElementType<renderers.DragPreviewProps>;
|
|
270
|
+
renderCursor?: ElementType<renderers.DropCursorProps>;
|
|
271
|
+
renderContainer?: ElementType<{}>;
|
|
272
|
+
|
|
273
|
+
/* Sizes */
|
|
274
|
+
rowHeight?: number;
|
|
275
|
+
width?: number;
|
|
276
|
+
height?: number;
|
|
277
|
+
indent?: number;
|
|
278
|
+
paddingTop?: number;
|
|
279
|
+
paddingBottom?: number;
|
|
280
|
+
padding?: number;
|
|
281
|
+
|
|
282
|
+
/* Config */
|
|
283
|
+
openByDefault?: boolean;
|
|
284
|
+
selectionFollowsFocus?: boolean;
|
|
285
|
+
disableDrag?: string | boolean | BoolFunc<T>;
|
|
286
|
+
disableDrop?: string | boolean | BoolFunc<T>;
|
|
287
|
+
childrenAccessor?: string | ((d: T) => T[]);
|
|
288
|
+
idAccessor?: string | ((d: T) => string);
|
|
289
|
+
|
|
290
|
+
/* Event Handlers */
|
|
291
|
+
onActivate?: (node: NodeApi<T>) => void;
|
|
292
|
+
onSelect?: (nodes: NodeApi<T>[]) => void;
|
|
293
|
+
onScroll?: (props: ListOnScrollProps) => void;
|
|
294
|
+
|
|
295
|
+
/* Selection */
|
|
296
|
+
selection?: string;
|
|
297
|
+
|
|
298
|
+
/* Open State */
|
|
299
|
+
initialOpenState?: OpenMap;
|
|
300
|
+
|
|
301
|
+
/* Search */
|
|
302
|
+
searchTerm?: string;
|
|
303
|
+
searchMatch?: (node: NodeApi<T>, searchTerm: string) => boolean;
|
|
304
|
+
|
|
305
|
+
/* Extra */
|
|
306
|
+
className?: string | undefined;
|
|
307
|
+
dndRootElement?: globalThis.Node | null;
|
|
308
|
+
onClick?: MouseEventHandler;
|
|
309
|
+
onContextMenu?: MouseEventHandler;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Row Component Props
|
|
168
314
|
|
|
169
|
-
|
|
315
|
+
The _\<RowRenderer\>_ is responsible for attaching the drop ref, the row style (top, height) and the aria-attributes. The default should work fine for most use cases, but it can be replaced by your own component if you need. See the _renderRow_ prop in the _\<Tree\>_ component.
|
|
170
316
|
|
|
171
|
-
|
|
317
|
+
```ts
|
|
318
|
+
type RowRendererProps<T extends IdObj> = {
|
|
319
|
+
node: NodeApi<T>;
|
|
320
|
+
innerRef: (el: HTMLDivElement | null) => void;
|
|
321
|
+
attrs: HTMLAttributes<any>;
|
|
322
|
+
children: ReactElement;
|
|
323
|
+
};
|
|
324
|
+
```
|
|
172
325
|
|
|
173
|
-
|
|
174
|
-
| ------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
175
|
-
| select | MouseEventHandler | Attach this to the element that tiggers selection. Maybe you want to add it to the outermost div. <br /> `<div onClick={handlers.select}>` |
|
|
176
|
-
| toggle | MouseEventHandler | Attach this to the element that opens and closes the node. Maybe you want to add it to the `+`/`-` icon. <br />`<icon onClick={handlers.toggle}>` |
|
|
177
|
-
| edit | `() => void` | Makes this node editable. This will re-render the Node with the `state.isEditing` prop set to `true`. |
|
|
178
|
-
| submit | `(update: string) => void` | Sends the update to the `onEdit` handler in the Tree component, and sets the `state.isEditing` prop to `false`. |
|
|
179
|
-
| reset | `() => void` | Re-renders with the `state.isEditing` prop set to `false`. |
|
|
326
|
+
## Node Component Props
|
|
180
327
|
|
|
181
|
-
|
|
328
|
+
The _\<NodeRenderer\>_ is responsible for attaching the drag ref, the node style (padding for indentation), the visual look of the node, the edit input of the node, and anything else you can dream up.
|
|
182
329
|
|
|
183
|
-
|
|
330
|
+
There is a default renderer, but it's only there as a placeholder to get started. You'll wan't to create your own component for this. It is passed as the _\<Tree\>_ components only child.
|
|
184
331
|
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
tree
|
|
190
|
-
|
|
332
|
+
```ts
|
|
333
|
+
export type NodeRendererProps<T extends IdObj> = {
|
|
334
|
+
style: CSSProperties;
|
|
335
|
+
node: NodeApi<T>;
|
|
336
|
+
tree: TreeApi<T>;
|
|
337
|
+
dragHandle?: (el: HTMLDivElement | null) => void;
|
|
338
|
+
preview?: boolean;
|
|
339
|
+
};
|
|
191
340
|
```
|
|
192
341
|
|
|
193
|
-
|
|
194
|
-
| ----------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
195
|
-
| `getSelectedIds()` | `string[]` | Get the the ids of all currently selected nodes. |
|
|
196
|
-
| `edit(id: string)` | `Promise<{cancelled: boolean, value: string \| undefined}>` | Edit a node programatically. Resolves when the edit is finished or cancelled. |
|
|
197
|
-
| `submit(id: string, value: string)` | void | Submit the edit. |
|
|
198
|
-
| `reset(id: string)` | void | Cancel the edit. |
|
|
199
|
-
| `select(index: number, meta = false, shift = false)` | `void` | Select a node by it's visible index in the tree. The meta flag, when true, will allow multiple items to be selected. The shift flag, when true, will select all nodes between the last one selected, and this one. |
|
|
200
|
-
| `selectById(id: string, meta = false, shift = false)` | `void` | Same as above but selects by id. If the id is not present (in a collapsed folder), nothing will happen. First use the `scrollToId` function which will open all the parents and scroll to the id. |
|
|
201
|
-
| `scrollToId(id: string)` | void | Scroll to the id opening all it's parents if needed. |
|
|
342
|
+
## DragPreview Component Props
|
|
202
343
|
|
|
203
|
-
|
|
344
|
+
The _\<DragPreview\>_ is responsible for showing a "ghost" version of the node being dragged. The default is a semi-transparent version of the NodeRenderer and should work fine for most people. To customize it, pass your new component to the _renderDragPreview_ prop.
|
|
204
345
|
|
|
205
|
-
|
|
346
|
+
```ts
|
|
347
|
+
type DragPreviewProps = {
|
|
348
|
+
offset: XYCoord | null;
|
|
349
|
+
mouse: XYCoord | null;
|
|
350
|
+
id: string | null;
|
|
351
|
+
dragIds: string[];
|
|
352
|
+
isDragging: boolean;
|
|
353
|
+
};
|
|
354
|
+
```
|
|
206
355
|
|
|
207
|
-
|
|
356
|
+
## Cursor Component Props
|
|
208
357
|
|
|
209
|
-
|
|
210
|
-
function MySection() {
|
|
211
|
-
const tree = useRef(null)
|
|
358
|
+
The _\<Cursor\>_ is responsible for showing a line that indicates where the node will move to when it's dropped. The default is a blue line with circle on the left side. You may want to customize this. Pass your own component to the _renderCursor_ prop.
|
|
212
359
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
360
|
+
```ts
|
|
361
|
+
export type DropCursorProps = {
|
|
362
|
+
top: number;
|
|
363
|
+
left: number;
|
|
364
|
+
indent: number;
|
|
365
|
+
};
|
|
366
|
+
```
|
|
216
367
|
|
|
217
|
-
|
|
218
|
-
|
|
368
|
+
## Node API Reference
|
|
369
|
+
|
|
370
|
+
#### State Properties
|
|
371
|
+
|
|
372
|
+
All these properties on the node instance return booleans related to the state of the node.
|
|
373
|
+
|
|
374
|
+
_node_.**isRoot**
|
|
375
|
+
|
|
376
|
+
Returns true if this is the root node. The root node is added internally by react-arborist and not shown in the UI.
|
|
377
|
+
|
|
378
|
+
_node_.**isLeaf**
|
|
379
|
+
|
|
380
|
+
Returns true if the children property is not an array.
|
|
381
|
+
|
|
382
|
+
_node_.**isInternal**
|
|
383
|
+
|
|
384
|
+
Returns true if the children property is an array.
|
|
385
|
+
|
|
386
|
+
_node_.**isOpen**
|
|
387
|
+
|
|
388
|
+
Returns true if node is internal and in an open state.
|
|
389
|
+
|
|
390
|
+
_node_.**isEditing**
|
|
391
|
+
|
|
392
|
+
Returns true if this node is currently being edited. Use this property in the NodeRenderer to render the rename form.
|
|
393
|
+
|
|
394
|
+
_node_.**isSelected**
|
|
395
|
+
|
|
396
|
+
Returns true if node is selected.
|
|
397
|
+
|
|
398
|
+
_node_.**isSelectedStart**
|
|
399
|
+
|
|
400
|
+
Returns true if node is the first of a contiguous group of selected nodes. Useful for styling.
|
|
401
|
+
|
|
402
|
+
_node_.**isSelectedEnd**
|
|
403
|
+
|
|
404
|
+
Returns true if node is the last of a contiguous group of selected nodes. Useful for styling.
|
|
405
|
+
|
|
406
|
+
_node_.**isFocused**
|
|
407
|
+
|
|
408
|
+
Returns true if node is focused.
|
|
409
|
+
|
|
410
|
+
_node_.**isDragging**
|
|
411
|
+
|
|
412
|
+
Returns true if node is being dragged.
|
|
413
|
+
|
|
414
|
+
_node_.**willReceiveDrop**
|
|
415
|
+
|
|
416
|
+
Returns true if node is internal and the user is hovering a dragged node over it.
|
|
417
|
+
|
|
418
|
+
_node_.**state**
|
|
419
|
+
|
|
420
|
+
Returns an object with all the above properties as keys and boolean values. Useful for adding class names to an element with a library like [clsx](https://github.com/lukeed/clsx) or [classnames](https://github.com/JedWatson/classnames).
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
type NodeState = {
|
|
424
|
+
isEditing: boolean;
|
|
425
|
+
isDragging: boolean;
|
|
426
|
+
isSelected: boolean;
|
|
427
|
+
isSelectedStart: boolean;
|
|
428
|
+
isSelectedEnd: boolean;
|
|
429
|
+
isFocused: boolean;
|
|
430
|
+
isOpen: boolean;
|
|
431
|
+
willReceiveDrop: boolean;
|
|
432
|
+
};
|
|
219
433
|
```
|
|
220
434
|
|
|
221
|
-
|
|
435
|
+
#### Accessors
|
|
436
|
+
|
|
437
|
+
_node_.**childIndex**
|
|
438
|
+
|
|
439
|
+
Returns the node's index in relation to its siblings.
|
|
440
|
+
|
|
441
|
+
_node_.**next**
|
|
442
|
+
|
|
443
|
+
Returns the next visible node. The node directly under this node in the tree component. Returns null if none exist.
|
|
444
|
+
|
|
445
|
+
_node_.**prev**
|
|
446
|
+
|
|
447
|
+
Returns the previous visible node. The node directly above this node in the tree component. Returns null if none exist.
|
|
448
|
+
|
|
449
|
+
_node_.**nextSibling**
|
|
450
|
+
|
|
451
|
+
Returns the next sibling in the data of this node. Returns null if none exist.
|
|
452
|
+
|
|
453
|
+
#### Selection Methods
|
|
454
|
+
|
|
455
|
+
_node_.**select**()
|
|
456
|
+
|
|
457
|
+
Select only this node.
|
|
458
|
+
|
|
459
|
+
_node_.**deselect**()
|
|
460
|
+
|
|
461
|
+
Deselect this node. Other nodes may still be selected.
|
|
462
|
+
|
|
463
|
+
_node_.**selectMulti**()
|
|
464
|
+
|
|
465
|
+
Select this node while maintaining all other selections.
|
|
466
|
+
|
|
467
|
+
_node_.**selectContiguous**()
|
|
468
|
+
|
|
469
|
+
Deselect all nodes from the anchor node to the last selected node, the select all nodes from the anchor node to this node. The anchor changes to the focused node after calling _select()_ or _selectMulti()_.
|
|
470
|
+
|
|
471
|
+
#### Activation Methods
|
|
472
|
+
|
|
473
|
+
_node_.**activate**()
|
|
474
|
+
|
|
475
|
+
Runs the Tree props' onActivate callback passing in this node.
|
|
476
|
+
|
|
477
|
+
_node_.**focus**()
|
|
478
|
+
|
|
479
|
+
Focus this node.
|
|
480
|
+
|
|
481
|
+
#### Open/Close Methods
|
|
482
|
+
|
|
483
|
+
_node_.**open**()
|
|
484
|
+
|
|
485
|
+
Opens the node if it is an internal node.
|
|
486
|
+
|
|
487
|
+
_node_.**close**()
|
|
488
|
+
|
|
489
|
+
Closes the node if it is an internal node.
|
|
490
|
+
|
|
491
|
+
_node_.**toggle**()
|
|
492
|
+
|
|
493
|
+
Toggles the open/closed state of the node if it is an internal node.
|
|
494
|
+
|
|
495
|
+
_node_.**openParents**()
|
|
496
|
+
|
|
497
|
+
Opens all the parents of this node.
|
|
498
|
+
|
|
499
|
+
_node_.**edit**()
|
|
500
|
+
|
|
501
|
+
Moves this node into the editing state. Calling node._isEditing_ will return true.
|
|
502
|
+
|
|
503
|
+
_node_.**submit**(_newName_)
|
|
504
|
+
|
|
505
|
+
Submits _newName_ string to the _onRename_ handler. Moves this node out of the editing state.
|
|
506
|
+
|
|
507
|
+
_node_.**reset**()
|
|
508
|
+
|
|
509
|
+
Moves this node out of the editing state without submitting a new name.
|
|
510
|
+
|
|
511
|
+
#### Event Handlers
|
|
512
|
+
|
|
513
|
+
_node_.**handleClick**(_event_)
|
|
514
|
+
|
|
515
|
+
Useful for using the standard selection methods when a node is clicked. If the meta key is down, call _multiSelect()_. If the shift key is down, call _selectContiguous()_. Otherwise, call _select()_ and _activate()_.
|
|
516
|
+
|
|
517
|
+
## Tree API Reference
|
|
518
|
+
|
|
519
|
+
The tree api reference is stable across re-renders. It always has the most recent state and props.
|
|
520
|
+
|
|
521
|
+
#### Node Accessors
|
|
522
|
+
|
|
523
|
+
_tree_.**get**(_id_) : _NodeApi | null_
|
|
524
|
+
|
|
525
|
+
Get node by id from the _visibleNodes_ array.
|
|
526
|
+
|
|
527
|
+
_tree_.**at**(_index_) : _NodeApi | null_
|
|
528
|
+
|
|
529
|
+
Get node by index from the _visibleNodes_ array.
|
|
530
|
+
|
|
531
|
+
_tree_.**visibleNodes** : _NodeApi[]_
|
|
532
|
+
|
|
533
|
+
Returns an array of the visible nodes.
|
|
534
|
+
|
|
535
|
+
_tree_.**firstNode** : _NodeApi | null_
|
|
536
|
+
|
|
537
|
+
The first node in the _visibleNodes_ array.
|
|
538
|
+
|
|
539
|
+
_tree_.**lastNode** : _NodeApi | null_
|
|
540
|
+
|
|
541
|
+
The last node in the _visibleNodes_ array.
|
|
542
|
+
|
|
543
|
+
_tree_.**focusedNode** : _NodeApi | null_
|
|
544
|
+
|
|
545
|
+
The currently focused node.
|
|
546
|
+
|
|
547
|
+
_tree_.**mostRecentNode** : _NodeApi | null_
|
|
548
|
+
|
|
549
|
+
The most recently selected node.
|
|
550
|
+
|
|
551
|
+
_tree_.**nextNode** : _NodeApi | null_
|
|
552
|
+
|
|
553
|
+
The node directly after the _focusedNode_ in the _visibleNodes_ array.
|
|
554
|
+
|
|
555
|
+
_tree_.**prevNode** : _NodeApi | null_
|
|
556
|
+
|
|
557
|
+
The node directly before the _focusedNode_ in the _visibleNodes_ array.
|
|
558
|
+
|
|
559
|
+
#### Focus Methods
|
|
560
|
+
|
|
561
|
+
_tree_.**hasFocus** : _boolean_
|
|
562
|
+
|
|
563
|
+
Returns true if the the tree has focus somewhere within it.
|
|
564
|
+
|
|
565
|
+
_tree_.**focus**(_id_)
|
|
566
|
+
|
|
567
|
+
Focus on the node with _id_.
|
|
568
|
+
|
|
569
|
+
_tree_.**isFocused**(_id_) : _boolean_
|
|
570
|
+
|
|
571
|
+
Check if the node with _id_ is focused.
|
|
572
|
+
|
|
573
|
+
_tree_.**pageUp**()
|
|
574
|
+
|
|
575
|
+
Move focus up one page.
|
|
576
|
+
|
|
577
|
+
_tree_.**pageDown**()
|
|
578
|
+
|
|
579
|
+
Move focus down one page.
|
|
580
|
+
|
|
581
|
+
#### Selection Methods
|
|
582
|
+
|
|
583
|
+
_tree_.**selectedIds** : _Set\<string\>_
|
|
584
|
+
|
|
585
|
+
Returns a set of ids that are selected.
|
|
586
|
+
|
|
587
|
+
_tree_.**selectedNodes** : _NodeApi[]_
|
|
588
|
+
|
|
589
|
+
Returns an array of nodes that are selected.
|
|
590
|
+
|
|
591
|
+
_tree_.**isSelected**(_id_) : _boolean_
|
|
592
|
+
|
|
593
|
+
Returns true if the node with _id_ is selected.
|
|
594
|
+
|
|
595
|
+
_tree_.**select**(_id_)
|
|
596
|
+
|
|
597
|
+
Select only the node with _id_.
|
|
598
|
+
|
|
599
|
+
_tree_.**deselect**(_id_)
|
|
600
|
+
|
|
601
|
+
Deselect the node with _id_.
|
|
602
|
+
|
|
603
|
+
_tree_.**selectMulti**(_id_)
|
|
604
|
+
|
|
605
|
+
Add to the selection the node with _id_.
|
|
606
|
+
|
|
607
|
+
_tree_.**selectContiguous**(_id_)
|
|
608
|
+
|
|
609
|
+
Deselected nodes between the anchor and the last selected node, then select the nodes between the anchor and the node with _id_.
|
|
610
|
+
|
|
611
|
+
_tree_.**deselectAll**()
|
|
612
|
+
|
|
613
|
+
Deselect all nodes.
|
|
614
|
+
|
|
615
|
+
_tree_.**selectAll**()
|
|
616
|
+
|
|
617
|
+
Select all nodes.
|
|
618
|
+
|
|
619
|
+
#### Visibility
|
|
620
|
+
|
|
621
|
+
_tree_.**open**(_id_)
|
|
622
|
+
|
|
623
|
+
Open the node with _id_.
|
|
624
|
+
|
|
625
|
+
_tree_.**close**(_id_)
|
|
626
|
+
|
|
627
|
+
Close the node with _id_.
|
|
628
|
+
|
|
629
|
+
_tree_.**toggle**(_id_)
|
|
630
|
+
|
|
631
|
+
Toggle the open state of the node with _id_.
|
|
632
|
+
|
|
633
|
+
_tree_.**openParents**(_id_)
|
|
634
|
+
|
|
635
|
+
Open all parents of the node with _id_.
|
|
636
|
+
|
|
637
|
+
_tree_.**openSiblings**(_id_)
|
|
638
|
+
|
|
639
|
+
Open all siblings of the node with _id_.
|
|
640
|
+
|
|
641
|
+
_tree_.**isOpen**(_id_) : _boolean_
|
|
642
|
+
|
|
643
|
+
Returns true if the node with _id_ is open.
|
|
644
|
+
|
|
645
|
+
#### Drag and Drop
|
|
646
|
+
|
|
647
|
+
_tree_.**isDragging**(_id_) : _boolean_
|
|
648
|
+
|
|
649
|
+
Returns true if the node with _id_ is being dragged.
|
|
650
|
+
|
|
651
|
+
_tree_.**willReceiveDrop**(_id_) : _boolean_
|
|
652
|
+
|
|
653
|
+
Returns true if the node with _id_ is internal and is under the dragged node.
|
|
654
|
+
|
|
655
|
+
#### Scrolling
|
|
656
|
+
|
|
657
|
+
_tree_.**scrollTo**(_id_, _[align]_)
|
|
658
|
+
|
|
659
|
+
Scroll to the node with _id_. If this node is not visible, this method will open all its parents. The align argument can be _"auto" | "smart" | "center" | "end" | "start"_.
|
|
660
|
+
|
|
661
|
+
#### Properties
|
|
662
|
+
|
|
663
|
+
_tree_.**isEditing** : _boolean_
|
|
664
|
+
|
|
665
|
+
Returns true if the tree is editing a node.
|
|
666
|
+
|
|
667
|
+
_tree_.**isFiltered** : _boolean_
|
|
668
|
+
|
|
669
|
+
Returns true if the _searchTerm_ prop is not an empty string when trimmed.
|
|
670
|
+
|
|
671
|
+
_tree_.**props** : _TreeProps_
|
|
672
|
+
|
|
673
|
+
Returns all the props that were passed to the _\<Tree\>_ component.
|
|
674
|
+
|
|
675
|
+
_tree_.**root** : _NodeApi_
|
|
676
|
+
|
|
677
|
+
Returns the root _NodeApi_ instance. Its children are the Node representations of the _data_ prop array.
|
|
678
|
+
|
|
679
|
+
## Author
|
|
680
|
+
|
|
681
|
+
This library was created by James Kerr while working at Brim Data on the [Zui desktop app](https://www.youtube.com/watch?v=I2y663n8d2A). Work with data? Check us out at [brimdata.io](https://www.brimdata.io)
|
|
682
|
+
|
|
683
|
+
[Follow me on Twitter](https://twitter.com/specialCaseDev) for react-arborist updates.
|