react-arborist 2.0.0-rc → 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 +683 -0
- package/dist/components/default-container.d.ts +5 -0
- package/dist/components/default-node.d.ts +1 -1
- package/dist/index.js +75 -29
- package/dist/index.js.map +1 -1
- package/dist/interfaces/node-api.d.ts +4 -4
- package/dist/interfaces/tree-api.d.ts +3 -2
- package/dist/module.js +74 -28
- package/dist/module.js.map +1 -1
- package/dist/types/tree-props.d.ts +2 -1
- package/package.json +2 -1
- package/src/components/default-container.tsx +9 -0
- package/src/components/default-node.tsx +43 -8
- package/src/components/list-outer-element.tsx +1 -1
- package/src/components/provider.tsx +1 -1
- package/src/data/create-root.ts +3 -2
- package/src/interfaces/node-api.ts +23 -23
- package/src/interfaces/tree-api.ts +14 -9
- package/src/types/tree-props.ts +2 -1
- package/tsconfig.json +1 -1
- package/dist/data/flatten-tree.d.ts +0 -4
- package/dist/hooks/use-uncontrolled-tree.d.ts +0 -24
- package/dist/utils/props.d.ts +0 -3
- package/src/utils/props.ts +0 -8
|
@@ -28,7 +28,8 @@ export interface TreeProps<T extends IdObj> {
|
|
|
28
28
|
selectionFollowsFocus?: boolean;
|
|
29
29
|
disableDrag?: string | boolean | BoolFunc<T>;
|
|
30
30
|
disableDrop?: string | boolean | BoolFunc<T>;
|
|
31
|
-
|
|
31
|
+
childrenAccessor?: string | ((d: T) => T[]);
|
|
32
|
+
idAccessor?: string | ((d: T) => string);
|
|
32
33
|
onActivate?: (node: NodeApi<T>) => void;
|
|
33
34
|
onSelect?: (nodes: NodeApi<T>[]) => void;
|
|
34
35
|
onScroll?: (props: ListOnScrollProps) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-arborist",
|
|
3
|
-
"version": "2.0.0-rc",
|
|
3
|
+
"version": "2.0.0-rc.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"react-dom": ">= 16.14"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
+
"@parcel/core": "^2.3.2",
|
|
32
33
|
"@types/jest": "^27.4.1",
|
|
33
34
|
"@types/react": "^18.0.0",
|
|
34
35
|
"@types/react-window": "^1.8.5",
|
|
@@ -8,6 +8,11 @@ import { RowContainer } from "./row-container";
|
|
|
8
8
|
let focusSearchTerm = "";
|
|
9
9
|
let timeoutId: any = null;
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* All these keyboard shortcuts seem like they should be configurable.
|
|
13
|
+
* Each operation should be a given a name and separated from
|
|
14
|
+
* the event handler. Future clean up welcome.
|
|
15
|
+
*/
|
|
11
16
|
export function DefaultContainer() {
|
|
12
17
|
useDataUpdates();
|
|
13
18
|
const tree = useTreeApi();
|
|
@@ -37,6 +42,7 @@ export function DefaultContainer() {
|
|
|
37
42
|
return;
|
|
38
43
|
}
|
|
39
44
|
if (e.key === "Backspace") {
|
|
45
|
+
if (!tree.props.onDelete) return;
|
|
40
46
|
const ids = Array.from(tree.selectedIds);
|
|
41
47
|
if (ids.length > 1) {
|
|
42
48
|
let nextFocus = tree.mostRecentNode;
|
|
@@ -129,10 +135,12 @@ export function DefaultContainer() {
|
|
|
129
135
|
return;
|
|
130
136
|
}
|
|
131
137
|
if (e.key === "a" && !e.metaKey) {
|
|
138
|
+
if (!tree.props.onCreate) return;
|
|
132
139
|
tree.createLeaf();
|
|
133
140
|
return;
|
|
134
141
|
}
|
|
135
142
|
if (e.key === "A" && !e.metaKey) {
|
|
143
|
+
if (!tree.props.onCreate) return;
|
|
136
144
|
tree.createInternal();
|
|
137
145
|
return;
|
|
138
146
|
}
|
|
@@ -150,6 +158,7 @@ export function DefaultContainer() {
|
|
|
150
158
|
return;
|
|
151
159
|
}
|
|
152
160
|
if (e.key === "Enter") {
|
|
161
|
+
if (!tree.props.onRename) return;
|
|
153
162
|
setTimeout(() => {
|
|
154
163
|
if (tree.focusedNode) tree.edit(tree.focusedNode);
|
|
155
164
|
});
|
|
@@ -1,15 +1,50 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useEffect, useRef } from "react";
|
|
2
2
|
import { NodeRendererProps } from "../types/renderers";
|
|
3
3
|
import { IdObj } from "../types/utils";
|
|
4
4
|
|
|
5
|
-
export function DefaultNode<T extends IdObj>({
|
|
6
|
-
style,
|
|
7
|
-
node,
|
|
8
|
-
dragHandle,
|
|
9
|
-
}: NodeRendererProps<T>) {
|
|
5
|
+
export function DefaultNode<T extends IdObj>(props: NodeRendererProps<T>) {
|
|
10
6
|
return (
|
|
11
|
-
<div
|
|
12
|
-
|
|
7
|
+
<div ref={props.dragHandle} style={props.style}>
|
|
8
|
+
<span
|
|
9
|
+
onClick={(e) => {
|
|
10
|
+
e.stopPropagation();
|
|
11
|
+
props.node.toggle();
|
|
12
|
+
}}
|
|
13
|
+
>
|
|
14
|
+
{props.node.isLeaf ? "🌳" : props.node.isOpen ? "🗁" : "🗀"}
|
|
15
|
+
</span>{" "}
|
|
16
|
+
{props.node.isEditing ? <Edit {...props} /> : <Show {...props} />}
|
|
13
17
|
</div>
|
|
14
18
|
);
|
|
15
19
|
}
|
|
20
|
+
|
|
21
|
+
function Show<T extends IdObj>(props: NodeRendererProps<T>) {
|
|
22
|
+
return (
|
|
23
|
+
<>
|
|
24
|
+
{/* @ts-ignore */}
|
|
25
|
+
<span>{props.node.data.name}</span>
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function Edit<T extends IdObj>({ node }: NodeRendererProps<T>) {
|
|
31
|
+
const input = useRef<any>();
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
input.current?.focus();
|
|
35
|
+
input.current?.select();
|
|
36
|
+
}, []);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<input
|
|
40
|
+
ref={input}
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
defaultValue={node.data.name}
|
|
43
|
+
onBlur={() => node.reset()}
|
|
44
|
+
onKeyDown={(e) => {
|
|
45
|
+
if (e.key === "Escape") node.reset();
|
|
46
|
+
if (e.key === "Enter") node.submit(input.current?.value || "");
|
|
47
|
+
}}
|
|
48
|
+
></input>
|
|
49
|
+
);
|
|
50
|
+
}
|
package/src/data/create-root.ts
CHANGED
|
@@ -10,18 +10,19 @@ export function createRoot<T extends IdObj>(tree: TreeApi<T>): NodeApi<T> {
|
|
|
10
10
|
level: number,
|
|
11
11
|
parent: NodeApi<T> | null
|
|
12
12
|
) {
|
|
13
|
+
const id = tree.accessId(data);
|
|
13
14
|
const node = new NodeApi<T>({
|
|
14
15
|
tree,
|
|
15
16
|
data,
|
|
16
17
|
level,
|
|
17
18
|
parent,
|
|
18
|
-
id
|
|
19
|
+
id,
|
|
19
20
|
children: null,
|
|
20
21
|
isDraggable: tree.isDraggable(data),
|
|
21
22
|
isDroppable: tree.isDroppable(data),
|
|
22
23
|
rowIndex: null,
|
|
23
24
|
});
|
|
24
|
-
const children = tree.
|
|
25
|
+
const children = tree.accessChildren(data);
|
|
25
26
|
if (children) {
|
|
26
27
|
node.children = children.map((child: T) =>
|
|
27
28
|
visitSelfAndChildren(child, level + 1, node)
|
|
@@ -38,21 +38,6 @@ export class NodeApi<T extends IdObj = IdObj> {
|
|
|
38
38
|
this.rowIndex = params.rowIndex;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
get next(): NodeApi<T> | null {
|
|
42
|
-
if (this.rowIndex === null) return null;
|
|
43
|
-
return this.tree.at(this.rowIndex + 1);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
get prev(): NodeApi<T> | null {
|
|
47
|
-
if (this.rowIndex === null) return null;
|
|
48
|
-
return this.tree.at(this.rowIndex - 1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
get nextSibling(): NodeApi<T> | null {
|
|
52
|
-
const i = this.childIndex;
|
|
53
|
-
return this.parent?.children![i + 1] ?? null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
41
|
get isRoot() {
|
|
57
42
|
return this.id === ROOT_ID;
|
|
58
43
|
}
|
|
@@ -89,14 +74,6 @@ export class NodeApi<T extends IdObj = IdObj> {
|
|
|
89
74
|
return this.tree.isFocused(this.id);
|
|
90
75
|
}
|
|
91
76
|
|
|
92
|
-
get childIndex() {
|
|
93
|
-
if (this.parent && this.parent.children) {
|
|
94
|
-
return this.parent.children.findIndex((child) => child.id === this.id);
|
|
95
|
-
} else {
|
|
96
|
-
return -1;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
77
|
get isDragging() {
|
|
101
78
|
return this.tree.isDragging(this.id);
|
|
102
79
|
}
|
|
@@ -118,6 +95,29 @@ export class NodeApi<T extends IdObj = IdObj> {
|
|
|
118
95
|
};
|
|
119
96
|
}
|
|
120
97
|
|
|
98
|
+
get childIndex() {
|
|
99
|
+
if (this.parent && this.parent.children) {
|
|
100
|
+
return this.parent.children.findIndex((child) => child.id === this.id);
|
|
101
|
+
} else {
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get next(): NodeApi<T> | null {
|
|
107
|
+
if (this.rowIndex === null) return null;
|
|
108
|
+
return this.tree.at(this.rowIndex + 1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get prev(): NodeApi<T> | null {
|
|
112
|
+
if (this.rowIndex === null) return null;
|
|
113
|
+
return this.tree.at(this.rowIndex - 1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
get nextSibling(): NodeApi<T> | null {
|
|
117
|
+
const i = this.childIndex;
|
|
118
|
+
return this.parent?.children![i + 1] ?? null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
121
|
select() {
|
|
122
122
|
this.tree.select(this);
|
|
123
123
|
}
|
|
@@ -2,12 +2,7 @@ import { EditResult } from "../types/handlers";
|
|
|
2
2
|
import { Identity, IdObj } from "../types/utils";
|
|
3
3
|
import { TreeProps } from "../types/tree-props";
|
|
4
4
|
import { MutableRefObject } from "react";
|
|
5
|
-
import {
|
|
6
|
-
Align,
|
|
7
|
-
FixedSizeList,
|
|
8
|
-
ListOnItemsRenderedProps,
|
|
9
|
-
ListOnScrollProps,
|
|
10
|
-
} from "react-window";
|
|
5
|
+
import { Align, FixedSizeList, ListOnItemsRenderedProps } from "react-window";
|
|
11
6
|
import * as utils from "../utils";
|
|
12
7
|
import { DefaultCursor } from "../components/default-cursor";
|
|
13
8
|
import { DefaultRow } from "../components/default-row";
|
|
@@ -102,11 +97,21 @@ export class TreeApi<T extends IdObj> {
|
|
|
102
97
|
return (node: NodeApi<T>) => match(node, this.searchTerm);
|
|
103
98
|
}
|
|
104
99
|
|
|
105
|
-
|
|
106
|
-
const get = this.props.
|
|
100
|
+
accessChildren(data: T) {
|
|
101
|
+
const get = this.props.childrenAccessor || "children";
|
|
107
102
|
return utils.access<T[] | undefined>(data, get) ?? null;
|
|
108
103
|
}
|
|
109
104
|
|
|
105
|
+
accessId(data: T) {
|
|
106
|
+
const get = this.props.idAccessor || "id";
|
|
107
|
+
const id = utils.access<string>(data, get);
|
|
108
|
+
if (!id)
|
|
109
|
+
throw new Error(
|
|
110
|
+
"Data must contain an 'id' property or props.idAccessor must return a string"
|
|
111
|
+
);
|
|
112
|
+
return id;
|
|
113
|
+
}
|
|
114
|
+
|
|
110
115
|
/* Node Access */
|
|
111
116
|
|
|
112
117
|
get firstNode() {
|
|
@@ -348,7 +353,7 @@ export class TreeApi<T extends IdObj> {
|
|
|
348
353
|
safeRun(this.props.onSelect, this.selectedNodes);
|
|
349
354
|
}
|
|
350
355
|
|
|
351
|
-
|
|
356
|
+
deselectAll() {
|
|
352
357
|
this.dispatch(selection.clear());
|
|
353
358
|
this.dispatch(selection.anchor(null));
|
|
354
359
|
this.dispatch(selection.mostRecent(null));
|
package/src/types/tree-props.ts
CHANGED
|
@@ -38,7 +38,8 @@ export interface TreeProps<T extends IdObj> {
|
|
|
38
38
|
selectionFollowsFocus?: boolean;
|
|
39
39
|
disableDrag?: string | boolean | BoolFunc<T>;
|
|
40
40
|
disableDrop?: string | boolean | BoolFunc<T>;
|
|
41
|
-
|
|
41
|
+
childrenAccessor?: string | ((d: T) => T[]);
|
|
42
|
+
idAccessor?: string | ((d: T) => string);
|
|
42
43
|
|
|
43
44
|
/* Event Handlers */
|
|
44
45
|
onActivate?: (node: NodeApi<T>) => void;
|
package/tsconfig.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/* Language and Environment */
|
|
7
7
|
"target": "ES5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
8
|
-
"jsx": "
|
|
8
|
+
"jsx": "react-jsx", /* Specify what JSX code is generated. */
|
|
9
9
|
|
|
10
10
|
/* Modules */
|
|
11
11
|
"module": "CommonJS", /* Specify what module code is generated. */
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { NodeApi } from "../interfaces/node-api";
|
|
2
|
-
import { IdObj } from "../types/utils";
|
|
3
|
-
export declare function flattenTree<T extends IdObj>(root: NodeApi<T>): NodeApi<T>[];
|
|
4
|
-
export declare function filterTree<T extends IdObj>(root: NodeApi<T>, isMatch: (n: NodeApi<T>) => boolean): NodeApi<T>[];
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
declare type Data = {
|
|
2
|
-
id: string;
|
|
3
|
-
name: string;
|
|
4
|
-
children?: Data[];
|
|
5
|
-
};
|
|
6
|
-
export declare function useUncontrolledTree(initialData: Data[]): readonly [Data[], {
|
|
7
|
-
move: (args: {
|
|
8
|
-
dragIds: string[];
|
|
9
|
-
parentId: string;
|
|
10
|
-
index: number;
|
|
11
|
-
}) => void;
|
|
12
|
-
rename: (args: {
|
|
13
|
-
id: string;
|
|
14
|
-
name: string;
|
|
15
|
-
}) => void;
|
|
16
|
-
create: ({ parentId, index }: {
|
|
17
|
-
parentId: string;
|
|
18
|
-
index: number;
|
|
19
|
-
}) => Data;
|
|
20
|
-
drop: (args: {
|
|
21
|
-
id: string;
|
|
22
|
-
}) => void;
|
|
23
|
-
}];
|
|
24
|
-
export {};
|
package/dist/utils/props.d.ts
DELETED