react-arborist 1.2.0 → 2.0.0-rc
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/dist/components/{drop-cursor.d.ts → cursor.d.ts} +0 -0
- package/dist/components/default-container.d.ts +2 -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/flatten-tree.d.ts +4 -2
- 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-uncontrolled-tree.d.ts +24 -0
- package/dist/hooks/use-validated-props.d.ts +3 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +1900 -971
- package/dist/index.js.map +1 -1
- package/dist/interfaces/node-api.d.ts +67 -0
- package/dist/interfaces/tree-api.d.ts +112 -0
- package/dist/module.js +1886 -976
- 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 +43 -0
- package/dist/types/utils.d.ts +21 -0
- package/dist/utils/props.d.ts +3 -0
- package/dist/utils.d.ts +15 -6
- package/package.json +10 -7
- package/src/components/cursor.tsx +15 -0
- package/src/components/default-container.tsx +229 -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 +15 -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 +53 -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 +552 -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 +63 -0
- package/src/types/utils.ts +26 -0
- package/src/utils/props.ts +8 -0
- package/src/utils.ts +125 -11
- package/README.md +0 -221
- 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/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
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import { Range } from "./range";
|
|
2
|
-
|
|
3
|
-
type SelectionDirection = "forward" | "backward" | "none";
|
|
4
|
-
|
|
5
|
-
export type SelectionData = {
|
|
6
|
-
ranges: [number, number][];
|
|
7
|
-
currentIndex: number | null;
|
|
8
|
-
direction: SelectionDirection;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export class Selection {
|
|
12
|
-
ranges: Range[] = [];
|
|
13
|
-
currentIndex: number | null;
|
|
14
|
-
direction: SelectionDirection = "none";
|
|
15
|
-
items: any[];
|
|
16
|
-
|
|
17
|
-
static parse(data: SelectionData | null, items: any[]) {
|
|
18
|
-
if (data) {
|
|
19
|
-
return new Selection(
|
|
20
|
-
data.ranges,
|
|
21
|
-
data.currentIndex,
|
|
22
|
-
data.direction,
|
|
23
|
-
items
|
|
24
|
-
);
|
|
25
|
-
} else {
|
|
26
|
-
return new Selection();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
constructor(
|
|
31
|
-
ranges: [number, number][] = [],
|
|
32
|
-
currentIndex: number | null = ranges.length ? ranges.length - 1 : null,
|
|
33
|
-
direction: SelectionDirection = "none",
|
|
34
|
-
items: any[] = []
|
|
35
|
-
) {
|
|
36
|
-
ranges.forEach(([s, e]) => this.addRange(s, e));
|
|
37
|
-
this.currentIndex = currentIndex;
|
|
38
|
-
this.direction = direction;
|
|
39
|
-
this.items = items;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
get current() {
|
|
43
|
-
if (this.currentIndex === null) return null;
|
|
44
|
-
const range = this.ranges[this.currentIndex];
|
|
45
|
-
if (!range) {
|
|
46
|
-
return null;
|
|
47
|
-
} else {
|
|
48
|
-
return range;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
select(n: number) {
|
|
53
|
-
if (n < 0 || n >= this.items.length) return;
|
|
54
|
-
this.clear();
|
|
55
|
-
this.currentIndex = this.addRange(n, n);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
multiSelect(n: number) {
|
|
59
|
-
if (n < 0 || n >= this.items.length) return;
|
|
60
|
-
if (this.contains(n)) return;
|
|
61
|
-
this.currentIndex = this.addRange(n, n);
|
|
62
|
-
this.compact(n);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
deselect(n: number) {
|
|
66
|
-
if (n < 0 || n >= this.items.length) return;
|
|
67
|
-
const r = this.ranges.find((r) => r.contains(n));
|
|
68
|
-
if (!r) return;
|
|
69
|
-
else if (r.size === 1) this.removeRange(r);
|
|
70
|
-
else if (r.start === n) r.start++;
|
|
71
|
-
else if (r.end === n) r.end--;
|
|
72
|
-
else {
|
|
73
|
-
this.removeRange(r);
|
|
74
|
-
this.addRange(r.start, n - 1);
|
|
75
|
-
this.currentIndex = this.addRange(n + 1, r.end);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
getSelectedItems<T>(): T[] {
|
|
80
|
-
return this.ranges.flatMap((range) =>
|
|
81
|
-
range.map((index) => this.items[index])
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
extend(n: number) {
|
|
86
|
-
if (n < 0 || n >= this.items.length) return;
|
|
87
|
-
if (this.isEmpty()) {
|
|
88
|
-
this.select(n);
|
|
89
|
-
} else {
|
|
90
|
-
const anchor = this.getAnchor();
|
|
91
|
-
if (anchor !== null && this.current) {
|
|
92
|
-
const [start, end] = [n, anchor].sort((a, b) => a - b);
|
|
93
|
-
this.current.start = start;
|
|
94
|
-
this.current.end = end;
|
|
95
|
-
this.compact(n);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
contains(n: number | null) {
|
|
101
|
-
if (n === null) return false;
|
|
102
|
-
return this.ranges.some((r) => r.contains(n));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
getRanges() {
|
|
106
|
-
return this.ranges.map((r) => r.serialize());
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
clear() {
|
|
110
|
-
this.ranges = [];
|
|
111
|
-
this.currentIndex = null;
|
|
112
|
-
this.direction = "none";
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
serialize(): SelectionData {
|
|
116
|
-
return {
|
|
117
|
-
ranges: this.getRanges(),
|
|
118
|
-
currentIndex: this.currentIndex,
|
|
119
|
-
direction: this.direction,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
isEqual(other: Selection) {
|
|
124
|
-
if (other.ranges.length !== this.ranges.length) return false;
|
|
125
|
-
|
|
126
|
-
for (let i = 0; i < this.ranges.length; ++i) {
|
|
127
|
-
if (!this.ranges[i].isEqual(other.ranges[i])) return false;
|
|
128
|
-
}
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private addRange(start: number, end: number) {
|
|
133
|
-
const r = new Range(start, end);
|
|
134
|
-
// Keep ranges sorted by start
|
|
135
|
-
const index = this.ranges.findIndex((r) => r.start >= start);
|
|
136
|
-
if (index === -1) this.ranges.push(r);
|
|
137
|
-
else this.ranges.splice(index, 0, r);
|
|
138
|
-
return index === -1 ? this.ranges.length - 1 : index;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
private removeRange(r: Range) {
|
|
142
|
-
const index = this.ranges.indexOf(r);
|
|
143
|
-
this.ranges.splice(index, 1);
|
|
144
|
-
if (this.isEmpty()) {
|
|
145
|
-
this.currentIndex = null;
|
|
146
|
-
} else if (index === this.currentIndex) {
|
|
147
|
-
this.currentIndex = this.ranges.length - 1;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private isEmpty() {
|
|
152
|
-
return this.ranges.length === 0;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
getAnchor() {
|
|
156
|
-
if (!this.current) return null;
|
|
157
|
-
return this.direction === "backward"
|
|
158
|
-
? this.current.end
|
|
159
|
-
: this.current.start;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
getFocus() {
|
|
163
|
-
if (!this.current) return -1;
|
|
164
|
-
return this.direction === "backward"
|
|
165
|
-
? this.current.start
|
|
166
|
-
: this.current.end;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private compact(focus: number) {
|
|
170
|
-
const removals = [];
|
|
171
|
-
const current = this.current;
|
|
172
|
-
for (let r of this.ranges) {
|
|
173
|
-
if (!this.current || r === this.current) continue;
|
|
174
|
-
if (this.current.overlaps(r)) {
|
|
175
|
-
this.current.combine(r);
|
|
176
|
-
removals.push(r);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
removals.forEach((r) => this.removeRange(r));
|
|
180
|
-
if (current) this.currentIndex = this.ranges.indexOf(current);
|
|
181
|
-
if (!this.current) return;
|
|
182
|
-
if (this.current.start < focus) this.direction = "forward";
|
|
183
|
-
else if (this.current.end > focus) this.direction = "backward";
|
|
184
|
-
else this.direction = "none";
|
|
185
|
-
}
|
|
186
|
-
}
|
package/src/tree-api.ts
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import memoizeOne from "memoize-one";
|
|
2
|
-
import { Dispatch, MutableRefObject } from "react";
|
|
3
|
-
import { FixedSizeList } from "react-window";
|
|
4
|
-
import { flattenTree } from "./data/flatten-tree";
|
|
5
|
-
import { Cursor } from "./dnd/compute-drop";
|
|
6
|
-
import { Action, actions } from "./reducer";
|
|
7
|
-
import {
|
|
8
|
-
Node,
|
|
9
|
-
StateContext,
|
|
10
|
-
TreeProviderProps,
|
|
11
|
-
EditResult,
|
|
12
|
-
IdObj,
|
|
13
|
-
DropCursorProps,
|
|
14
|
-
} from "./types";
|
|
15
|
-
import ReactDOM from "react-dom";
|
|
16
|
-
import { noop } from "./utils";
|
|
17
|
-
import { Selection } from "./selection/selection";
|
|
18
|
-
import { defaultDropCursor } from "./components/default-drop-cursor";
|
|
19
|
-
export class TreeApi<T extends IdObj> {
|
|
20
|
-
private edits = new Map<string, (args: EditResult) => void>();
|
|
21
|
-
|
|
22
|
-
constructor(
|
|
23
|
-
public dispatch: Dispatch<Action>,
|
|
24
|
-
public state: StateContext,
|
|
25
|
-
public props: TreeProviderProps<T>,
|
|
26
|
-
public list: MutableRefObject<FixedSizeList | null>,
|
|
27
|
-
public listEl: MutableRefObject<HTMLDivElement | null>
|
|
28
|
-
) {}
|
|
29
|
-
|
|
30
|
-
sync(other: TreeApi<T>) {
|
|
31
|
-
this.dispatch = other.dispatch;
|
|
32
|
-
this.state = other.state;
|
|
33
|
-
this.props = other.props;
|
|
34
|
-
this.list = other.list;
|
|
35
|
-
this.listEl = other.listEl;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
getNode(id: string): Node<T> | null {
|
|
39
|
-
if (id in this.idToIndex)
|
|
40
|
-
return this.visibleNodes[this.idToIndex[id]] || null;
|
|
41
|
-
else return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
getSelectedIds() {
|
|
45
|
-
return this.state.selection.ids;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
edit(id: string | number): Promise<EditResult> {
|
|
49
|
-
const sid = id.toString();
|
|
50
|
-
this.resolveEdit(sid, { cancelled: true });
|
|
51
|
-
this.scrollToId(sid);
|
|
52
|
-
this.dispatch(actions.edit(sid));
|
|
53
|
-
return new Promise((resolve) => this.edits.set(sid, resolve));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
submit(id: string | number, value: string) {
|
|
57
|
-
const sid = id.toString();
|
|
58
|
-
this.onEdit(sid, value);
|
|
59
|
-
this.dispatch(actions.edit(null));
|
|
60
|
-
this.resolveEdit(sid, { cancelled: false, value });
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
reset(id: string | number) {
|
|
64
|
-
const sid = id.toString();
|
|
65
|
-
this.dispatch(actions.edit(null));
|
|
66
|
-
this.resolveEdit(sid, { cancelled: true });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private resolveEdit(id: string, value: EditResult) {
|
|
70
|
-
const resolve = this.edits.get(id.toString());
|
|
71
|
-
if (resolve) resolve(value);
|
|
72
|
-
this.edits.delete(id);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
select(index: number | null, meta = false, shift = false) {
|
|
76
|
-
this.dispatch(actions.select(index, meta, shift));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
selectById(id: string | number, meta = false, shift = false) {
|
|
80
|
-
const index = this.idToIndex[id];
|
|
81
|
-
this.select(index, meta, shift);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
selectUpwards(shiftKey: boolean) {
|
|
85
|
-
this.dispatch(actions.stepUp(shiftKey, this.visibleIds));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
selectDownwards(shiftKey: boolean) {
|
|
89
|
-
this.dispatch(actions.stepDown(shiftKey, this.visibleIds));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
hideCursor() {
|
|
93
|
-
this.dispatch(actions.setCursorLocation({ type: "none" }));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
showCursor(cursor: Cursor) {
|
|
97
|
-
this.dispatch(actions.setCursorLocation(cursor));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
scrollToId(id: string) {
|
|
101
|
-
if (!this.list) return;
|
|
102
|
-
const index = this.idToIndex[id];
|
|
103
|
-
if (index) {
|
|
104
|
-
this.list.current?.scrollToItem(index);
|
|
105
|
-
} else {
|
|
106
|
-
this.openParents(id);
|
|
107
|
-
ReactDOM.flushSync(() => {
|
|
108
|
-
const index = this.idToIndex[id];
|
|
109
|
-
if (index) {
|
|
110
|
-
this.list.current?.scrollToItem(index);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
open(id: string) {
|
|
117
|
-
this.onToggle(id, true);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
openParents(id: string) {
|
|
121
|
-
const node = dfs(this.props.root, id);
|
|
122
|
-
let parent = node?.parent;
|
|
123
|
-
|
|
124
|
-
while (parent) {
|
|
125
|
-
this.open(parent.id);
|
|
126
|
-
parent = parent.parent;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
get visibleIds() {
|
|
131
|
-
return getIds(this.visibleNodes);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
get idToIndex() {
|
|
135
|
-
return createIndex(this.visibleNodes);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
get visibleNodes() {
|
|
139
|
-
return createList(this.props.root) as Node<T>[];
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
get width() {
|
|
143
|
-
return this.props.treeProps.width || 300;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
get height() {
|
|
147
|
-
return this.props.treeProps.height || 500;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
get indent() {
|
|
151
|
-
return this.props.treeProps.indent || 24;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
get renderer() {
|
|
155
|
-
return this.props.treeProps.children;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
get onToggle() {
|
|
159
|
-
return this.props.treeProps.onToggle || noop;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
get rowHeight() {
|
|
163
|
-
return this.props.treeProps.rowHeight || 24;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
get onClick() {
|
|
167
|
-
return this.props.treeProps.onClick || noop;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
get onContextMenu() {
|
|
171
|
-
return this.props.treeProps.onContextMenu || noop;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
get onMove() {
|
|
175
|
-
return this.props.treeProps.onMove || noop;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
get onEdit() {
|
|
179
|
-
return this.props.treeProps.onEdit || noop;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
get cursorParentId() {
|
|
183
|
-
const { cursor } = this.state;
|
|
184
|
-
switch (cursor.type) {
|
|
185
|
-
case "highlight":
|
|
186
|
-
return cursor.id;
|
|
187
|
-
default:
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
get cursorOverFolder() {
|
|
193
|
-
return this.state.cursor.type === "highlight";
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
get editingId() {
|
|
197
|
-
return this.state.editingId;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
isSelected(index: number | null) {
|
|
201
|
-
const selection = Selection.parse(this.state.selection.data, []);
|
|
202
|
-
return selection.contains(index);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
renderDropCursor(props: DropCursorProps) {
|
|
206
|
-
const render = this.props.treeProps.dropCursor || defaultDropCursor;
|
|
207
|
-
return render(props);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const getIds = memoizeOne((nodes: Node[]) => nodes.map((n) => n.id));
|
|
212
|
-
const createIndex = memoizeOne((nodes: Node[]) => {
|
|
213
|
-
return nodes.reduce<{ [id: string]: number }>((map, node, index) => {
|
|
214
|
-
map[node.id] = index;
|
|
215
|
-
return map;
|
|
216
|
-
}, {});
|
|
217
|
-
});
|
|
218
|
-
const createList = memoizeOne(flattenTree);
|
|
219
|
-
|
|
220
|
-
function dfs(node: Node<unknown>, id: string): Node<unknown> | null {
|
|
221
|
-
if (!node) return null;
|
|
222
|
-
if (node.id === id) return node;
|
|
223
|
-
if (node.children) {
|
|
224
|
-
for (let child of node.children) {
|
|
225
|
-
const result = dfs(child, id);
|
|
226
|
-
if (result) return result;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return null;
|
|
230
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
ComponentType,
|
|
3
|
-
CSSProperties,
|
|
4
|
-
MouseEvent,
|
|
5
|
-
MouseEventHandler,
|
|
6
|
-
MutableRefObject,
|
|
7
|
-
ReactElement,
|
|
8
|
-
ReactNode,
|
|
9
|
-
Ref,
|
|
10
|
-
} from "react";
|
|
11
|
-
import { FixedSizeList } from "react-window";
|
|
12
|
-
import { Cursor } from "./dnd/compute-drop";
|
|
13
|
-
import { SelectionData } from "./selection/selection";
|
|
14
|
-
import { TreeApi } from "./tree-api";
|
|
15
|
-
|
|
16
|
-
// Forward ref can't forward generics without this little re-declare
|
|
17
|
-
// https://fettblog.eu/typescript-react-generic-forward-refs/
|
|
18
|
-
declare module "react" {
|
|
19
|
-
function forwardRef<T, P = {}>(
|
|
20
|
-
render: (props: P, ref: React.Ref<T>) => React.ReactElement | null
|
|
21
|
-
): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type Node<T = unknown> = {
|
|
25
|
-
id: string;
|
|
26
|
-
model: T;
|
|
27
|
-
level: number;
|
|
28
|
-
children: Node<T>[] | null;
|
|
29
|
-
parent: Node<T> | null;
|
|
30
|
-
isOpen: boolean;
|
|
31
|
-
isDraggable: boolean;
|
|
32
|
-
isDroppable: boolean;
|
|
33
|
-
rowIndex: number | null;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export type NodesById<T> = { [id: string]: Node<T> };
|
|
37
|
-
|
|
38
|
-
export interface IdObj {
|
|
39
|
-
id: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type NodeRendererProps<T extends IdObj> = {
|
|
43
|
-
innerRef: (el: HTMLDivElement | null) => void;
|
|
44
|
-
styles: { row: CSSProperties; indent: CSSProperties };
|
|
45
|
-
data: T;
|
|
46
|
-
state: NodeState;
|
|
47
|
-
handlers: NodeHandlers;
|
|
48
|
-
tree: TreeApi<T>;
|
|
49
|
-
preview: boolean;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export type NodeState = {
|
|
53
|
-
isOpen: boolean;
|
|
54
|
-
isSelected: boolean;
|
|
55
|
-
isHoveringOverChild: boolean;
|
|
56
|
-
isDragging: boolean;
|
|
57
|
-
isSelectedStart: boolean;
|
|
58
|
-
isSelectedEnd: boolean;
|
|
59
|
-
isEditing: boolean;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export type NodeHandlers = {
|
|
63
|
-
toggle: MouseEventHandler;
|
|
64
|
-
select: (e: MouseEvent, args: { selectOnClick: boolean }) => void;
|
|
65
|
-
edit: () => Promise<EditResult>;
|
|
66
|
-
submit: (name: string) => void;
|
|
67
|
-
reset: () => void;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export type NodeRenderer<T extends IdObj> = ComponentType<NodeRendererProps<T>>;
|
|
71
|
-
|
|
72
|
-
export type MoveHandler = (
|
|
73
|
-
dragIds: string[],
|
|
74
|
-
parentId: string | null,
|
|
75
|
-
index: number
|
|
76
|
-
) => void;
|
|
77
|
-
|
|
78
|
-
export type ToggleHandler = (id: string, isOpen: boolean) => void;
|
|
79
|
-
export type EditHandler = (id: string, name: string) => void;
|
|
80
|
-
export type NodeClickHandler<T> = (e: MouseEvent, n: Node<T>) => void;
|
|
81
|
-
export type IndexClickHandler = (e: MouseEvent, index: number) => void;
|
|
82
|
-
export type SelectedCheck = (index: number) => boolean;
|
|
83
|
-
|
|
84
|
-
export type CursorLocation = {
|
|
85
|
-
index: number | null;
|
|
86
|
-
level: number | null;
|
|
87
|
-
parentId: string | null;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export type DragItem = {
|
|
91
|
-
dragIds: string[];
|
|
92
|
-
id: string;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export type SelectionState = {
|
|
96
|
-
data: SelectionData | null;
|
|
97
|
-
ids: string[];
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export type StateContext = {
|
|
101
|
-
cursor: Cursor;
|
|
102
|
-
editingId: string | null;
|
|
103
|
-
selection: SelectionState;
|
|
104
|
-
visibleIds: string[];
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
type BoolFunc<T> = (data: T) => boolean;
|
|
108
|
-
|
|
109
|
-
export interface TreeProps<T extends IdObj> {
|
|
110
|
-
children: NodeRenderer<T>;
|
|
111
|
-
className?: string | undefined;
|
|
112
|
-
data: T;
|
|
113
|
-
disableDrag?: string | boolean | BoolFunc<T>;
|
|
114
|
-
disableDrop?: string | boolean | BoolFunc<T>;
|
|
115
|
-
dndRootElement?: globalThis.Node | null;
|
|
116
|
-
getChildren?: string | ((d: T) => T[]);
|
|
117
|
-
handle?: Ref<TreeApi<T>>; // Deprecated
|
|
118
|
-
height?: number;
|
|
119
|
-
hideRoot?: boolean;
|
|
120
|
-
indent?: number;
|
|
121
|
-
isOpen?: string | BoolFunc<T>;
|
|
122
|
-
onClick?: MouseEventHandler;
|
|
123
|
-
onContextMenu?: MouseEventHandler;
|
|
124
|
-
onEdit?: EditHandler;
|
|
125
|
-
onMove?: MoveHandler;
|
|
126
|
-
onToggle?: ToggleHandler;
|
|
127
|
-
openByDefault?: boolean;
|
|
128
|
-
rowHeight?: number;
|
|
129
|
-
width?: number;
|
|
130
|
-
dropCursor?: (props: DropCursorProps) => ReactElement;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export type TreeProviderProps<T extends IdObj> = {
|
|
134
|
-
treeProps: TreeProps<T>;
|
|
135
|
-
imperativeHandle: React.Ref<TreeApi<T>> | undefined;
|
|
136
|
-
children: ReactElement;
|
|
137
|
-
root: Node<T>;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
export type EditResult =
|
|
141
|
-
| { cancelled: true }
|
|
142
|
-
| { cancelled: false; value: string };
|
|
143
|
-
|
|
144
|
-
export type DropCursorProps = {
|
|
145
|
-
top: number;
|
|
146
|
-
left: number;
|
|
147
|
-
indent: number;
|
|
148
|
-
};
|