@react-fabric/data 1.0.0-beta.54 → 1.0.0-beta.56
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/cjs/hooks/useFilteredList.js +68 -10
- package/dist/cjs/table/HeaderCell.js +3 -2
- package/dist/cjs/table/Table.js +7 -1
- package/dist/cjs/table/useVirtualTable.js +18 -0
- package/dist/cjs/tree/TreeNode.js +3 -2
- package/dist/cjs/tree/TreePanel.js +18 -4
- package/dist/cjs/tree/useTree.js +107 -39
- package/dist/cjs/tree/utils.js +5 -4
- package/dist/cjs/virtual/Gallery.js +2 -2
- package/dist/cjs/virtual/List.js +2 -2
- package/dist/esm/hooks/useFilteredList.js +69 -11
- package/dist/esm/table/HeaderCell.js +3 -2
- package/dist/esm/table/Table.js +7 -1
- package/dist/esm/table/useVirtualTable.js +19 -1
- package/dist/esm/tree/TreeNode.js +3 -2
- package/dist/esm/tree/TreePanel.js +19 -5
- package/dist/esm/tree/useTree.js +109 -41
- package/dist/esm/tree/utils.js +5 -4
- package/dist/esm/virtual/Gallery.js +2 -2
- package/dist/esm/virtual/List.js +2 -2
- package/dist/types/hooks/useFilteredList.d.ts +49 -6
- package/dist/types/table/HeaderCell.d.ts +1 -1
- package/dist/types/table/Table.d.ts +1 -1
- package/dist/types/table/types.d.ts +3 -0
- package/dist/types/table/useVirtualTable.d.ts +3 -0
- package/dist/types/tree/TreePanel.d.ts +1 -1
- package/dist/types/tree/types.d.ts +12 -13
- package/dist/types/tree/useTree.d.ts +3 -0
- package/dist/types/tree/utils.d.ts +2 -2
- package/package.json +5 -5
- package/src/hooks/useFilteredList.tsx +90 -9
- package/src/table/HeaderCell.tsx +3 -2
- package/src/table/Table.tsx +5 -0
- package/src/table/types.ts +4 -0
- package/src/table/useVirtualTable.ts +24 -1
- package/src/tree/TreeNode.tsx +4 -5
- package/src/tree/TreePanel.tsx +12 -4
- package/src/tree/types.ts +12 -13
- package/src/tree/useTree.ts +105 -35
- package/src/tree/utils.ts +11 -5
- package/src/virtual/Gallery.tsx +1 -1
- package/src/virtual/List.tsx +1 -1
package/src/tree/useTree.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { useDebounce } from "@react-fabric/core";
|
|
25
|
-
import { EMPTY_ARRAY } from "@react-fabric/utilities";
|
|
25
|
+
import { EMPTY_ARRAY, isEmpty } from "@react-fabric/utilities";
|
|
26
26
|
import memoizeOne from "memoize-one";
|
|
27
27
|
import { useCallback, useEffect, useReducer, useRef } from "react";
|
|
28
28
|
import {
|
|
@@ -56,6 +56,10 @@ type TreeActions =
|
|
|
56
56
|
* update item check state
|
|
57
57
|
*/
|
|
58
58
|
| { type: "checked"; id: string[] }
|
|
59
|
+
/**
|
|
60
|
+
* toggle item select, used as action handler
|
|
61
|
+
*/
|
|
62
|
+
| { type: "toggleSelect"; id: string }
|
|
59
63
|
/**
|
|
60
64
|
* toggle item check, used as action handler
|
|
61
65
|
*/
|
|
@@ -85,6 +89,7 @@ interface TreeState {
|
|
|
85
89
|
items: InternalNode[];
|
|
86
90
|
itemMap: Map<string, InternalNode>;
|
|
87
91
|
tree: InternalNode[];
|
|
92
|
+
query?: string;
|
|
88
93
|
selected?: string;
|
|
89
94
|
checked?: string[];
|
|
90
95
|
}
|
|
@@ -105,7 +110,7 @@ export const useTree = <T extends KeyValue>({
|
|
|
105
110
|
onExpandToggle,
|
|
106
111
|
}: Partial<TreePanelProps<T>>) => {
|
|
107
112
|
const componentEvents = useRef({ onSelect, onChecked });
|
|
108
|
-
const intialExpand = useRef(defaultExpanded ?? EMPTY_ARRAY);
|
|
113
|
+
const intialExpand = useRef([...(defaultExpanded ?? EMPTY_ARRAY)]);
|
|
109
114
|
const itemList = createItemList(items);
|
|
110
115
|
|
|
111
116
|
const fireExpandToggle = useCallback(
|
|
@@ -122,23 +127,26 @@ export const useTree = <T extends KeyValue>({
|
|
|
122
127
|
(node: InternalNode) => {
|
|
123
128
|
if (node.open && !node.leaf && !node.children?.length) {
|
|
124
129
|
node.loading = true;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
dispatch({
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
130
|
+
// delay onload callback to avoid state issues
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
void Promise.resolve(onLoad?.(node.id))
|
|
133
|
+
.then((resp = EMPTY_ARRAY) => {
|
|
134
|
+
node.children = refactorTree(
|
|
135
|
+
resp,
|
|
136
|
+
{ sorter, defaultExpanded },
|
|
137
|
+
{ level: node.level + 1, parent: node.id },
|
|
138
|
+
);
|
|
139
|
+
})
|
|
140
|
+
.finally(() => {
|
|
141
|
+
node.loading = false;
|
|
142
|
+
dispatch({ type: "loaded" });
|
|
143
|
+
intialExpand.current?.length > 0 &&
|
|
144
|
+
dispatch({
|
|
145
|
+
type: "expand",
|
|
146
|
+
id: intialExpand.current.shift() as unknown as string,
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}, 100);
|
|
142
150
|
} else {
|
|
143
151
|
dispatch({ type: "loaded" });
|
|
144
152
|
intialExpand.current?.length > 0 &&
|
|
@@ -151,12 +159,36 @@ export const useTree = <T extends KeyValue>({
|
|
|
151
159
|
[onLoad],
|
|
152
160
|
);
|
|
153
161
|
|
|
162
|
+
const fireSelected = useDebounce(
|
|
163
|
+
(nodeId: string, data: T) => {
|
|
164
|
+
componentEvents.current.onSelect?.(nodeId, data);
|
|
165
|
+
},
|
|
166
|
+
[onSelect],
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const fireChecked = useDebounce(
|
|
170
|
+
(leafs: string[], nodes: string[], partials: string[]) => {
|
|
171
|
+
componentEvents.current.onChecked?.(leafs, nodes, partials);
|
|
172
|
+
},
|
|
173
|
+
[onChecked],
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const fireQuery = useDebounce(
|
|
177
|
+
(query: string) => {
|
|
178
|
+
onQuery?.(query);
|
|
179
|
+
},
|
|
180
|
+
[onQuery],
|
|
181
|
+
);
|
|
182
|
+
|
|
154
183
|
const [state, dispatch] = useReducer(
|
|
155
184
|
(state: TreeState, action: TreeActions) => {
|
|
156
185
|
if (action.type === "load") {
|
|
157
186
|
state.items = refactorTree(action.items, { sorter, defaultExpanded });
|
|
158
187
|
state.itemMap = makeTreeMap(state.items);
|
|
159
188
|
state.tree = flattenTree(state.items);
|
|
189
|
+
state.selected = undefined;
|
|
190
|
+
state.checked = undefined;
|
|
191
|
+
state.query = "";
|
|
160
192
|
return { ...state };
|
|
161
193
|
}
|
|
162
194
|
if (action.type === "toggleExpand") {
|
|
@@ -171,7 +203,8 @@ export const useTree = <T extends KeyValue>({
|
|
|
171
203
|
state.itemMap = makeTreeMap(state.items);
|
|
172
204
|
fireExpandToggle(Array.from(state.itemMap.values()));
|
|
173
205
|
state.tree = flattenTree(state.items);
|
|
174
|
-
state.selected
|
|
206
|
+
state.selected = updateSelection(state.itemMap, selected, true);
|
|
207
|
+
state.checked?.forEach((id) => updateChecked(state.itemMap, id, 1));
|
|
175
208
|
return { ...state };
|
|
176
209
|
}
|
|
177
210
|
if (action.type === "expand") {
|
|
@@ -206,36 +239,60 @@ export const useTree = <T extends KeyValue>({
|
|
|
206
239
|
}
|
|
207
240
|
if (action.type === "filter") {
|
|
208
241
|
if (onQuery) {
|
|
209
|
-
onQuery
|
|
242
|
+
// TODO: onQuery should provide new tree listing
|
|
243
|
+
// save current tree state as preQueryState
|
|
244
|
+
// on clearing filter restore preQueryState
|
|
245
|
+
if (!isEmpty(action.query)) {
|
|
246
|
+
// state.prevItems = state.items;
|
|
247
|
+
fireQuery(action.query);
|
|
248
|
+
} else {
|
|
249
|
+
// state.items = state.prevItems;
|
|
250
|
+
// build tree map
|
|
251
|
+
}
|
|
210
252
|
} else {
|
|
211
253
|
filterTree(state.itemMap, action.query, matcher);
|
|
212
254
|
state.tree = flattenTree(state.items);
|
|
213
|
-
return { ...state };
|
|
214
255
|
}
|
|
256
|
+
return { ...state, query: action.query };
|
|
257
|
+
}
|
|
258
|
+
if (action.type === "toggleSelect") {
|
|
259
|
+
if (!onSelect) {
|
|
260
|
+
if (state.selected) {
|
|
261
|
+
updateSelection(state.itemMap, state.selected);
|
|
262
|
+
}
|
|
263
|
+
state.selected = updateSelection(state.itemMap, action.id, true);
|
|
264
|
+
state.tree = flattenTree(state.items);
|
|
265
|
+
} else {
|
|
266
|
+
fireSelected(action.id, state.itemMap.get(action.id)?.data);
|
|
267
|
+
}
|
|
268
|
+
return { ...state };
|
|
215
269
|
}
|
|
216
270
|
if (action.type === "select") {
|
|
217
271
|
if (state.selected) {
|
|
218
272
|
updateSelection(state.itemMap, state.selected);
|
|
219
273
|
}
|
|
220
|
-
updateSelection(state.itemMap, action.id, true);
|
|
274
|
+
state.selected = updateSelection(state.itemMap, action.id, true);
|
|
221
275
|
state.tree = flattenTree(state.items);
|
|
222
|
-
|
|
223
|
-
action.id,
|
|
224
|
-
state.itemMap.get(action.id)?.data,
|
|
225
|
-
);
|
|
226
|
-
return { ...state, selected: action.id };
|
|
276
|
+
return { ...state };
|
|
227
277
|
}
|
|
228
278
|
if (action.type === "toggleCheck") {
|
|
229
279
|
updateChecked(state.itemMap, action.id);
|
|
230
|
-
const checkList: string[][] = [[], []];
|
|
280
|
+
const checkList: string[][] = [[], [], []];
|
|
231
281
|
Array.from(state.itemMap.values())
|
|
232
|
-
.filter((node) => node.checked
|
|
233
|
-
.forEach((node) =>
|
|
234
|
-
|
|
235
|
-
|
|
282
|
+
.filter((node) => node.checked !== 0)
|
|
283
|
+
.forEach((node) =>
|
|
284
|
+
checkList[node.leaf ? 0 : node.checked].push(node.id),
|
|
285
|
+
);
|
|
286
|
+
fireChecked(
|
|
287
|
+
checkList[0], // leafs
|
|
288
|
+
checkList[1], // nodes
|
|
289
|
+
checkList[2], // partials
|
|
290
|
+
);
|
|
291
|
+
return { ...state, checked: checkList[0] };
|
|
236
292
|
}
|
|
237
293
|
if (action.type === "checked") {
|
|
238
|
-
|
|
294
|
+
state.itemMap.forEach((item) => (item.checked = 0));
|
|
295
|
+
action.id.forEach((id) => updateChecked(state.itemMap, id, 1));
|
|
239
296
|
return { ...state, checked: action.id };
|
|
240
297
|
}
|
|
241
298
|
return state;
|
|
@@ -245,6 +302,7 @@ export const useTree = <T extends KeyValue>({
|
|
|
245
302
|
items: [],
|
|
246
303
|
tree: [],
|
|
247
304
|
checked: [],
|
|
305
|
+
query: "",
|
|
248
306
|
},
|
|
249
307
|
);
|
|
250
308
|
|
|
@@ -260,6 +318,8 @@ export const useTree = <T extends KeyValue>({
|
|
|
260
318
|
type: "expand",
|
|
261
319
|
id: intialExpand.current.shift() as unknown as string,
|
|
262
320
|
});
|
|
321
|
+
selected && dispatch({ type: "select", id: selected });
|
|
322
|
+
checked && dispatch({ type: "checked", id: checked });
|
|
263
323
|
}, [itemList]);
|
|
264
324
|
|
|
265
325
|
useEffect(() => {
|
|
@@ -279,13 +339,20 @@ export const useTree = <T extends KeyValue>({
|
|
|
279
339
|
}, []);
|
|
280
340
|
|
|
281
341
|
const select = useCallback((id: string) => {
|
|
282
|
-
dispatch({ type: "
|
|
342
|
+
dispatch({ type: "toggleSelect", id });
|
|
283
343
|
}, []);
|
|
284
344
|
|
|
285
345
|
const expand = useCallback((id: string) => {
|
|
286
346
|
dispatch({ type: "expand", id });
|
|
287
347
|
}, []);
|
|
288
348
|
|
|
349
|
+
const expandAndLoad = useCallback((expandList: string[]) => {
|
|
350
|
+
if (expandList.length > 0) {
|
|
351
|
+
intialExpand.current = [...expandList];
|
|
352
|
+
dispatch({ type: "expand", id: intialExpand.current.shift() as string });
|
|
353
|
+
}
|
|
354
|
+
}, []);
|
|
355
|
+
|
|
289
356
|
const expandAll = useCallback(() => {
|
|
290
357
|
dispatch({ type: "expandAll" });
|
|
291
358
|
}, []);
|
|
@@ -304,10 +371,13 @@ export const useTree = <T extends KeyValue>({
|
|
|
304
371
|
|
|
305
372
|
return {
|
|
306
373
|
tree: state.tree,
|
|
374
|
+
query: state.query,
|
|
375
|
+
selected: state.selected,
|
|
307
376
|
toggleExpand,
|
|
308
377
|
expandAll,
|
|
309
378
|
collapseAll,
|
|
310
379
|
toggleCheck,
|
|
380
|
+
expandAndLoad,
|
|
311
381
|
select,
|
|
312
382
|
expand,
|
|
313
383
|
onFilter,
|
package/src/tree/utils.ts
CHANGED
|
@@ -127,10 +127,10 @@ export const flattenTree = (
|
|
|
127
127
|
|
|
128
128
|
export const updateSelection = (
|
|
129
129
|
nodes: Map<string, InternalNode>,
|
|
130
|
-
id
|
|
130
|
+
id?: string,
|
|
131
131
|
selected?: true,
|
|
132
132
|
) => {
|
|
133
|
-
const node = nodes.get(id);
|
|
133
|
+
const node = nodes.get(id ?? "");
|
|
134
134
|
if (node) {
|
|
135
135
|
// change selection
|
|
136
136
|
node.selected = selected;
|
|
@@ -139,16 +139,22 @@ export const updateSelection = (
|
|
|
139
139
|
while (parent) {
|
|
140
140
|
const parentNode = nodes.get(parent);
|
|
141
141
|
parentNode && (parentNode.childSelected = selected);
|
|
142
|
-
selected && parentNode && (parentNode.open = true);
|
|
142
|
+
// selected && parentNode && (parentNode.open = true);
|
|
143
143
|
parent = parentNode?.parent;
|
|
144
144
|
}
|
|
145
|
+
return id;
|
|
145
146
|
}
|
|
146
147
|
};
|
|
147
148
|
|
|
148
|
-
export const updateChecked = (
|
|
149
|
+
export const updateChecked = (
|
|
150
|
+
list: Map<string, AnyObject>,
|
|
151
|
+
id: string,
|
|
152
|
+
checked?: 0 | 1 | 2,
|
|
153
|
+
) => {
|
|
149
154
|
const node = list.get(id);
|
|
150
155
|
if (node) {
|
|
151
|
-
node.checked =
|
|
156
|
+
node.checked =
|
|
157
|
+
checked === undefined ? (node.checked === 0 ? 1 : 0) : checked;
|
|
152
158
|
// check all children
|
|
153
159
|
node.children &&
|
|
154
160
|
getChildren(node.children).forEach(
|
package/src/virtual/Gallery.tsx
CHANGED
|
@@ -189,7 +189,7 @@ const _VirtualGallery = <T extends AnyObject>({
|
|
|
189
189
|
|
|
190
190
|
const currentIndex = useRef(0);
|
|
191
191
|
useEffect(() => {
|
|
192
|
-
currentIndex.current = virtualItems[
|
|
192
|
+
currentIndex.current = virtualItems[2]?.index ?? 0;
|
|
193
193
|
if (
|
|
194
194
|
scrollerRef.current &&
|
|
195
195
|
virtualItems[0] &&
|
package/src/virtual/List.tsx
CHANGED
|
@@ -159,7 +159,7 @@ const _VirtualList = <T extends AnyObject>({
|
|
|
159
159
|
|
|
160
160
|
const currentIndex = useRef(0);
|
|
161
161
|
useEffect(() => {
|
|
162
|
-
currentIndex.current = virtualItems[
|
|
162
|
+
currentIndex.current = virtualItems[2]?.index ?? 0;
|
|
163
163
|
if (
|
|
164
164
|
scrollerRef.current &&
|
|
165
165
|
virtualItems[0] &&
|