@headless-tree/core 0.0.10 → 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 +6 -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
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildProxiedInstance = void 0;
|
|
4
|
+
const errors_1 = require("../utilities/errors");
|
|
5
|
+
const noop = () => { };
|
|
6
|
+
const findPrevInstanceMethod = (features, instanceType, methodKey, featureSearchIndex) => {
|
|
7
|
+
var _a;
|
|
8
|
+
for (let i = featureSearchIndex; i >= 0; i--) {
|
|
9
|
+
const feature = features[i];
|
|
10
|
+
const itemInstanceMethod = (_a = feature[instanceType]) === null || _a === void 0 ? void 0 : _a[methodKey];
|
|
11
|
+
if (itemInstanceMethod) {
|
|
12
|
+
return i;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
const invokeInstanceMethod = (features, instanceType, opts, methodKey, featureIndex, args) => {
|
|
18
|
+
var _a;
|
|
19
|
+
const prevIndex = findPrevInstanceMethod(features, instanceType, methodKey, featureIndex - 1);
|
|
20
|
+
const itemInstanceMethod = (_a = features[featureIndex][instanceType]) === null || _a === void 0 ? void 0 : _a[methodKey];
|
|
21
|
+
return itemInstanceMethod(Object.assign(Object.assign({}, opts), { prev: prevIndex !== null
|
|
22
|
+
? (...newArgs) => invokeInstanceMethod(features, instanceType, opts, methodKey, prevIndex, newArgs)
|
|
23
|
+
: null }), ...args);
|
|
24
|
+
};
|
|
25
|
+
const buildProxiedInstance = (features, instanceType, buildOpts) => {
|
|
26
|
+
// demo with prototypes: https://jsfiddle.net/bgenc58r/
|
|
27
|
+
const opts = {};
|
|
28
|
+
const item = new Proxy({}, {
|
|
29
|
+
has(target, key) {
|
|
30
|
+
if (typeof key === "symbol") {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (key === "toJSON") {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const hasInstanceMethod = findPrevInstanceMethod(features, instanceType, key, features.length - 1);
|
|
37
|
+
return Boolean(hasInstanceMethod);
|
|
38
|
+
},
|
|
39
|
+
get(target, key) {
|
|
40
|
+
if (typeof key === "symbol") {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
if (key === "toJSON") {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
return (...args) => {
|
|
47
|
+
const featureIndex = findPrevInstanceMethod(features, instanceType, key, features.length - 1);
|
|
48
|
+
if (featureIndex === null) {
|
|
49
|
+
throw (0, errors_1.throwError)(`feature missing for method ${key}`);
|
|
50
|
+
}
|
|
51
|
+
return invokeInstanceMethod(features, instanceType, opts, key, featureIndex, args);
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
Object.assign(opts, buildOpts(item));
|
|
56
|
+
return [item, noop];
|
|
57
|
+
};
|
|
58
|
+
exports.buildProxiedInstance = buildProxiedInstance;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable no-continue,no-labels,no-extra-label */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.buildStaticInstance = void 0;
|
|
5
|
+
const buildStaticInstance = (features, instanceType, buildOpts) => {
|
|
6
|
+
const instance = {};
|
|
7
|
+
const finalize = () => {
|
|
8
|
+
const opts = buildOpts(instance);
|
|
9
|
+
featureLoop: for (let i = 0; i < features.length; i++) {
|
|
10
|
+
// Loop goes in forward order, because later features overwrite previous ones
|
|
11
|
+
// TODO loop order correct? I think so...
|
|
12
|
+
const definition = features[i][instanceType];
|
|
13
|
+
if (!definition)
|
|
14
|
+
continue featureLoop;
|
|
15
|
+
methodLoop: for (const [key, method] of Object.entries(definition)) {
|
|
16
|
+
if (!method)
|
|
17
|
+
continue methodLoop;
|
|
18
|
+
const prev = instance[key];
|
|
19
|
+
instance[key] = (...args) => {
|
|
20
|
+
return method(Object.assign(Object.assign({}, opts), { prev }), ...args);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
return [instance, finalize];
|
|
26
|
+
};
|
|
27
|
+
exports.buildStaticInstance = buildStaticInstance;
|
|
@@ -2,24 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createTree = void 0;
|
|
4
4
|
const feature_1 = require("../features/tree/feature");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const itemInstance = {};
|
|
8
|
-
for (const feature of features) {
|
|
9
|
-
Object.assign(
|
|
10
|
-
// TODO dont run createItemInstance, but assign prototype objects instead?
|
|
11
|
-
// https://jsfiddle.net/bgenc58r/
|
|
12
|
-
itemInstance, (_b = (_a = feature.createItemInstance) === null || _a === void 0 ? void 0 : _a.call(feature, Object.assign({}, itemInstance), itemInstance, tree, itemId)) !== null && _b !== void 0 ? _b : {});
|
|
13
|
-
}
|
|
14
|
-
return itemInstance;
|
|
15
|
-
};
|
|
5
|
+
const build_static_instance_1 = require("./build-static-instance");
|
|
6
|
+
const errors_1 = require("../utilities/errors");
|
|
16
7
|
const verifyFeatures = (features) => {
|
|
17
8
|
var _a;
|
|
18
9
|
const loadedFeatures = features === null || features === void 0 ? void 0 : features.map((feature) => feature.key);
|
|
19
10
|
for (const feature of features !== null && features !== void 0 ? features : []) {
|
|
20
11
|
const missingDependency = (_a = feature.deps) === null || _a === void 0 ? void 0 : _a.find((dep) => !(loadedFeatures === null || loadedFeatures === void 0 ? void 0 : loadedFeatures.includes(dep)));
|
|
21
12
|
if (missingDependency) {
|
|
22
|
-
throw
|
|
13
|
+
throw (0, errors_1.throwError)(`${feature.key} needs ${missingDependency}`);
|
|
23
14
|
}
|
|
24
15
|
}
|
|
25
16
|
};
|
|
@@ -32,14 +23,16 @@ const compareFeatures = (feature1, feature2) => {
|
|
|
32
23
|
};
|
|
33
24
|
const sortFeatures = (features = []) => features.sort(compareFeatures);
|
|
34
25
|
const createTree = (initialConfig) => {
|
|
35
|
-
var _a, _b, _c, _d
|
|
36
|
-
const
|
|
26
|
+
var _a, _b, _c, _d;
|
|
27
|
+
const buildInstance = (_a = initialConfig.instanceBuilder) !== null && _a !== void 0 ? _a : build_static_instance_1.buildStaticInstance;
|
|
37
28
|
const additionalFeatures = [
|
|
38
29
|
feature_1.treeFeature,
|
|
39
30
|
...sortFeatures(initialConfig.features),
|
|
40
31
|
];
|
|
41
32
|
verifyFeatures(additionalFeatures);
|
|
42
|
-
|
|
33
|
+
const features = [...additionalFeatures];
|
|
34
|
+
const [treeInstance, finalizeTree] = buildInstance(features, "treeInstance", (tree) => ({ tree }));
|
|
35
|
+
let state = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getInitialState) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, (_c = (_b = initialConfig.initialState) !== null && _b !== void 0 ? _b : initialConfig.state) !== null && _c !== void 0 ? _c : {});
|
|
43
36
|
let config = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getDefaultConfig) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, initialConfig);
|
|
44
37
|
const stateHandlerNames = additionalFeatures.reduce((acc, feature) => (Object.assign(Object.assign({}, acc), feature.stateHandlerNames)), {});
|
|
45
38
|
let treeElement;
|
|
@@ -50,11 +43,12 @@ const createTree = (initialConfig) => {
|
|
|
50
43
|
const itemDataRefs = {};
|
|
51
44
|
let itemMetaMap = {};
|
|
52
45
|
const hotkeyPresets = {};
|
|
53
|
-
const rebuildItemMeta = (
|
|
46
|
+
const rebuildItemMeta = () => {
|
|
54
47
|
// TODO can we find a way to only run this for the changed substructure?
|
|
55
48
|
itemInstances = [];
|
|
56
49
|
itemMetaMap = {};
|
|
57
|
-
const rootInstance =
|
|
50
|
+
const [rootInstance, finalizeRootInstance] = buildInstance(features, "itemInstance", (item) => ({ item, tree: treeInstance, itemId: config.rootItemId }));
|
|
51
|
+
finalizeRootInstance();
|
|
58
52
|
itemInstancesMap[config.rootItemId] = rootInstance;
|
|
59
53
|
itemMetaMap[config.rootItemId] = {
|
|
60
54
|
itemId: config.rootItemId,
|
|
@@ -67,7 +61,12 @@ const createTree = (initialConfig) => {
|
|
|
67
61
|
for (const item of treeInstance.getItemsMeta()) {
|
|
68
62
|
itemMetaMap[item.itemId] = item;
|
|
69
63
|
if (!itemInstancesMap[item.itemId]) {
|
|
70
|
-
const instance =
|
|
64
|
+
const [instance, finalizeInstance] = buildInstance(features, "itemInstance", (instance) => ({
|
|
65
|
+
item: instance,
|
|
66
|
+
tree: treeInstance,
|
|
67
|
+
itemId: item.itemId,
|
|
68
|
+
}));
|
|
69
|
+
finalizeInstance();
|
|
71
70
|
itemInstancesMap[item.itemId] = instance;
|
|
72
71
|
itemInstances.push(instance);
|
|
73
72
|
}
|
|
@@ -83,25 +82,36 @@ const createTree = (initialConfig) => {
|
|
|
83
82
|
};
|
|
84
83
|
const mainFeature = {
|
|
85
84
|
key: "main",
|
|
86
|
-
|
|
85
|
+
treeInstance: {
|
|
86
|
+
getState: () => state,
|
|
87
|
+
setState: ({}, updater) => {
|
|
87
88
|
var _a;
|
|
88
89
|
// Not necessary, since I think the subupdate below keeps the state fresh anyways?
|
|
89
90
|
// state = typeof updater === "function" ? updater(state) : updater;
|
|
90
|
-
(_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state);
|
|
91
|
-
},
|
|
91
|
+
(_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state); // TODO this cant be right... This doesnt allow external state updates
|
|
92
|
+
},
|
|
93
|
+
applySubStateUpdate: ({}, stateName, updater) => {
|
|
92
94
|
state[stateName] =
|
|
93
95
|
typeof updater === "function" ? updater(state[stateName]) : updater;
|
|
94
|
-
config[stateHandlerNames[stateName]]
|
|
95
|
-
|
|
96
|
+
const externalStateSetter = config[stateHandlerNames[stateName]];
|
|
97
|
+
externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
|
|
98
|
+
},
|
|
99
|
+
// TODO rebuildSubTree: (itemId: string) => void;
|
|
100
|
+
rebuildTree: () => {
|
|
96
101
|
var _a;
|
|
97
|
-
rebuildItemMeta(
|
|
102
|
+
rebuildItemMeta();
|
|
98
103
|
(_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state);
|
|
99
|
-
},
|
|
104
|
+
},
|
|
105
|
+
getConfig: () => config,
|
|
106
|
+
setConfig: (_, updater) => {
|
|
100
107
|
config = typeof updater === "function" ? updater(config) : updater;
|
|
101
108
|
if (config.state) {
|
|
102
109
|
state = Object.assign(Object.assign({}, state), config.state);
|
|
103
110
|
}
|
|
104
|
-
},
|
|
111
|
+
},
|
|
112
|
+
getItemInstance: ({}, itemId) => itemInstancesMap[itemId],
|
|
113
|
+
getItems: () => itemInstances,
|
|
114
|
+
registerElement: ({}, element) => {
|
|
105
115
|
if (treeElement === element) {
|
|
106
116
|
return;
|
|
107
117
|
}
|
|
@@ -112,29 +122,38 @@ const createTree = (initialConfig) => {
|
|
|
112
122
|
eachFeature((feature) => { var _a; return (_a = feature.onTreeMount) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance, element); });
|
|
113
123
|
}
|
|
114
124
|
treeElement = element;
|
|
115
|
-
},
|
|
116
|
-
|
|
125
|
+
},
|
|
126
|
+
getElement: () => treeElement,
|
|
127
|
+
getDataRef: () => treeDataRef,
|
|
128
|
+
getHotkeyPresets: () => hotkeyPresets,
|
|
129
|
+
},
|
|
130
|
+
itemInstance: {
|
|
131
|
+
// TODO just change to a getRef method that memoizes, maybe as part of getProps
|
|
132
|
+
registerElement: ({ itemId, item }, element) => {
|
|
117
133
|
if (itemElementsMap[itemId] === element) {
|
|
118
134
|
return;
|
|
119
135
|
}
|
|
120
136
|
const oldElement = itemElementsMap[itemId];
|
|
121
137
|
if (oldElement && !element) {
|
|
122
|
-
eachFeature((feature) => { var _a; return (_a = feature.onItemUnmount) === null || _a === void 0 ? void 0 : _a.call(feature,
|
|
138
|
+
eachFeature((feature) => { var _a; return (_a = feature.onItemUnmount) === null || _a === void 0 ? void 0 : _a.call(feature, item, oldElement, treeInstance); });
|
|
123
139
|
}
|
|
124
140
|
else if (!oldElement && element) {
|
|
125
|
-
eachFeature((feature) => { var _a; return (_a = feature.onItemMount) === null || _a === void 0 ? void 0 : _a.call(feature,
|
|
141
|
+
eachFeature((feature) => { var _a; return (_a = feature.onItemMount) === null || _a === void 0 ? void 0 : _a.call(feature, item, element, treeInstance); });
|
|
126
142
|
}
|
|
127
143
|
itemElementsMap[itemId] = element;
|
|
128
|
-
},
|
|
144
|
+
},
|
|
145
|
+
getElement: ({ itemId }) => itemElementsMap[itemId],
|
|
129
146
|
// eslint-disable-next-line no-return-assign
|
|
130
|
-
getDataRef: () => { var _a; return ((_a = itemDataRefs[itemId]) !== null && _a !== void 0 ? _a : (itemDataRefs[itemId] = { current: {} })); },
|
|
147
|
+
getDataRef: ({ itemId }) => { var _a; return ((_a = itemDataRefs[itemId]) !== null && _a !== void 0 ? _a : (itemDataRefs[itemId] = { current: {} })); },
|
|
148
|
+
getItemMeta: ({ itemId }) => itemMetaMap[itemId],
|
|
149
|
+
},
|
|
131
150
|
};
|
|
132
|
-
|
|
151
|
+
features.unshift(mainFeature);
|
|
133
152
|
for (const feature of features) {
|
|
134
|
-
Object.assign(
|
|
135
|
-
Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
|
|
153
|
+
Object.assign(hotkeyPresets, (_d = feature.hotkeys) !== null && _d !== void 0 ? _d : {});
|
|
136
154
|
}
|
|
137
|
-
|
|
155
|
+
finalizeTree();
|
|
156
|
+
rebuildItemMeta();
|
|
138
157
|
return treeInstance;
|
|
139
158
|
};
|
|
140
159
|
exports.createTree = createTree;
|
|
@@ -9,18 +9,19 @@ exports.asyncDataLoaderFeature = {
|
|
|
9
9
|
stateHandlerNames: {
|
|
10
10
|
loadingItems: "setLoadingItems",
|
|
11
11
|
},
|
|
12
|
-
|
|
12
|
+
treeInstance: {
|
|
13
|
+
retrieveItemData: ({ tree }, itemId) => {
|
|
13
14
|
var _a, _b, _c, _d, _e;
|
|
14
15
|
var _f, _g;
|
|
15
|
-
const config =
|
|
16
|
-
const dataRef =
|
|
16
|
+
const config = tree.getConfig();
|
|
17
|
+
const dataRef = tree.getDataRef();
|
|
17
18
|
(_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
|
|
18
19
|
(_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
|
|
19
20
|
if (dataRef.current.itemData[itemId]) {
|
|
20
21
|
return dataRef.current.itemData[itemId];
|
|
21
22
|
}
|
|
22
|
-
if (!
|
|
23
|
-
|
|
23
|
+
if (!tree.getState().loadingItems.includes(itemId)) {
|
|
24
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => [
|
|
24
25
|
...loadingItems,
|
|
25
26
|
itemId,
|
|
26
27
|
]);
|
|
@@ -28,24 +29,25 @@ exports.asyncDataLoaderFeature = {
|
|
|
28
29
|
var _a;
|
|
29
30
|
dataRef.current.itemData[itemId] = item;
|
|
30
31
|
(_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, itemId, item);
|
|
31
|
-
|
|
32
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
return (_e = (_d = config.createLoadingItemData) === null || _d === void 0 ? void 0 : _d.call(config)) !== null && _e !== void 0 ? _e : null;
|
|
35
|
-
},
|
|
36
|
+
},
|
|
37
|
+
retrieveChildrenIds: ({ tree }, itemId) => {
|
|
36
38
|
var _a, _b, _c, _d, _e;
|
|
37
39
|
var _f, _g;
|
|
38
|
-
const config =
|
|
39
|
-
const dataRef =
|
|
40
|
+
const config = tree.getConfig();
|
|
41
|
+
const dataRef = tree.getDataRef();
|
|
40
42
|
(_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
|
|
41
43
|
(_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
|
|
42
44
|
if (dataRef.current.childrenIds[itemId]) {
|
|
43
45
|
return dataRef.current.childrenIds[itemId];
|
|
44
46
|
}
|
|
45
|
-
if (
|
|
47
|
+
if (tree.getState().loadingItems.includes(itemId)) {
|
|
46
48
|
return [];
|
|
47
49
|
}
|
|
48
|
-
|
|
50
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => [
|
|
49
51
|
...loadingItems,
|
|
50
52
|
itemId,
|
|
51
53
|
]);
|
|
@@ -59,8 +61,8 @@ exports.asyncDataLoaderFeature = {
|
|
|
59
61
|
const childrenIds = children.map(({ id }) => id);
|
|
60
62
|
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
61
63
|
(_b = config.onLoadedChildren) === null || _b === void 0 ? void 0 : _b.call(config, itemId, childrenIds);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
|
|
65
|
+
tree.rebuildTree();
|
|
64
66
|
});
|
|
65
67
|
}
|
|
66
68
|
else {
|
|
@@ -68,21 +70,33 @@ exports.asyncDataLoaderFeature = {
|
|
|
68
70
|
var _a;
|
|
69
71
|
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
70
72
|
(_a = config.onLoadedChildren) === null || _a === void 0 ? void 0 : _a.call(config, itemId, childrenIds);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
|
|
74
|
+
tree.rebuildTree();
|
|
73
75
|
});
|
|
74
76
|
}
|
|
75
77
|
return [];
|
|
76
|
-
},
|
|
78
|
+
},
|
|
79
|
+
invalidateItemData: ({ tree }, itemId) => {
|
|
77
80
|
var _a;
|
|
78
|
-
const dataRef =
|
|
81
|
+
const dataRef = tree.getDataRef();
|
|
79
82
|
(_a = dataRef.current.itemData) === null || _a === void 0 ? true : delete _a[itemId];
|
|
80
|
-
|
|
81
|
-
},
|
|
83
|
+
tree.retrieveItemData(itemId);
|
|
84
|
+
},
|
|
85
|
+
invalidateChildrenIds: ({ tree }, itemId) => {
|
|
82
86
|
var _a;
|
|
83
|
-
const dataRef =
|
|
87
|
+
const dataRef = tree.getDataRef();
|
|
84
88
|
(_a = dataRef.current.childrenIds) === null || _a === void 0 ? true : delete _a[itemId];
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
89
|
+
tree.retrieveChildrenIds(itemId);
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
itemInstance: {
|
|
93
|
+
isLoading: ({ tree, item }) => tree.getState().loadingItems.includes(item.getItemMeta().itemId),
|
|
94
|
+
invalidateItemData: ({ tree, item }) => tree.invalidateItemData(item.getItemMeta().itemId),
|
|
95
|
+
invalidateChildrenIds: ({ tree, item }) => tree.invalidateChildrenIds(item.getItemMeta().itemId),
|
|
96
|
+
updateCachedChildrenIds: ({ tree, itemId }, childrenIds) => {
|
|
97
|
+
const dataRef = tree.getDataRef();
|
|
98
|
+
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
99
|
+
tree.rebuildTree();
|
|
100
|
+
},
|
|
101
|
+
},
|
|
88
102
|
};
|
|
@@ -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
|
};
|
|
@@ -6,45 +6,64 @@ const utils_2 = require("../../utils");
|
|
|
6
6
|
exports.dragAndDropFeature = {
|
|
7
7
|
key: "dragAndDrop",
|
|
8
8
|
deps: ["selection"],
|
|
9
|
-
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: (0, utils_2.makeStateUpdater)("dnd", tree) }, defaultConfig)),
|
|
9
|
+
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: (0, utils_2.makeStateUpdater)("dnd", tree), canDropInbetween: true }, defaultConfig)),
|
|
10
10
|
stateHandlerNames: {
|
|
11
11
|
dnd: "setDndState",
|
|
12
12
|
},
|
|
13
|
-
|
|
13
|
+
treeInstance: {
|
|
14
|
+
getDropTarget: ({ tree }) => {
|
|
14
15
|
var _a, _b;
|
|
15
16
|
return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
|
|
16
|
-
},
|
|
17
|
+
},
|
|
18
|
+
getDragLineData: ({ tree }) => {
|
|
17
19
|
var _a, _b, _c, _d, _e;
|
|
20
|
+
// TODO doesnt work if scrolled down!
|
|
18
21
|
const target = tree.getDropTarget();
|
|
19
|
-
const
|
|
22
|
+
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
|
|
20
23
|
if (!target || target.childIndex === null)
|
|
21
24
|
return null;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const leftOffset = target.dragLineLevel * ((_b = tree.getConfig().indent) !== null && _b !== void 0 ? _b : 1);
|
|
26
|
+
const targetItem = tree.getItems()[target.dragLineIndex];
|
|
27
|
+
if (!targetItem) {
|
|
28
|
+
const bb = (_d = (_c = tree
|
|
29
|
+
.getItems()[target.dragLineIndex - 1]) === null || _c === void 0 ? void 0 : _c.getElement()) === null || _d === void 0 ? void 0 : _d.getBoundingClientRect();
|
|
25
30
|
if (bb) {
|
|
26
31
|
return {
|
|
27
|
-
|
|
32
|
+
indent,
|
|
28
33
|
top: bb.bottom,
|
|
29
|
-
left: bb.left,
|
|
34
|
+
left: bb.left + leftOffset,
|
|
30
35
|
right: bb.right,
|
|
31
36
|
};
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
|
-
const bb = (_e =
|
|
39
|
+
const bb = (_e = targetItem.getElement()) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();
|
|
35
40
|
if (bb) {
|
|
36
41
|
return {
|
|
37
|
-
|
|
42
|
+
indent,
|
|
38
43
|
top: bb.top,
|
|
39
|
-
left: bb.left,
|
|
44
|
+
left: bb.left + leftOffset,
|
|
40
45
|
right: bb.right,
|
|
41
46
|
};
|
|
42
47
|
}
|
|
43
48
|
return null;
|
|
44
|
-
}
|
|
45
|
-
|
|
49
|
+
},
|
|
50
|
+
getDragLineStyle: ({ tree }, topOffset = -1, leftOffset = -8) => {
|
|
51
|
+
const dragLine = tree.getDragLineData();
|
|
52
|
+
return dragLine
|
|
53
|
+
? {
|
|
54
|
+
top: `${dragLine.top + topOffset}px`,
|
|
55
|
+
left: `${dragLine.left + leftOffset}px`,
|
|
56
|
+
width: `${dragLine.right - dragLine.left - leftOffset}px`,
|
|
57
|
+
pointerEvents: "none", // important to prevent capturing drag events
|
|
58
|
+
}
|
|
59
|
+
: { display: "none" };
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
itemInstance: {
|
|
63
|
+
// TODO instead of individual getMemoizedProp calls, use a wrapped getMemoizedProps or something (getProps: () => getMemoized({...})
|
|
64
|
+
getProps: ({ tree, item, prev }) => {
|
|
46
65
|
var _a, _b, _c;
|
|
47
|
-
return (Object.assign(Object.assign({}, prev
|
|
66
|
+
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) => {
|
|
48
67
|
var _a, _b, _c;
|
|
49
68
|
const selectedItems = tree.getSelectedItems();
|
|
50
69
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
@@ -66,34 +85,42 @@ exports.dragAndDropFeature = {
|
|
|
66
85
|
});
|
|
67
86
|
}), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
|
|
68
87
|
var _a, _b, _c;
|
|
69
|
-
const target = (0, utils_1.getDropTarget)(e, item, tree);
|
|
70
88
|
const dataRef = tree.getDataRef();
|
|
71
|
-
|
|
72
|
-
|
|
89
|
+
const nextDragCode = (0, utils_1.getDragCode)(e, item, tree);
|
|
90
|
+
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
91
|
+
if (dataRef.current.lastAllowDrop) {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
}
|
|
73
94
|
return;
|
|
74
95
|
}
|
|
75
|
-
|
|
96
|
+
dataRef.current.lastDragCode = nextDragCode;
|
|
97
|
+
const target = (0, utils_1.getDropTarget)(e, item, tree);
|
|
98
|
+
if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
|
|
99
|
+
(!e.dataTransfer ||
|
|
100
|
+
!((_c = (_b = tree
|
|
101
|
+
.getConfig()).canDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
|
|
102
|
+
dataRef.current.lastAllowDrop = false;
|
|
76
103
|
return;
|
|
77
104
|
}
|
|
78
|
-
e.
|
|
79
|
-
|
|
80
|
-
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
105
|
+
if (!(0, utils_1.canDrop)(e.dataTransfer, target, tree)) {
|
|
106
|
+
dataRef.current.lastAllowDrop = false;
|
|
81
107
|
return;
|
|
82
108
|
}
|
|
83
|
-
dataRef.current.lastDragCode = nextDragCode;
|
|
84
109
|
tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
|
|
110
|
+
dataRef.current.lastAllowDrop = true;
|
|
111
|
+
e.preventDefault();
|
|
85
112
|
}), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
|
|
86
113
|
const dataRef = tree.getDataRef();
|
|
87
114
|
dataRef.current.lastDragCode = "no-drag";
|
|
88
115
|
tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
|
|
89
116
|
}), onDragEnd: item.getMemoizedProp("dnd/onDragEnd", () => (e) => {
|
|
90
|
-
var _a, _b, _c;
|
|
117
|
+
var _a, _b, _c, _d;
|
|
91
118
|
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
92
119
|
tree.applySubStateUpdate("dnd", null);
|
|
93
|
-
if (e.dataTransfer.dropEffect === "none" || !draggedItems) {
|
|
120
|
+
if (((_b = e.dataTransfer) === null || _b === void 0 ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
94
121
|
return;
|
|
95
122
|
}
|
|
96
|
-
(
|
|
123
|
+
(_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
|
|
97
124
|
}), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
|
|
98
125
|
var _a, _b, _c;
|
|
99
126
|
const dataRef = tree.getDataRef();
|
|
@@ -109,30 +136,35 @@ exports.dragAndDropFeature = {
|
|
|
109
136
|
if (draggedItems) {
|
|
110
137
|
(_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target);
|
|
111
138
|
}
|
|
112
|
-
else {
|
|
139
|
+
else if (e.dataTransfer) {
|
|
113
140
|
(_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target);
|
|
114
141
|
}
|
|
115
142
|
// TODO rebuild tree?
|
|
116
143
|
}) }));
|
|
117
|
-
},
|
|
144
|
+
},
|
|
145
|
+
isDropTarget: ({ tree, item }) => {
|
|
118
146
|
const target = tree.getDropTarget();
|
|
119
147
|
return target ? target.item.getId() === item.getId() : false;
|
|
120
|
-
},
|
|
148
|
+
},
|
|
149
|
+
isDropTargetAbove: ({ tree, item }) => {
|
|
121
150
|
const target = tree.getDropTarget();
|
|
122
151
|
if (!target ||
|
|
123
152
|
target.childIndex === null ||
|
|
124
153
|
target.item !== item.getParent())
|
|
125
154
|
return false;
|
|
126
155
|
return target.childIndex === item.getItemMeta().posInSet;
|
|
127
|
-
},
|
|
156
|
+
},
|
|
157
|
+
isDropTargetBelow: ({ tree, item }) => {
|
|
128
158
|
const target = tree.getDropTarget();
|
|
129
159
|
if (!target ||
|
|
130
160
|
target.childIndex === null ||
|
|
131
161
|
target.item !== item.getParent())
|
|
132
162
|
return false;
|
|
133
163
|
return target.childIndex - 1 === item.getItemMeta().posInSet;
|
|
134
|
-
},
|
|
164
|
+
},
|
|
165
|
+
isDraggingOver: ({ tree, item }) => {
|
|
135
166
|
var _a, _b;
|
|
136
167
|
return ((_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggingOverItem) === null || _b === void 0 ? void 0 : _b.getId()) === item.getId();
|
|
137
|
-
}
|
|
168
|
+
},
|
|
169
|
+
},
|
|
138
170
|
};
|
|
@@ -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>;
|