@headless-tree/core 0.0.9 → 0.0.11
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/CHANGELOG.md +12 -0
- package/lib/cjs/core/build-proxified-instance.d.ts +2 -0
- package/lib/cjs/core/build-proxified-instance.js +58 -0
- package/lib/cjs/core/build-static-instance.d.ts +2 -0
- package/lib/cjs/core/build-static-instance.js +27 -0
- package/lib/cjs/core/create-tree.js +55 -36
- package/lib/cjs/features/async-data-loader/feature.js +37 -23
- package/lib/cjs/features/async-data-loader/types.d.ts +2 -1
- package/lib/cjs/features/drag-and-drop/feature.js +64 -32
- package/lib/cjs/features/drag-and-drop/types.d.ts +13 -4
- package/lib/cjs/features/drag-and-drop/utils.d.ts +1 -2
- package/lib/cjs/features/drag-and-drop/utils.js +140 -37
- package/lib/cjs/features/expand-all/feature.js +12 -6
- package/lib/cjs/features/main/types.d.ts +8 -2
- package/lib/cjs/features/renaming/feature.js +33 -18
- package/lib/cjs/features/renaming/types.d.ts +1 -1
- package/lib/cjs/features/search/feature.js +38 -24
- package/lib/cjs/features/search/types.d.ts +0 -1
- package/lib/cjs/features/selection/feature.js +23 -14
- package/lib/cjs/features/sync-data-loader/feature.js +7 -2
- package/lib/cjs/features/tree/feature.d.ts +2 -1
- package/lib/cjs/features/tree/feature.js +85 -63
- package/lib/cjs/features/tree/types.d.ts +5 -3
- package/lib/cjs/index.d.ts +3 -1
- package/lib/cjs/index.js +2 -1
- package/lib/cjs/test-utils/test-tree-do.d.ts +23 -0
- package/lib/cjs/test-utils/test-tree-do.js +99 -0
- package/lib/cjs/test-utils/test-tree-expect.d.ts +15 -0
- package/lib/cjs/test-utils/test-tree-expect.js +62 -0
- package/lib/cjs/test-utils/test-tree.d.ts +47 -0
- package/lib/cjs/test-utils/test-tree.js +195 -0
- package/lib/cjs/types/core.d.ts +31 -15
- package/lib/cjs/utilities/errors.d.ts +1 -0
- package/lib/cjs/utilities/errors.js +5 -0
- package/lib/cjs/utilities/insert-items-at-target.js +10 -3
- package/lib/cjs/utilities/remove-items-from-parents.js +14 -8
- package/lib/cjs/utils.d.ts +3 -3
- package/lib/cjs/utils.js +6 -6
- package/lib/esm/core/build-proxified-instance.d.ts +2 -0
- package/lib/esm/core/build-proxified-instance.js +54 -0
- package/lib/esm/core/build-static-instance.d.ts +2 -0
- package/lib/esm/core/build-static-instance.js +23 -0
- package/lib/esm/core/create-tree.js +55 -36
- package/lib/esm/features/async-data-loader/feature.js +37 -23
- package/lib/esm/features/async-data-loader/types.d.ts +2 -1
- package/lib/esm/features/drag-and-drop/feature.js +64 -32
- package/lib/esm/features/drag-and-drop/types.d.ts +13 -4
- package/lib/esm/features/drag-and-drop/utils.d.ts +1 -2
- package/lib/esm/features/drag-and-drop/utils.js +138 -34
- package/lib/esm/features/expand-all/feature.js +12 -6
- package/lib/esm/features/main/types.d.ts +8 -2
- package/lib/esm/features/renaming/feature.js +33 -18
- package/lib/esm/features/renaming/types.d.ts +1 -1
- package/lib/esm/features/search/feature.js +38 -24
- package/lib/esm/features/search/types.d.ts +0 -1
- package/lib/esm/features/selection/feature.js +23 -14
- package/lib/esm/features/sync-data-loader/feature.js +7 -2
- package/lib/esm/features/tree/feature.d.ts +2 -1
- package/lib/esm/features/tree/feature.js +86 -64
- package/lib/esm/features/tree/types.d.ts +5 -3
- package/lib/esm/index.d.ts +3 -1
- package/lib/esm/index.js +2 -1
- package/lib/esm/test-utils/test-tree-do.d.ts +23 -0
- package/lib/esm/test-utils/test-tree-do.js +95 -0
- package/lib/esm/test-utils/test-tree-expect.d.ts +15 -0
- package/lib/esm/test-utils/test-tree-expect.js +58 -0
- package/lib/esm/test-utils/test-tree.d.ts +47 -0
- package/lib/esm/test-utils/test-tree.js +191 -0
- package/lib/esm/types/core.d.ts +31 -15
- package/lib/esm/utilities/errors.d.ts +1 -0
- package/lib/esm/utilities/errors.js +1 -0
- package/lib/esm/utilities/insert-items-at-target.js +10 -3
- package/lib/esm/utilities/remove-items-from-parents.js +14 -8
- package/lib/esm/utils.d.ts +3 -3
- package/lib/esm/utils.js +3 -3
- package/package.json +7 -3
- package/src/core/build-proxified-instance.ts +115 -0
- package/src/core/build-static-instance.ts +28 -0
- package/src/core/create-tree.ts +60 -62
- package/src/features/async-data-loader/async-data-loader.spec.ts +143 -0
- package/src/features/async-data-loader/feature.ts +33 -31
- package/src/features/async-data-loader/types.ts +3 -1
- package/src/features/drag-and-drop/drag-and-drop.spec.ts +716 -0
- package/src/features/drag-and-drop/feature.ts +109 -85
- package/src/features/drag-and-drop/types.ts +21 -7
- package/src/features/drag-and-drop/utils.ts +196 -55
- package/src/features/expand-all/expand-all.spec.ts +52 -0
- package/src/features/expand-all/feature.ts +8 -12
- package/src/features/hotkeys-core/feature.ts +1 -1
- package/src/features/main/types.ts +14 -1
- package/src/features/renaming/feature.ts +30 -29
- package/src/features/renaming/renaming.spec.ts +125 -0
- package/src/features/renaming/types.ts +1 -1
- package/src/features/search/feature.ts +34 -38
- package/src/features/search/search.spec.ts +115 -0
- package/src/features/search/types.ts +0 -1
- package/src/features/selection/feature.ts +29 -30
- package/src/features/selection/selection.spec.ts +220 -0
- package/src/features/sync-data-loader/feature.ts +8 -11
- package/src/features/tree/feature.ts +82 -87
- package/src/features/tree/tree.spec.ts +515 -0
- package/src/features/tree/types.ts +5 -3
- package/src/index.ts +4 -1
- package/src/test-utils/test-tree-do.ts +136 -0
- package/src/test-utils/test-tree-expect.ts +86 -0
- package/src/test-utils/test-tree.ts +217 -0
- package/src/types/core.ts +92 -33
- package/src/utilities/errors.ts +2 -0
- package/src/utilities/insert-items-at-target.ts +10 -3
- package/src/utilities/remove-items-from-parents.ts +15 -10
- package/src/utils.spec.ts +89 -0
- package/src/utils.ts +6 -6
- package/tsconfig.json +1 -0
- package/vitest.config.ts +6 -0
|
@@ -6,18 +6,19 @@ export const asyncDataLoaderFeature = {
|
|
|
6
6
|
stateHandlerNames: {
|
|
7
7
|
loadingItems: "setLoadingItems",
|
|
8
8
|
},
|
|
9
|
-
|
|
9
|
+
treeInstance: {
|
|
10
|
+
retrieveItemData: ({ tree }, itemId) => {
|
|
10
11
|
var _a, _b, _c, _d, _e;
|
|
11
12
|
var _f, _g;
|
|
12
|
-
const config =
|
|
13
|
-
const dataRef =
|
|
13
|
+
const config = tree.getConfig();
|
|
14
|
+
const dataRef = tree.getDataRef();
|
|
14
15
|
(_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
|
|
15
16
|
(_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
|
|
16
17
|
if (dataRef.current.itemData[itemId]) {
|
|
17
18
|
return dataRef.current.itemData[itemId];
|
|
18
19
|
}
|
|
19
|
-
if (!
|
|
20
|
-
|
|
20
|
+
if (!tree.getState().loadingItems.includes(itemId)) {
|
|
21
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => [
|
|
21
22
|
...loadingItems,
|
|
22
23
|
itemId,
|
|
23
24
|
]);
|
|
@@ -25,24 +26,25 @@ export const asyncDataLoaderFeature = {
|
|
|
25
26
|
var _a;
|
|
26
27
|
dataRef.current.itemData[itemId] = item;
|
|
27
28
|
(_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, itemId, item);
|
|
28
|
-
|
|
29
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
|
|
29
30
|
});
|
|
30
31
|
}
|
|
31
32
|
return (_e = (_d = config.createLoadingItemData) === null || _d === void 0 ? void 0 : _d.call(config)) !== null && _e !== void 0 ? _e : null;
|
|
32
|
-
},
|
|
33
|
+
},
|
|
34
|
+
retrieveChildrenIds: ({ tree }, itemId) => {
|
|
33
35
|
var _a, _b, _c, _d, _e;
|
|
34
36
|
var _f, _g;
|
|
35
|
-
const config =
|
|
36
|
-
const dataRef =
|
|
37
|
+
const config = tree.getConfig();
|
|
38
|
+
const dataRef = tree.getDataRef();
|
|
37
39
|
(_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
|
|
38
40
|
(_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
|
|
39
41
|
if (dataRef.current.childrenIds[itemId]) {
|
|
40
42
|
return dataRef.current.childrenIds[itemId];
|
|
41
43
|
}
|
|
42
|
-
if (
|
|
44
|
+
if (tree.getState().loadingItems.includes(itemId)) {
|
|
43
45
|
return [];
|
|
44
46
|
}
|
|
45
|
-
|
|
47
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => [
|
|
46
48
|
...loadingItems,
|
|
47
49
|
itemId,
|
|
48
50
|
]);
|
|
@@ -56,8 +58,8 @@ export const asyncDataLoaderFeature = {
|
|
|
56
58
|
const childrenIds = children.map(({ id }) => id);
|
|
57
59
|
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
58
60
|
(_b = config.onLoadedChildren) === null || _b === void 0 ? void 0 : _b.call(config, itemId, childrenIds);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
|
|
62
|
+
tree.rebuildTree();
|
|
61
63
|
});
|
|
62
64
|
}
|
|
63
65
|
else {
|
|
@@ -65,21 +67,33 @@ export const asyncDataLoaderFeature = {
|
|
|
65
67
|
var _a;
|
|
66
68
|
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
67
69
|
(_a = config.onLoadedChildren) === null || _a === void 0 ? void 0 : _a.call(config, itemId, childrenIds);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
|
|
71
|
+
tree.rebuildTree();
|
|
70
72
|
});
|
|
71
73
|
}
|
|
72
74
|
return [];
|
|
73
|
-
},
|
|
75
|
+
},
|
|
76
|
+
invalidateItemData: ({ tree }, itemId) => {
|
|
74
77
|
var _a;
|
|
75
|
-
const dataRef =
|
|
78
|
+
const dataRef = tree.getDataRef();
|
|
76
79
|
(_a = dataRef.current.itemData) === null || _a === void 0 ? true : delete _a[itemId];
|
|
77
|
-
|
|
78
|
-
},
|
|
80
|
+
tree.retrieveItemData(itemId);
|
|
81
|
+
},
|
|
82
|
+
invalidateChildrenIds: ({ tree }, itemId) => {
|
|
79
83
|
var _a;
|
|
80
|
-
const dataRef =
|
|
84
|
+
const dataRef = tree.getDataRef();
|
|
81
85
|
(_a = dataRef.current.childrenIds) === null || _a === void 0 ? true : delete _a[itemId];
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
86
|
+
tree.retrieveChildrenIds(itemId);
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
itemInstance: {
|
|
90
|
+
isLoading: ({ tree, item }) => tree.getState().loadingItems.includes(item.getItemMeta().itemId),
|
|
91
|
+
invalidateItemData: ({ tree, item }) => tree.invalidateItemData(item.getItemMeta().itemId),
|
|
92
|
+
invalidateChildrenIds: ({ tree, item }) => tree.invalidateChildrenIds(item.getItemMeta().itemId),
|
|
93
|
+
updateCachedChildrenIds: ({ tree, itemId }, childrenIds) => {
|
|
94
|
+
const dataRef = tree.getDataRef();
|
|
95
|
+
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
96
|
+
tree.rebuildTree();
|
|
97
|
+
},
|
|
98
|
+
},
|
|
85
99
|
};
|
|
@@ -35,7 +35,8 @@ export type AsyncDataLoaderFeatureDef<T> = {
|
|
|
35
35
|
itemInstance: SyncDataLoaderFeatureDef<T>["itemInstance"] & {
|
|
36
36
|
invalidateItemData: () => void;
|
|
37
37
|
invalidateChildrenIds: () => void;
|
|
38
|
-
|
|
38
|
+
updateCachedChildrenIds: (childrenIds: string[]) => void;
|
|
39
|
+
isLoading: () => boolean;
|
|
39
40
|
};
|
|
40
41
|
hotkeys: SyncDataLoaderFeatureDef<T>["hotkeys"];
|
|
41
42
|
};
|
|
@@ -3,45 +3,64 @@ import { makeStateUpdater } from "../../utils";
|
|
|
3
3
|
export const dragAndDropFeature = {
|
|
4
4
|
key: "dragAndDrop",
|
|
5
5
|
deps: ["selection"],
|
|
6
|
-
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: makeStateUpdater("dnd", tree) }, defaultConfig)),
|
|
6
|
+
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: makeStateUpdater("dnd", tree), canDropInbetween: true }, defaultConfig)),
|
|
7
7
|
stateHandlerNames: {
|
|
8
8
|
dnd: "setDndState",
|
|
9
9
|
},
|
|
10
|
-
|
|
10
|
+
treeInstance: {
|
|
11
|
+
getDropTarget: ({ tree }) => {
|
|
11
12
|
var _a, _b;
|
|
12
13
|
return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
|
|
13
|
-
},
|
|
14
|
+
},
|
|
15
|
+
getDragLineData: ({ tree }) => {
|
|
14
16
|
var _a, _b, _c, _d, _e;
|
|
17
|
+
// TODO doesnt work if scrolled down!
|
|
15
18
|
const target = tree.getDropTarget();
|
|
16
|
-
const
|
|
19
|
+
const indent = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1; // TODO rename to indent
|
|
17
20
|
if (!target || target.childIndex === null)
|
|
18
21
|
return null;
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
const leftOffset = target.dragLineLevel * ((_b = tree.getConfig().indent) !== null && _b !== void 0 ? _b : 1);
|
|
23
|
+
const targetItem = tree.getItems()[target.dragLineIndex];
|
|
24
|
+
if (!targetItem) {
|
|
25
|
+
const bb = (_d = (_c = tree
|
|
26
|
+
.getItems()[target.dragLineIndex - 1]) === null || _c === void 0 ? void 0 : _c.getElement()) === null || _d === void 0 ? void 0 : _d.getBoundingClientRect();
|
|
22
27
|
if (bb) {
|
|
23
28
|
return {
|
|
24
|
-
|
|
29
|
+
indent,
|
|
25
30
|
top: bb.bottom,
|
|
26
|
-
left: bb.left,
|
|
31
|
+
left: bb.left + leftOffset,
|
|
27
32
|
right: bb.right,
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
|
-
const bb = (_e =
|
|
36
|
+
const bb = (_e = targetItem.getElement()) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();
|
|
32
37
|
if (bb) {
|
|
33
38
|
return {
|
|
34
|
-
|
|
39
|
+
indent,
|
|
35
40
|
top: bb.top,
|
|
36
|
-
left: bb.left,
|
|
41
|
+
left: bb.left + leftOffset,
|
|
37
42
|
right: bb.right,
|
|
38
43
|
};
|
|
39
44
|
}
|
|
40
45
|
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
46
|
+
},
|
|
47
|
+
getDragLineStyle: ({ tree }, topOffset = -1, leftOffset = -8) => {
|
|
48
|
+
const dragLine = tree.getDragLineData();
|
|
49
|
+
return dragLine
|
|
50
|
+
? {
|
|
51
|
+
top: `${dragLine.top + topOffset}px`,
|
|
52
|
+
left: `${dragLine.left + leftOffset}px`,
|
|
53
|
+
width: `${dragLine.right - dragLine.left - leftOffset}px`,
|
|
54
|
+
pointerEvents: "none", // important to prevent capturing drag events
|
|
55
|
+
}
|
|
56
|
+
: { display: "none" };
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
itemInstance: {
|
|
60
|
+
// TODO instead of individual getMemoizedProp calls, use a wrapped getMemoizedProps or something (getProps: () => getMemoized({...})
|
|
61
|
+
getProps: ({ tree, item, prev }) => {
|
|
43
62
|
var _a, _b, _c;
|
|
44
|
-
return (Object.assign(Object.assign({}, prev
|
|
63
|
+
return (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: item.getMemoizedProp("dnd/onDragStart", () => (e) => {
|
|
45
64
|
var _a, _b, _c;
|
|
46
65
|
const selectedItems = tree.getSelectedItems();
|
|
47
66
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
@@ -63,34 +82,42 @@ export const dragAndDropFeature = {
|
|
|
63
82
|
});
|
|
64
83
|
}), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
|
|
65
84
|
var _a, _b, _c;
|
|
66
|
-
const target = getDropTarget(e, item, tree);
|
|
67
85
|
const dataRef = tree.getDataRef();
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
const nextDragCode = getDragCode(e, item, tree);
|
|
87
|
+
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
88
|
+
if (dataRef.current.lastAllowDrop) {
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
}
|
|
70
91
|
return;
|
|
71
92
|
}
|
|
72
|
-
|
|
93
|
+
dataRef.current.lastDragCode = nextDragCode;
|
|
94
|
+
const target = getDropTarget(e, item, tree);
|
|
95
|
+
if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
|
|
96
|
+
(!e.dataTransfer ||
|
|
97
|
+
!((_c = (_b = tree
|
|
98
|
+
.getConfig()).canDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
|
|
99
|
+
dataRef.current.lastAllowDrop = false;
|
|
73
100
|
return;
|
|
74
101
|
}
|
|
75
|
-
e.
|
|
76
|
-
|
|
77
|
-
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
102
|
+
if (!canDrop(e.dataTransfer, target, tree)) {
|
|
103
|
+
dataRef.current.lastAllowDrop = false;
|
|
78
104
|
return;
|
|
79
105
|
}
|
|
80
|
-
dataRef.current.lastDragCode = nextDragCode;
|
|
81
106
|
tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
|
|
107
|
+
dataRef.current.lastAllowDrop = true;
|
|
108
|
+
e.preventDefault();
|
|
82
109
|
}), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
|
|
83
110
|
const dataRef = tree.getDataRef();
|
|
84
111
|
dataRef.current.lastDragCode = "no-drag";
|
|
85
112
|
tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
|
|
86
113
|
}), onDragEnd: item.getMemoizedProp("dnd/onDragEnd", () => (e) => {
|
|
87
|
-
var _a, _b, _c;
|
|
114
|
+
var _a, _b, _c, _d;
|
|
88
115
|
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
89
116
|
tree.applySubStateUpdate("dnd", null);
|
|
90
|
-
if (e.dataTransfer.dropEffect === "none" || !draggedItems) {
|
|
117
|
+
if (((_b = e.dataTransfer) === null || _b === void 0 ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
91
118
|
return;
|
|
92
119
|
}
|
|
93
|
-
(
|
|
120
|
+
(_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
|
|
94
121
|
}), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
|
|
95
122
|
var _a, _b, _c;
|
|
96
123
|
const dataRef = tree.getDataRef();
|
|
@@ -106,30 +133,35 @@ export const dragAndDropFeature = {
|
|
|
106
133
|
if (draggedItems) {
|
|
107
134
|
(_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target);
|
|
108
135
|
}
|
|
109
|
-
else {
|
|
136
|
+
else if (e.dataTransfer) {
|
|
110
137
|
(_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target);
|
|
111
138
|
}
|
|
112
139
|
// TODO rebuild tree?
|
|
113
140
|
}) }));
|
|
114
|
-
},
|
|
141
|
+
},
|
|
142
|
+
isDropTarget: ({ tree, item }) => {
|
|
115
143
|
const target = tree.getDropTarget();
|
|
116
144
|
return target ? target.item.getId() === item.getId() : false;
|
|
117
|
-
},
|
|
145
|
+
},
|
|
146
|
+
isDropTargetAbove: ({ tree, item }) => {
|
|
118
147
|
const target = tree.getDropTarget();
|
|
119
148
|
if (!target ||
|
|
120
149
|
target.childIndex === null ||
|
|
121
150
|
target.item !== item.getParent())
|
|
122
151
|
return false;
|
|
123
152
|
return target.childIndex === item.getItemMeta().posInSet;
|
|
124
|
-
},
|
|
153
|
+
},
|
|
154
|
+
isDropTargetBelow: ({ tree, item }) => {
|
|
125
155
|
const target = tree.getDropTarget();
|
|
126
156
|
if (!target ||
|
|
127
157
|
target.childIndex === null ||
|
|
128
158
|
target.item !== item.getParent())
|
|
129
159
|
return false;
|
|
130
160
|
return target.childIndex - 1 === item.getItemMeta().posInSet;
|
|
131
|
-
},
|
|
161
|
+
},
|
|
162
|
+
isDraggingOver: ({ tree, item }) => {
|
|
132
163
|
var _a, _b;
|
|
133
164
|
return ((_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggingOverItem) === null || _b === void 0 ? void 0 : _b.getId()) === item.getId();
|
|
134
|
-
}
|
|
165
|
+
},
|
|
166
|
+
},
|
|
135
167
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ItemInstance, SetStateFn } from "../../types/core";
|
|
2
2
|
export type DndDataRef = {
|
|
3
3
|
lastDragCode?: string;
|
|
4
|
+
lastAllowDrop?: boolean;
|
|
4
5
|
};
|
|
5
6
|
export type DndState<T> = {
|
|
6
7
|
draggedItems?: ItemInstance<T>[];
|
|
@@ -8,7 +9,7 @@ export type DndState<T> = {
|
|
|
8
9
|
dragTarget?: DropTarget<T>;
|
|
9
10
|
};
|
|
10
11
|
export type DragLineData = {
|
|
11
|
-
|
|
12
|
+
indent: number;
|
|
12
13
|
top: number;
|
|
13
14
|
left: number;
|
|
14
15
|
right: number;
|
|
@@ -17,10 +18,14 @@ export type DropTarget<T> = {
|
|
|
17
18
|
item: ItemInstance<T>;
|
|
18
19
|
childIndex: number;
|
|
19
20
|
insertionIndex: number;
|
|
21
|
+
dragLineIndex: number;
|
|
22
|
+
dragLineLevel: number;
|
|
20
23
|
} | {
|
|
21
24
|
item: ItemInstance<T>;
|
|
22
25
|
childIndex: null;
|
|
23
26
|
insertionIndex: null;
|
|
27
|
+
dragLineIndex: null;
|
|
28
|
+
dragLineLevel: null;
|
|
24
29
|
};
|
|
25
30
|
export declare enum DropTargetPosition {
|
|
26
31
|
Top = "top",
|
|
@@ -32,13 +37,16 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
32
37
|
dnd?: DndState<T> | null;
|
|
33
38
|
};
|
|
34
39
|
config: {
|
|
35
|
-
setDndState?: SetStateFn<DndState<T> | null>;
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
setDndState?: SetStateFn<DndState<T> | undefined | null>;
|
|
41
|
+
/** Defines the size of the area at the top and bottom of an item where, when an item is dropped, the item willö
|
|
42
|
+
* be placed above or below the item within the same parent, as opposed to being placed inside the item.
|
|
43
|
+
* If `canDropInbetween` is `false`, this is ignored. */
|
|
44
|
+
reorderAreaPercentage?: number;
|
|
38
45
|
canDropInbetween?: boolean;
|
|
39
46
|
isItemDraggable?: (item: ItemInstance<T>) => boolean;
|
|
40
47
|
canDrag?: (items: ItemInstance<T>[]) => boolean;
|
|
41
48
|
canDrop?: (items: ItemInstance<T>[], target: DropTarget<T>) => boolean;
|
|
49
|
+
indent?: number;
|
|
42
50
|
createForeignDragObject?: (items: ItemInstance<T>[]) => {
|
|
43
51
|
format: string;
|
|
44
52
|
data: any;
|
|
@@ -58,6 +66,7 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
58
66
|
treeInstance: {
|
|
59
67
|
getDropTarget: () => DropTarget<T> | null;
|
|
60
68
|
getDragLineData: () => DragLineData | null;
|
|
69
|
+
getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
|
|
61
70
|
};
|
|
62
71
|
itemInstance: {
|
|
63
72
|
isDropTarget: () => boolean;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ItemInstance, TreeInstance } from "../../types/core";
|
|
2
2
|
import { DropTarget } from "./types";
|
|
3
|
-
export declare const getDragCode: ({ item, childIndex }: DropTarget<any>) => string;
|
|
4
|
-
export declare const getDropOffset: (e: any, item: ItemInstance<any>) => number;
|
|
5
3
|
export declare const canDrop: (dataTransfer: DataTransfer | null, target: DropTarget<any>, tree: TreeInstance<any>) => boolean;
|
|
4
|
+
export declare const getDragCode: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>) => string;
|
|
6
5
|
export declare const getDropTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>, canDropInbetween?: boolean | undefined) => DropTarget<any>;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
var ItemDropCategory;
|
|
2
|
+
(function (ItemDropCategory) {
|
|
3
|
+
ItemDropCategory[ItemDropCategory["Item"] = 0] = "Item";
|
|
4
|
+
ItemDropCategory[ItemDropCategory["ExpandedFolder"] = 1] = "ExpandedFolder";
|
|
5
|
+
ItemDropCategory[ItemDropCategory["LastInGroup"] = 2] = "LastInGroup";
|
|
6
|
+
})(ItemDropCategory || (ItemDropCategory = {}));
|
|
7
|
+
var PlacementType;
|
|
8
|
+
(function (PlacementType) {
|
|
9
|
+
PlacementType[PlacementType["ReorderAbove"] = 0] = "ReorderAbove";
|
|
10
|
+
PlacementType[PlacementType["ReorderBelow"] = 1] = "ReorderBelow";
|
|
11
|
+
PlacementType[PlacementType["MakeChild"] = 2] = "MakeChild";
|
|
12
|
+
PlacementType[PlacementType["Reparent"] = 3] = "Reparent";
|
|
13
|
+
})(PlacementType || (PlacementType = {}));
|
|
8
14
|
export const canDrop = (dataTransfer, target, tree) => {
|
|
9
15
|
var _a, _b, _c, _d;
|
|
10
16
|
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
@@ -12,6 +18,11 @@ export const canDrop = (dataTransfer, target, tree) => {
|
|
|
12
18
|
if (draggedItems && !((_c = (_b = config.canDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target)) !== null && _c !== void 0 ? _c : true)) {
|
|
13
19
|
return false;
|
|
14
20
|
}
|
|
21
|
+
if (draggedItems &&
|
|
22
|
+
draggedItems.some((draggedItem) => target.item.getId() === draggedItem.getId() ||
|
|
23
|
+
target.item.isDescendentOf(draggedItem.getId()))) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
15
26
|
if (!draggedItems &&
|
|
16
27
|
dataTransfer &&
|
|
17
28
|
!((_d = config.canDropForeignDragObject) === null || _d === void 0 ? void 0 : _d.call(config, dataTransfer, target))) {
|
|
@@ -19,52 +30,145 @@ export const canDrop = (dataTransfer, target, tree) => {
|
|
|
19
30
|
}
|
|
20
31
|
return true;
|
|
21
32
|
};
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
return
|
|
33
|
+
const getItemDropCategory = (item) => {
|
|
34
|
+
if (item.isExpanded()) {
|
|
35
|
+
return ItemDropCategory.ExpandedFolder;
|
|
25
36
|
}
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
const parent = item.getParent();
|
|
38
|
+
if (parent && item.getIndexInParent() === parent.getItemMeta().setSize - 1) {
|
|
39
|
+
return ItemDropCategory.LastInGroup;
|
|
28
40
|
}
|
|
29
|
-
return
|
|
41
|
+
return ItemDropCategory.Item;
|
|
30
42
|
};
|
|
31
|
-
|
|
32
|
-
var _a, _b, _c
|
|
43
|
+
const getTargetPlacement = (e, item, tree, canMakeChild) => {
|
|
44
|
+
var _a, _b, _c;
|
|
33
45
|
const config = tree.getConfig();
|
|
46
|
+
if (!config.canDropInbetween) {
|
|
47
|
+
return canMakeChild
|
|
48
|
+
? { type: PlacementType.MakeChild }
|
|
49
|
+
: { type: PlacementType.ReorderBelow };
|
|
50
|
+
}
|
|
51
|
+
const bb = (_a = item.getElement()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
52
|
+
const topPercent = bb ? (e.pageY - bb.top) / bb.height : 0.5;
|
|
53
|
+
const leftPixels = bb ? e.pageX - bb.left : 0;
|
|
54
|
+
const targetDropCategory = getItemDropCategory(item);
|
|
55
|
+
const reorderAreaPercentage = !canMakeChild
|
|
56
|
+
? 0.5
|
|
57
|
+
: (_b = config.reorderAreaPercentage) !== null && _b !== void 0 ? _b : 0.3;
|
|
58
|
+
const indent = (_c = config.indent) !== null && _c !== void 0 ? _c : 20;
|
|
59
|
+
const makeChildType = canMakeChild
|
|
60
|
+
? PlacementType.MakeChild
|
|
61
|
+
: PlacementType.ReorderBelow;
|
|
62
|
+
if (targetDropCategory === ItemDropCategory.ExpandedFolder) {
|
|
63
|
+
if (topPercent < reorderAreaPercentage) {
|
|
64
|
+
return { type: PlacementType.ReorderAbove };
|
|
65
|
+
}
|
|
66
|
+
return { type: makeChildType };
|
|
67
|
+
}
|
|
68
|
+
if (targetDropCategory === ItemDropCategory.LastInGroup) {
|
|
69
|
+
if (leftPixels < item.getItemMeta().level * indent) {
|
|
70
|
+
if (topPercent < 0.5) {
|
|
71
|
+
return { type: PlacementType.ReorderAbove };
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
type: PlacementType.Reparent,
|
|
75
|
+
reparentLevel: Math.floor(leftPixels / indent),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// if not at left of item area, treat as if it was a normal item
|
|
79
|
+
}
|
|
80
|
+
// targetDropCategory === ItemDropCategory.Item
|
|
81
|
+
if (topPercent < reorderAreaPercentage) {
|
|
82
|
+
return { type: PlacementType.ReorderAbove };
|
|
83
|
+
}
|
|
84
|
+
if (topPercent > 1 - reorderAreaPercentage) {
|
|
85
|
+
return { type: PlacementType.ReorderBelow };
|
|
86
|
+
}
|
|
87
|
+
return { type: makeChildType };
|
|
88
|
+
};
|
|
89
|
+
export const getDragCode = (e, item, tree) => {
|
|
90
|
+
const placement = getTargetPlacement(e, item, tree, true);
|
|
91
|
+
return [
|
|
92
|
+
item.getId(),
|
|
93
|
+
placement.type,
|
|
94
|
+
placement.type === PlacementType.Reparent ? placement.reparentLevel : 0,
|
|
95
|
+
].join("__");
|
|
96
|
+
};
|
|
97
|
+
const getNthParent = (item, n) => {
|
|
98
|
+
if (n === item.getItemMeta().level) {
|
|
99
|
+
return item;
|
|
100
|
+
}
|
|
101
|
+
return getNthParent(item.getParent(), n);
|
|
102
|
+
};
|
|
103
|
+
export const getDropTarget = (e, item, tree, canDropInbetween = tree.getConfig().canDropInbetween) => {
|
|
104
|
+
var _a, _b, _c;
|
|
34
105
|
const draggedItems = (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) !== null && _b !== void 0 ? _b : [];
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
106
|
+
const itemMeta = item.getItemMeta();
|
|
107
|
+
const parent = item.getParent();
|
|
108
|
+
const itemTarget = {
|
|
109
|
+
item,
|
|
38
110
|
childIndex: null,
|
|
39
111
|
insertionIndex: null,
|
|
112
|
+
dragLineIndex: null,
|
|
113
|
+
dragLineLevel: null,
|
|
40
114
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
115
|
+
const parentTarget = parent
|
|
116
|
+
? {
|
|
117
|
+
item: parent,
|
|
118
|
+
childIndex: null,
|
|
119
|
+
insertionIndex: null,
|
|
120
|
+
dragLineIndex: null,
|
|
121
|
+
dragLineLevel: null,
|
|
44
122
|
}
|
|
123
|
+
: null;
|
|
124
|
+
const canBecomeSibling = parentTarget && canDrop(e.dataTransfer, parentTarget, tree);
|
|
125
|
+
const canMakeChild = canDrop(e.dataTransfer, itemTarget, tree);
|
|
126
|
+
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
127
|
+
if (!canDropInbetween &&
|
|
128
|
+
parent &&
|
|
129
|
+
canBecomeSibling &&
|
|
130
|
+
placement.type !== PlacementType.MakeChild) {
|
|
131
|
+
return parentTarget;
|
|
132
|
+
}
|
|
133
|
+
if (!canDropInbetween && parent && !canBecomeSibling) {
|
|
134
|
+
// TODO! this breaks in story DND/Can Drop. Maybe move this logic into a composable DropTargetStrategy[] ?
|
|
135
|
+
return getDropTarget(e, parent, tree, false);
|
|
136
|
+
}
|
|
137
|
+
if (!parent) {
|
|
138
|
+
// Shouldn't happen, but if dropped "next" to root item, just drop it inside
|
|
45
139
|
return itemTarget;
|
|
46
140
|
}
|
|
47
|
-
|
|
48
|
-
const offset = getDropOffset(e, item);
|
|
49
|
-
const pos = canDropInside
|
|
50
|
-
? getDropTargetPosition(offset, (_c = config.topLinePercentage) !== null && _c !== void 0 ? _c : 0.3, (_d = config.bottomLinePercentage) !== null && _d !== void 0 ? _d : 0.7)
|
|
51
|
-
: getDropTargetPosition(offset, 0.5, 0.5);
|
|
52
|
-
if (pos === DropTargetPosition.Item) {
|
|
141
|
+
if (placement.type === PlacementType.MakeChild) {
|
|
53
142
|
return itemTarget;
|
|
54
143
|
}
|
|
55
|
-
if (!
|
|
56
|
-
return getDropTarget(e,
|
|
144
|
+
if (!canBecomeSibling) {
|
|
145
|
+
return getDropTarget(e, parent, tree, false);
|
|
146
|
+
}
|
|
147
|
+
if (placement.type === PlacementType.Reparent) {
|
|
148
|
+
const reparentedTarget = getNthParent(item, placement.reparentLevel - 1);
|
|
149
|
+
const targetItemAbove = getNthParent(item, placement.reparentLevel); // .getItemBelow()!;
|
|
150
|
+
const targetIndex = targetItemAbove.getIndexInParent() + 1;
|
|
151
|
+
// TODO possibly count items dragged out above the new target
|
|
152
|
+
return {
|
|
153
|
+
item: reparentedTarget,
|
|
154
|
+
childIndex: targetIndex,
|
|
155
|
+
insertionIndex: targetIndex,
|
|
156
|
+
dragLineIndex: itemMeta.index + 1,
|
|
157
|
+
dragLineLevel: placement.reparentLevel,
|
|
158
|
+
};
|
|
57
159
|
}
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
160
|
+
const maybeAddOneForBelow = placement.type === PlacementType.ReorderAbove ? 0 : 1;
|
|
161
|
+
const childIndex = item.getIndexInParent() + maybeAddOneForBelow;
|
|
162
|
+
const numberOfDragItemsBeforeTarget = (_c = parent
|
|
61
163
|
.getChildren()
|
|
62
164
|
.slice(0, childIndex)
|
|
63
165
|
.reduce((counter, child) => child && (draggedItems === null || draggedItems === void 0 ? void 0 : draggedItems.some((i) => i.getId() === child.getId()))
|
|
64
166
|
? ++counter
|
|
65
|
-
: counter, 0);
|
|
167
|
+
: counter, 0)) !== null && _c !== void 0 ? _c : 0;
|
|
66
168
|
return {
|
|
67
|
-
item:
|
|
169
|
+
item: parent,
|
|
170
|
+
dragLineIndex: itemMeta.index + maybeAddOneForBelow,
|
|
171
|
+
dragLineLevel: itemMeta.level,
|
|
68
172
|
childIndex,
|
|
69
173
|
// TODO performance could be improved by computing this only when dragcode changed
|
|
70
174
|
insertionIndex: childIndex - numberOfDragItemsBeforeTarget,
|
|
@@ -10,13 +10,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { poll } from "../../utils";
|
|
11
11
|
export const expandAllFeature = {
|
|
12
12
|
key: "expand-all",
|
|
13
|
-
|
|
13
|
+
treeInstance: {
|
|
14
|
+
expandAll: (_a, cancelToken_1) => __awaiter(void 0, [_a, cancelToken_1], void 0, function* ({ tree }, cancelToken) {
|
|
14
15
|
yield Promise.all(tree.getItems().map((item) => item.expandAll(cancelToken)));
|
|
15
|
-
}),
|
|
16
|
+
}),
|
|
17
|
+
collapseAll: ({ tree }) => {
|
|
16
18
|
tree.applySubStateUpdate("expandedItems", []);
|
|
17
19
|
tree.rebuildTree();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
itemInstance: {
|
|
23
|
+
expandAll: (_a, cancelToken_1) => __awaiter(void 0, [_a, cancelToken_1], void 0, function* ({ tree, item }, cancelToken) {
|
|
20
24
|
if (cancelToken === null || cancelToken === void 0 ? void 0 : cancelToken.current) {
|
|
21
25
|
return;
|
|
22
26
|
}
|
|
@@ -29,10 +33,12 @@ export const expandAllFeature = {
|
|
|
29
33
|
yield poll(() => !tree.getState().loadingItems.includes(child.getId()));
|
|
30
34
|
yield (child === null || child === void 0 ? void 0 : child.expandAll(cancelToken));
|
|
31
35
|
})));
|
|
32
|
-
}),
|
|
36
|
+
}),
|
|
37
|
+
collapseAll: ({ item }) => {
|
|
33
38
|
for (const child of item.getChildren()) {
|
|
34
39
|
child === null || child === void 0 ? void 0 : child.collapseAll();
|
|
35
40
|
}
|
|
36
41
|
item.collapse();
|
|
37
|
-
}
|
|
42
|
+
},
|
|
43
|
+
},
|
|
38
44
|
};
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { FeatureImplementation, HotkeysConfig, ItemInstance, SetStateFn, TreeConfig, TreeState, Updater } from "../../types/core";
|
|
1
|
+
import { FeatureImplementation, HotkeysConfig, ItemInstance, SetStateFn, TreeConfig, TreeInstance, TreeState, Updater } from "../../types/core";
|
|
2
2
|
import { ItemMeta } from "../tree/types";
|
|
3
|
+
export type InstanceTypeMap = {
|
|
4
|
+
itemInstance: ItemInstance<any>;
|
|
5
|
+
treeInstance: TreeInstance<any>;
|
|
6
|
+
};
|
|
7
|
+
export type InstanceBuilder = <T extends keyof InstanceTypeMap>(features: FeatureImplementation[], instanceType: T, buildOpts: (self: any) => any) => [instance: InstanceTypeMap[T], finalize: () => void];
|
|
3
8
|
export type MainFeatureDef<T = any> = {
|
|
4
9
|
state: {};
|
|
5
10
|
config: {
|
|
6
11
|
features?: FeatureImplementation<any>[];
|
|
7
12
|
initialState?: Partial<TreeState<T>>;
|
|
8
13
|
state?: Partial<TreeState<T>>;
|
|
9
|
-
setState?: SetStateFn<TreeState<T
|
|
14
|
+
setState?: SetStateFn<Partial<TreeState<T>>>;
|
|
15
|
+
instanceBuilder?: InstanceBuilder;
|
|
10
16
|
};
|
|
11
17
|
treeInstance: {
|
|
12
18
|
/** @internal */
|