@headless-tree/core 0.0.6 → 0.0.7
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/create-tree.js +27 -6
- package/lib/cjs/features/async-data-loader/feature.js +0 -1
- package/lib/cjs/features/drag-and-drop/feature.js +29 -1
- package/lib/cjs/features/drag-and-drop/types.d.ts +7 -0
- package/lib/cjs/features/expand-all/feature.js +0 -1
- package/lib/cjs/features/hotkeys-core/feature.js +0 -1
- package/lib/cjs/features/renaming/feature.js +0 -2
- package/lib/cjs/features/search/feature.js +0 -1
- package/lib/cjs/features/selection/feature.js +1 -2
- package/lib/cjs/features/sync-data-loader/feature.js +0 -1
- package/lib/cjs/features/tree/feature.js +0 -1
- package/lib/cjs/types/core.d.ts +2 -1
- package/lib/esm/core/create-tree.js +27 -6
- package/lib/esm/features/async-data-loader/feature.js +0 -1
- package/lib/esm/features/drag-and-drop/feature.js +29 -1
- package/lib/esm/features/drag-and-drop/types.d.ts +7 -0
- package/lib/esm/features/expand-all/feature.js +0 -1
- package/lib/esm/features/hotkeys-core/feature.js +0 -1
- package/lib/esm/features/renaming/feature.js +0 -2
- package/lib/esm/features/search/feature.js +0 -1
- package/lib/esm/features/selection/feature.js +1 -2
- package/lib/esm/features/sync-data-loader/feature.js +0 -1
- package/lib/esm/features/tree/feature.js +0 -1
- package/lib/esm/types/core.d.ts +2 -1
- package/package.json +1 -1
- package/src/core/create-tree.ts +31 -2
- package/src/features/async-data-loader/feature.ts +0 -1
- package/src/features/drag-and-drop/feature.ts +41 -2
- package/src/features/drag-and-drop/types.ts +8 -0
- package/src/features/expand-all/feature.ts +0 -1
- package/src/features/hotkeys-core/feature.ts +0 -1
- package/src/features/renaming/feature.ts +0 -2
- package/src/features/search/feature.ts +0 -1
- package/src/features/selection/feature.ts +1 -2
- package/src/features/sync-data-loader/feature.ts +0 -1
- package/src/features/tree/feature.ts +0 -1
- package/src/types/core.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,11 +10,33 @@ const buildItemInstance = (features, tree, itemId) => {
|
|
|
10
10
|
}
|
|
11
11
|
return itemInstance;
|
|
12
12
|
};
|
|
13
|
+
const verifyFeatures = (features) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const loadedFeatures = features === null || features === void 0 ? void 0 : features.map((feature) => feature.key);
|
|
16
|
+
for (const feature of features !== null && features !== void 0 ? features : []) {
|
|
17
|
+
const missingDependency = (_a = feature.deps) === null || _a === void 0 ? void 0 : _a.find((dep) => !(loadedFeatures === null || loadedFeatures === void 0 ? void 0 : loadedFeatures.includes(dep)));
|
|
18
|
+
if (missingDependency) {
|
|
19
|
+
throw new Error(`${feature.key} needs ${missingDependency}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const compareFeatures = (feature1, feature2) => {
|
|
24
|
+
var _a;
|
|
25
|
+
if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
return -1;
|
|
29
|
+
};
|
|
30
|
+
const sortFeatures = (features = []) => features.sort(compareFeatures);
|
|
13
31
|
const createTree = (initialConfig) => {
|
|
14
|
-
var _a, _b, _c, _d, _e
|
|
32
|
+
var _a, _b, _c, _d, _e;
|
|
15
33
|
const treeInstance = {};
|
|
16
|
-
const additionalFeatures = [
|
|
17
|
-
|
|
34
|
+
const additionalFeatures = [
|
|
35
|
+
feature_1.treeFeature,
|
|
36
|
+
...sortFeatures(initialConfig.features),
|
|
37
|
+
];
|
|
38
|
+
verifyFeatures(additionalFeatures);
|
|
39
|
+
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; }, (_b = (_a = initialConfig.initialState) !== null && _a !== void 0 ? _a : initialConfig.state) !== null && _b !== void 0 ? _b : {});
|
|
18
40
|
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);
|
|
19
41
|
const stateHandlerNames = additionalFeatures.reduce((acc, feature) => (Object.assign(Object.assign({}, acc), feature.stateHandlerNames)), {});
|
|
20
42
|
let treeElement;
|
|
@@ -105,11 +127,10 @@ const createTree = (initialConfig) => {
|
|
|
105
127
|
// eslint-disable-next-line no-return-assign
|
|
106
128
|
getDataRef: () => { var _a; return ((_a = itemDataRefs[itemId]) !== null && _a !== void 0 ? _a : (itemDataRefs[itemId] = { current: {} })); }, getItemMeta: () => itemMetaMap[itemId] })),
|
|
107
129
|
};
|
|
108
|
-
// todo sort features
|
|
109
130
|
const features = [mainFeature, ...additionalFeatures];
|
|
110
131
|
for (const feature of features) {
|
|
111
|
-
Object.assign(treeInstance, (
|
|
112
|
-
Object.assign(hotkeyPresets, (
|
|
132
|
+
Object.assign(treeInstance, (_d = (_c = feature.createTreeInstance) === null || _c === void 0 ? void 0 : _c.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _d !== void 0 ? _d : {});
|
|
133
|
+
Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
|
|
113
134
|
}
|
|
114
135
|
rebuildItemMeta(mainFeature);
|
|
115
136
|
return treeInstance;
|
|
@@ -4,7 +4,6 @@ exports.asyncDataLoaderFeature = void 0;
|
|
|
4
4
|
const utils_1 = require("../../utils");
|
|
5
5
|
exports.asyncDataLoaderFeature = {
|
|
6
6
|
key: "async-data-loader",
|
|
7
|
-
dependingFeatures: ["main"],
|
|
8
7
|
getInitialState: (initialState) => (Object.assign({ loadingItems: [] }, initialState)),
|
|
9
8
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItems: (0, utils_1.makeStateUpdater)("loadingItems", tree) }, defaultConfig)),
|
|
10
9
|
stateHandlerNames: {
|
|
@@ -5,7 +5,7 @@ const utils_1 = require("./utils");
|
|
|
5
5
|
const utils_2 = require("../../utils");
|
|
6
6
|
exports.dragAndDropFeature = {
|
|
7
7
|
key: "dragAndDrop",
|
|
8
|
-
|
|
8
|
+
deps: ["selection"],
|
|
9
9
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: (0, utils_2.makeStateUpdater)("dnd", tree) }, defaultConfig)),
|
|
10
10
|
stateHandlerNames: {
|
|
11
11
|
dnd: "setDndState",
|
|
@@ -13,6 +13,34 @@ exports.dragAndDropFeature = {
|
|
|
13
13
|
createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { getDropTarget: () => {
|
|
14
14
|
var _a, _b;
|
|
15
15
|
return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
|
|
16
|
+
}, getDragLineData: () => {
|
|
17
|
+
var _a, _b, _c, _d, _e;
|
|
18
|
+
const target = tree.getDropTarget();
|
|
19
|
+
const intend = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
20
|
+
if (!target || target.childIndex === null)
|
|
21
|
+
return null;
|
|
22
|
+
const children = target.item.getChildren();
|
|
23
|
+
if (target.childIndex === children.length) {
|
|
24
|
+
const bb = (_c = (_b = children[target.childIndex - 1]) === null || _b === void 0 ? void 0 : _b.getElement()) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect();
|
|
25
|
+
if (bb) {
|
|
26
|
+
return {
|
|
27
|
+
intend,
|
|
28
|
+
top: bb.bottom,
|
|
29
|
+
left: bb.left,
|
|
30
|
+
right: bb.right,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const bb = (_e = (_d = children[target.childIndex]) === null || _d === void 0 ? void 0 : _d.getElement()) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();
|
|
35
|
+
if (bb) {
|
|
36
|
+
return {
|
|
37
|
+
intend,
|
|
38
|
+
top: bb.top,
|
|
39
|
+
left: bb.left,
|
|
40
|
+
right: bb.right,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
16
44
|
} })),
|
|
17
45
|
createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { getProps: () => {
|
|
18
46
|
var _a, _b, _c;
|
|
@@ -7,6 +7,12 @@ export type DndState<T> = {
|
|
|
7
7
|
draggingOverItem?: ItemInstance<T>;
|
|
8
8
|
dragTarget?: DropTarget<T>;
|
|
9
9
|
};
|
|
10
|
+
export type DragLineData = {
|
|
11
|
+
intend: number;
|
|
12
|
+
top: number;
|
|
13
|
+
left: number;
|
|
14
|
+
right: number;
|
|
15
|
+
};
|
|
10
16
|
export type DropTarget<T> = {
|
|
11
17
|
item: ItemInstance<T>;
|
|
12
18
|
childIndex: number;
|
|
@@ -51,6 +57,7 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
51
57
|
};
|
|
52
58
|
treeInstance: {
|
|
53
59
|
getDropTarget: () => DropTarget<T> | null;
|
|
60
|
+
getDragLineData: () => DragLineData | null;
|
|
54
61
|
};
|
|
55
62
|
itemInstance: {
|
|
56
63
|
isDropTarget: () => boolean;
|
|
@@ -13,7 +13,6 @@ exports.expandAllFeature = void 0;
|
|
|
13
13
|
const utils_1 = require("../../utils");
|
|
14
14
|
exports.expandAllFeature = {
|
|
15
15
|
key: "expand-all",
|
|
16
|
-
dependingFeatures: ["main", "tree"],
|
|
17
16
|
createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { expandAll: (cancelToken) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
17
|
yield Promise.all(tree.getItems().map((item) => item.expandAll(cancelToken)));
|
|
19
18
|
}), collapseAll: () => {
|
|
@@ -20,7 +20,6 @@ const findHotkeyMatch = (pressedKeys, tree, config1, config2) => {
|
|
|
20
20
|
};
|
|
21
21
|
exports.hotkeysCoreFeature = {
|
|
22
22
|
key: "hotkeys-core",
|
|
23
|
-
dependingFeatures: ["main", "tree"],
|
|
24
23
|
onTreeMount: (tree, element) => {
|
|
25
24
|
const data = tree.getDataRef();
|
|
26
25
|
const keydown = (e) => {
|
|
@@ -4,14 +4,12 @@ exports.renamingFeature = void 0;
|
|
|
4
4
|
const utils_1 = require("../../utils");
|
|
5
5
|
exports.renamingFeature = {
|
|
6
6
|
key: "renaming",
|
|
7
|
-
dependingFeatures: ["main", "tree"],
|
|
8
7
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setRenamingItem: (0, utils_1.makeStateUpdater)("renamingItem", tree), setRenamingValue: (0, utils_1.makeStateUpdater)("renamingValue", tree), canRename: () => true }, defaultConfig)),
|
|
9
8
|
stateHandlerNames: {
|
|
10
9
|
renamingItem: "setRenamingItem",
|
|
11
10
|
renamingValue: "setRenamingValue",
|
|
12
11
|
},
|
|
13
12
|
createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { startRenamingItem: (itemId) => {
|
|
14
|
-
const config = instance.getConfig();
|
|
15
13
|
const item = instance.getItemInstance(itemId);
|
|
16
14
|
if (!item.canRename()) {
|
|
17
15
|
return;
|
|
@@ -4,7 +4,6 @@ exports.searchFeature = void 0;
|
|
|
4
4
|
const utils_1 = require("../../utils");
|
|
5
5
|
exports.searchFeature = {
|
|
6
6
|
key: "search",
|
|
7
|
-
dependingFeatures: ["main", "tree"],
|
|
8
7
|
getInitialState: (initialState) => (Object.assign({ search: null }, initialState)),
|
|
9
8
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setSearch: (0, utils_1.makeStateUpdater)("search", tree), isSearchMatchingItem: (search, item) => search.length > 0 &&
|
|
10
9
|
item.getItemName().toLowerCase().includes(search.toLowerCase()) }, defaultConfig)),
|
|
@@ -4,7 +4,6 @@ exports.selectionFeature = void 0;
|
|
|
4
4
|
const utils_1 = require("../../utils");
|
|
5
5
|
exports.selectionFeature = {
|
|
6
6
|
key: "selection",
|
|
7
|
-
dependingFeatures: ["main", "tree"],
|
|
8
7
|
getInitialState: (initialState) => (Object.assign({ selectedItems: [] }, initialState)),
|
|
9
8
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setSelectedItems: (0, utils_1.makeStateUpdater)("selectedItems", tree) }, defaultConfig)),
|
|
10
9
|
stateHandlerNames: {
|
|
@@ -36,7 +35,7 @@ exports.selectionFeature = {
|
|
|
36
35
|
const newSelectedItems = tree
|
|
37
36
|
.getItems()
|
|
38
37
|
.slice(a, b + 1)
|
|
39
|
-
.map((
|
|
38
|
+
.map((treeItem) => treeItem.getItemMeta().itemId);
|
|
40
39
|
if (!ctrl) {
|
|
41
40
|
tree.setSelectedItems(newSelectedItems);
|
|
42
41
|
return;
|
|
@@ -4,7 +4,6 @@ exports.syncDataLoaderFeature = void 0;
|
|
|
4
4
|
const utils_1 = require("../../utils");
|
|
5
5
|
exports.syncDataLoaderFeature = {
|
|
6
6
|
key: "sync-data-loader",
|
|
7
|
-
dependingFeatures: ["main"],
|
|
8
7
|
getInitialState: (initialState) => (Object.assign({ loadingItems: [] }, initialState)),
|
|
9
8
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItems: (0, utils_1.makeStateUpdater)("loadingItems", tree) }, defaultConfig)),
|
|
10
9
|
stateHandlerNames: {
|
|
@@ -13,7 +13,6 @@ exports.treeFeature = void 0;
|
|
|
13
13
|
const utils_1 = require("../../utils");
|
|
14
14
|
exports.treeFeature = {
|
|
15
15
|
key: "tree",
|
|
16
|
-
dependingFeatures: ["main"],
|
|
17
16
|
getInitialState: (initialState) => (Object.assign({ expandedItems: [], focusedItem: null }, initialState)),
|
|
18
17
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setExpandedItems: (0, utils_1.makeStateUpdater)("expandedItems", tree), setFocusedItem: (0, utils_1.makeStateUpdater)("focusedItem", tree) }, defaultConfig)),
|
|
19
18
|
stateHandlerNames: {
|
package/lib/cjs/types/core.d.ts
CHANGED
|
@@ -51,7 +51,8 @@ export type HotkeysConfig<T, F extends FeatureDef = FeatureDefs<T>> = Record<Hot
|
|
|
51
51
|
export type CustomHotkeysConfig<T, F extends FeatureDef = FeatureDefs<T>> = Partial<Record<HotkeyName<F> | `custom${string}`, Partial<HotkeyConfig<T>>>>;
|
|
52
52
|
export type FeatureImplementation<T = any, D extends FeatureDef = any, F extends FeatureDef = EmptyFeatureDef> = {
|
|
53
53
|
key?: string;
|
|
54
|
-
|
|
54
|
+
deps?: string[];
|
|
55
|
+
overwrites?: string[];
|
|
55
56
|
stateHandlerNames?: Partial<Record<keyof MergedFeatures<F>["state"], keyof MergedFeatures<F>["config"]>>;
|
|
56
57
|
getInitialState?: (initialState: Partial<MergedFeatures<F>["state"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["state"] & MergedFeatures<F>["state"]>;
|
|
57
58
|
getDefaultConfig?: (defaultConfig: Partial<MergedFeatures<F>["config"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["config"] & MergedFeatures<F>["config"]>;
|
|
@@ -7,11 +7,33 @@ const buildItemInstance = (features, tree, itemId) => {
|
|
|
7
7
|
}
|
|
8
8
|
return itemInstance;
|
|
9
9
|
};
|
|
10
|
+
const verifyFeatures = (features) => {
|
|
11
|
+
var _a;
|
|
12
|
+
const loadedFeatures = features === null || features === void 0 ? void 0 : features.map((feature) => feature.key);
|
|
13
|
+
for (const feature of features !== null && features !== void 0 ? features : []) {
|
|
14
|
+
const missingDependency = (_a = feature.deps) === null || _a === void 0 ? void 0 : _a.find((dep) => !(loadedFeatures === null || loadedFeatures === void 0 ? void 0 : loadedFeatures.includes(dep)));
|
|
15
|
+
if (missingDependency) {
|
|
16
|
+
throw new Error(`${feature.key} needs ${missingDependency}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const compareFeatures = (feature1, feature2) => {
|
|
21
|
+
var _a;
|
|
22
|
+
if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
return -1;
|
|
26
|
+
};
|
|
27
|
+
const sortFeatures = (features = []) => features.sort(compareFeatures);
|
|
10
28
|
export const createTree = (initialConfig) => {
|
|
11
|
-
var _a, _b, _c, _d, _e
|
|
29
|
+
var _a, _b, _c, _d, _e;
|
|
12
30
|
const treeInstance = {};
|
|
13
|
-
const additionalFeatures = [
|
|
14
|
-
|
|
31
|
+
const additionalFeatures = [
|
|
32
|
+
treeFeature,
|
|
33
|
+
...sortFeatures(initialConfig.features),
|
|
34
|
+
];
|
|
35
|
+
verifyFeatures(additionalFeatures);
|
|
36
|
+
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; }, (_b = (_a = initialConfig.initialState) !== null && _a !== void 0 ? _a : initialConfig.state) !== null && _b !== void 0 ? _b : {});
|
|
15
37
|
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);
|
|
16
38
|
const stateHandlerNames = additionalFeatures.reduce((acc, feature) => (Object.assign(Object.assign({}, acc), feature.stateHandlerNames)), {});
|
|
17
39
|
let treeElement;
|
|
@@ -102,11 +124,10 @@ export const createTree = (initialConfig) => {
|
|
|
102
124
|
// eslint-disable-next-line no-return-assign
|
|
103
125
|
getDataRef: () => { var _a; return ((_a = itemDataRefs[itemId]) !== null && _a !== void 0 ? _a : (itemDataRefs[itemId] = { current: {} })); }, getItemMeta: () => itemMetaMap[itemId] })),
|
|
104
126
|
};
|
|
105
|
-
// todo sort features
|
|
106
127
|
const features = [mainFeature, ...additionalFeatures];
|
|
107
128
|
for (const feature of features) {
|
|
108
|
-
Object.assign(treeInstance, (
|
|
109
|
-
Object.assign(hotkeyPresets, (
|
|
129
|
+
Object.assign(treeInstance, (_d = (_c = feature.createTreeInstance) === null || _c === void 0 ? void 0 : _c.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _d !== void 0 ? _d : {});
|
|
130
|
+
Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
|
|
110
131
|
}
|
|
111
132
|
rebuildItemMeta(mainFeature);
|
|
112
133
|
return treeInstance;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { makeStateUpdater } from "../../utils";
|
|
2
2
|
export const asyncDataLoaderFeature = {
|
|
3
3
|
key: "async-data-loader",
|
|
4
|
-
dependingFeatures: ["main"],
|
|
5
4
|
getInitialState: (initialState) => (Object.assign({ loadingItems: [] }, initialState)),
|
|
6
5
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItems: makeStateUpdater("loadingItems", tree) }, defaultConfig)),
|
|
7
6
|
stateHandlerNames: {
|
|
@@ -2,7 +2,7 @@ import { canDrop, getDragCode, getDropTarget } from "./utils";
|
|
|
2
2
|
import { makeStateUpdater } from "../../utils";
|
|
3
3
|
export const dragAndDropFeature = {
|
|
4
4
|
key: "dragAndDrop",
|
|
5
|
-
|
|
5
|
+
deps: ["selection"],
|
|
6
6
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: makeStateUpdater("dnd", tree) }, defaultConfig)),
|
|
7
7
|
stateHandlerNames: {
|
|
8
8
|
dnd: "setDndState",
|
|
@@ -10,6 +10,34 @@ export const dragAndDropFeature = {
|
|
|
10
10
|
createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { getDropTarget: () => {
|
|
11
11
|
var _a, _b;
|
|
12
12
|
return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
|
|
13
|
+
}, getDragLineData: () => {
|
|
14
|
+
var _a, _b, _c, _d, _e;
|
|
15
|
+
const target = tree.getDropTarget();
|
|
16
|
+
const intend = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
17
|
+
if (!target || target.childIndex === null)
|
|
18
|
+
return null;
|
|
19
|
+
const children = target.item.getChildren();
|
|
20
|
+
if (target.childIndex === children.length) {
|
|
21
|
+
const bb = (_c = (_b = children[target.childIndex - 1]) === null || _b === void 0 ? void 0 : _b.getElement()) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect();
|
|
22
|
+
if (bb) {
|
|
23
|
+
return {
|
|
24
|
+
intend,
|
|
25
|
+
top: bb.bottom,
|
|
26
|
+
left: bb.left,
|
|
27
|
+
right: bb.right,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const bb = (_e = (_d = children[target.childIndex]) === null || _d === void 0 ? void 0 : _d.getElement()) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();
|
|
32
|
+
if (bb) {
|
|
33
|
+
return {
|
|
34
|
+
intend,
|
|
35
|
+
top: bb.top,
|
|
36
|
+
left: bb.left,
|
|
37
|
+
right: bb.right,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
13
41
|
} })),
|
|
14
42
|
createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { getProps: () => {
|
|
15
43
|
var _a, _b, _c;
|
|
@@ -7,6 +7,12 @@ export type DndState<T> = {
|
|
|
7
7
|
draggingOverItem?: ItemInstance<T>;
|
|
8
8
|
dragTarget?: DropTarget<T>;
|
|
9
9
|
};
|
|
10
|
+
export type DragLineData = {
|
|
11
|
+
intend: number;
|
|
12
|
+
top: number;
|
|
13
|
+
left: number;
|
|
14
|
+
right: number;
|
|
15
|
+
};
|
|
10
16
|
export type DropTarget<T> = {
|
|
11
17
|
item: ItemInstance<T>;
|
|
12
18
|
childIndex: number;
|
|
@@ -51,6 +57,7 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
51
57
|
};
|
|
52
58
|
treeInstance: {
|
|
53
59
|
getDropTarget: () => DropTarget<T> | null;
|
|
60
|
+
getDragLineData: () => DragLineData | null;
|
|
54
61
|
};
|
|
55
62
|
itemInstance: {
|
|
56
63
|
isDropTarget: () => boolean;
|
|
@@ -10,7 +10,6 @@ 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
|
-
dependingFeatures: ["main", "tree"],
|
|
14
13
|
createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { expandAll: (cancelToken) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
14
|
yield Promise.all(tree.getItems().map((item) => item.expandAll(cancelToken)));
|
|
16
15
|
}), collapseAll: () => {
|
|
@@ -17,7 +17,6 @@ const findHotkeyMatch = (pressedKeys, tree, config1, config2) => {
|
|
|
17
17
|
};
|
|
18
18
|
export const hotkeysCoreFeature = {
|
|
19
19
|
key: "hotkeys-core",
|
|
20
|
-
dependingFeatures: ["main", "tree"],
|
|
21
20
|
onTreeMount: (tree, element) => {
|
|
22
21
|
const data = tree.getDataRef();
|
|
23
22
|
const keydown = (e) => {
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { makeStateUpdater } from "../../utils";
|
|
2
2
|
export const renamingFeature = {
|
|
3
3
|
key: "renaming",
|
|
4
|
-
dependingFeatures: ["main", "tree"],
|
|
5
4
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setRenamingItem: makeStateUpdater("renamingItem", tree), setRenamingValue: makeStateUpdater("renamingValue", tree), canRename: () => true }, defaultConfig)),
|
|
6
5
|
stateHandlerNames: {
|
|
7
6
|
renamingItem: "setRenamingItem",
|
|
8
7
|
renamingValue: "setRenamingValue",
|
|
9
8
|
},
|
|
10
9
|
createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { startRenamingItem: (itemId) => {
|
|
11
|
-
const config = instance.getConfig();
|
|
12
10
|
const item = instance.getItemInstance(itemId);
|
|
13
11
|
if (!item.canRename()) {
|
|
14
12
|
return;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { makeStateUpdater, memo } from "../../utils";
|
|
2
2
|
export const searchFeature = {
|
|
3
3
|
key: "search",
|
|
4
|
-
dependingFeatures: ["main", "tree"],
|
|
5
4
|
getInitialState: (initialState) => (Object.assign({ search: null }, initialState)),
|
|
6
5
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setSearch: makeStateUpdater("search", tree), isSearchMatchingItem: (search, item) => search.length > 0 &&
|
|
7
6
|
item.getItemName().toLowerCase().includes(search.toLowerCase()) }, defaultConfig)),
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { makeStateUpdater } from "../../utils";
|
|
2
2
|
export const selectionFeature = {
|
|
3
3
|
key: "selection",
|
|
4
|
-
dependingFeatures: ["main", "tree"],
|
|
5
4
|
getInitialState: (initialState) => (Object.assign({ selectedItems: [] }, initialState)),
|
|
6
5
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setSelectedItems: makeStateUpdater("selectedItems", tree) }, defaultConfig)),
|
|
7
6
|
stateHandlerNames: {
|
|
@@ -33,7 +32,7 @@ export const selectionFeature = {
|
|
|
33
32
|
const newSelectedItems = tree
|
|
34
33
|
.getItems()
|
|
35
34
|
.slice(a, b + 1)
|
|
36
|
-
.map((
|
|
35
|
+
.map((treeItem) => treeItem.getItemMeta().itemId);
|
|
37
36
|
if (!ctrl) {
|
|
38
37
|
tree.setSelectedItems(newSelectedItems);
|
|
39
38
|
return;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { makeStateUpdater } from "../../utils";
|
|
2
2
|
export const syncDataLoaderFeature = {
|
|
3
3
|
key: "sync-data-loader",
|
|
4
|
-
dependingFeatures: ["main"],
|
|
5
4
|
getInitialState: (initialState) => (Object.assign({ loadingItems: [] }, initialState)),
|
|
6
5
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItems: makeStateUpdater("loadingItems", tree) }, defaultConfig)),
|
|
7
6
|
stateHandlerNames: {
|
|
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { makeStateUpdater, memo, poll } from "../../utils";
|
|
11
11
|
export const treeFeature = {
|
|
12
12
|
key: "tree",
|
|
13
|
-
dependingFeatures: ["main"],
|
|
14
13
|
getInitialState: (initialState) => (Object.assign({ expandedItems: [], focusedItem: null }, initialState)),
|
|
15
14
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setExpandedItems: makeStateUpdater("expandedItems", tree), setFocusedItem: makeStateUpdater("focusedItem", tree) }, defaultConfig)),
|
|
16
15
|
stateHandlerNames: {
|
package/lib/esm/types/core.d.ts
CHANGED
|
@@ -51,7 +51,8 @@ export type HotkeysConfig<T, F extends FeatureDef = FeatureDefs<T>> = Record<Hot
|
|
|
51
51
|
export type CustomHotkeysConfig<T, F extends FeatureDef = FeatureDefs<T>> = Partial<Record<HotkeyName<F> | `custom${string}`, Partial<HotkeyConfig<T>>>>;
|
|
52
52
|
export type FeatureImplementation<T = any, D extends FeatureDef = any, F extends FeatureDef = EmptyFeatureDef> = {
|
|
53
53
|
key?: string;
|
|
54
|
-
|
|
54
|
+
deps?: string[];
|
|
55
|
+
overwrites?: string[];
|
|
55
56
|
stateHandlerNames?: Partial<Record<keyof MergedFeatures<F>["state"], keyof MergedFeatures<F>["config"]>>;
|
|
56
57
|
getInitialState?: (initialState: Partial<MergedFeatures<F>["state"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["state"] & MergedFeatures<F>["state"]>;
|
|
57
58
|
getDefaultConfig?: (defaultConfig: Partial<MergedFeatures<F>["config"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["config"] & MergedFeatures<F>["config"]>;
|
package/package.json
CHANGED
package/src/core/create-tree.ts
CHANGED
|
@@ -30,12 +30,42 @@ const buildItemInstance = (
|
|
|
30
30
|
return itemInstance;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
const verifyFeatures = (features: FeatureImplementation[] | undefined) => {
|
|
34
|
+
const loadedFeatures = features?.map((feature) => feature.key);
|
|
35
|
+
for (const feature of features ?? []) {
|
|
36
|
+
const missingDependency = feature.deps?.find(
|
|
37
|
+
(dep) => !loadedFeatures?.includes(dep)
|
|
38
|
+
);
|
|
39
|
+
if (missingDependency) {
|
|
40
|
+
throw new Error(`${feature.key} needs ${missingDependency}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const compareFeatures = (
|
|
46
|
+
feature1: FeatureImplementation,
|
|
47
|
+
feature2: FeatureImplementation
|
|
48
|
+
) => {
|
|
49
|
+
if (feature2.key && feature1.overwrites?.includes(feature2.key)) {
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
return -1;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const sortFeatures = (features: FeatureImplementation[] = []) =>
|
|
56
|
+
features.sort(compareFeatures);
|
|
57
|
+
|
|
33
58
|
export const createTree = <T>(
|
|
34
59
|
initialConfig: TreeConfig<T>
|
|
35
60
|
): TreeInstance<T> => {
|
|
36
61
|
const treeInstance: TreeInstance<T> = {} as any;
|
|
37
62
|
|
|
38
|
-
const additionalFeatures = [
|
|
63
|
+
const additionalFeatures = [
|
|
64
|
+
treeFeature,
|
|
65
|
+
...sortFeatures(initialConfig.features),
|
|
66
|
+
];
|
|
67
|
+
verifyFeatures(additionalFeatures);
|
|
68
|
+
|
|
39
69
|
let state = additionalFeatures.reduce(
|
|
40
70
|
(acc, feature) => feature.getInitialState?.(acc, treeInstance) ?? acc,
|
|
41
71
|
initialConfig.initialState ?? initialConfig.state ?? {}
|
|
@@ -182,7 +212,6 @@ export const createTree = <T>(
|
|
|
182
212
|
}),
|
|
183
213
|
};
|
|
184
214
|
|
|
185
|
-
// todo sort features
|
|
186
215
|
const features = [mainFeature, ...additionalFeatures];
|
|
187
216
|
|
|
188
217
|
for (const feature of features) {
|
|
@@ -10,7 +10,6 @@ export const asyncDataLoaderFeature: FeatureImplementation<
|
|
|
10
10
|
MainFeatureDef | TreeFeatureDef<any> | AsyncDataLoaderFeatureDef<any>
|
|
11
11
|
> = {
|
|
12
12
|
key: "async-data-loader",
|
|
13
|
-
dependingFeatures: ["main"],
|
|
14
13
|
|
|
15
14
|
getInitialState: (initialState) => ({
|
|
16
15
|
loadingItems: [],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FeatureDefs, FeatureImplementation } from "../../types/core";
|
|
2
|
-
import { DndDataRef, DragAndDropFeatureDef } from "./types";
|
|
2
|
+
import { DndDataRef, DragAndDropFeatureDef, DragLineData } from "./types";
|
|
3
3
|
import { canDrop, getDragCode, getDropTarget } from "./utils";
|
|
4
4
|
import { makeStateUpdater } from "../../utils";
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ export const dragAndDropFeature: FeatureImplementation<
|
|
|
9
9
|
FeatureDefs<any>
|
|
10
10
|
> = {
|
|
11
11
|
key: "dragAndDrop",
|
|
12
|
-
|
|
12
|
+
deps: ["selection"],
|
|
13
13
|
|
|
14
14
|
getDefaultConfig: (defaultConfig, tree) => ({
|
|
15
15
|
canDrop: (_, target) => target.item.isFolder(),
|
|
@@ -28,6 +28,45 @@ export const dragAndDropFeature: FeatureImplementation<
|
|
|
28
28
|
getDropTarget: () => {
|
|
29
29
|
return tree.getState().dnd?.dragTarget ?? null;
|
|
30
30
|
},
|
|
31
|
+
|
|
32
|
+
getDragLineData: (): DragLineData | null => {
|
|
33
|
+
const target = tree.getDropTarget();
|
|
34
|
+
const intend = (target?.item.getItemMeta().level ?? 0) + 1;
|
|
35
|
+
|
|
36
|
+
if (!target || target.childIndex === null) return null;
|
|
37
|
+
|
|
38
|
+
const children = target.item.getChildren();
|
|
39
|
+
|
|
40
|
+
if (target.childIndex === children.length) {
|
|
41
|
+
const bb = children[target.childIndex - 1]
|
|
42
|
+
?.getElement()
|
|
43
|
+
?.getBoundingClientRect();
|
|
44
|
+
|
|
45
|
+
if (bb) {
|
|
46
|
+
return {
|
|
47
|
+
intend,
|
|
48
|
+
top: bb.bottom,
|
|
49
|
+
left: bb.left,
|
|
50
|
+
right: bb.right,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const bb = children[target.childIndex]
|
|
56
|
+
?.getElement()
|
|
57
|
+
?.getBoundingClientRect();
|
|
58
|
+
|
|
59
|
+
if (bb) {
|
|
60
|
+
return {
|
|
61
|
+
intend,
|
|
62
|
+
top: bb.top,
|
|
63
|
+
left: bb.left,
|
|
64
|
+
right: bb.right,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null;
|
|
69
|
+
},
|
|
31
70
|
}),
|
|
32
71
|
|
|
33
72
|
createItemInstance: (prev, item, tree) => ({
|
|
@@ -10,6 +10,13 @@ export type DndState<T> = {
|
|
|
10
10
|
dragTarget?: DropTarget<T>;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
export type DragLineData = {
|
|
14
|
+
intend: number;
|
|
15
|
+
top: number;
|
|
16
|
+
left: number;
|
|
17
|
+
right: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
13
20
|
export type DropTarget<T> =
|
|
14
21
|
| {
|
|
15
22
|
item: ItemInstance<T>;
|
|
@@ -70,6 +77,7 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
70
77
|
};
|
|
71
78
|
treeInstance: {
|
|
72
79
|
getDropTarget: () => DropTarget<T> | null;
|
|
80
|
+
getDragLineData: () => DragLineData | null;
|
|
73
81
|
};
|
|
74
82
|
itemInstance: {
|
|
75
83
|
isDropTarget: () => boolean;
|
|
@@ -48,7 +48,6 @@ export const hotkeysCoreFeature: FeatureImplementation<
|
|
|
48
48
|
MainFeatureDef | HotkeysCoreFeatureDef<any>
|
|
49
49
|
> = {
|
|
50
50
|
key: "hotkeys-core",
|
|
51
|
-
dependingFeatures: ["main", "tree"],
|
|
52
51
|
|
|
53
52
|
onTreeMount: (tree, element) => {
|
|
54
53
|
const data = tree.getDataRef<HotkeysCoreDataRef>();
|
|
@@ -10,7 +10,6 @@ export const renamingFeature: FeatureImplementation<
|
|
|
10
10
|
MainFeatureDef | TreeFeatureDef<any> | RenamingFeatureDef<any>
|
|
11
11
|
> = {
|
|
12
12
|
key: "renaming",
|
|
13
|
-
dependingFeatures: ["main", "tree"],
|
|
14
13
|
|
|
15
14
|
getDefaultConfig: (defaultConfig, tree) => ({
|
|
16
15
|
setRenamingItem: makeStateUpdater("renamingItem", tree),
|
|
@@ -28,7 +27,6 @@ export const renamingFeature: FeatureImplementation<
|
|
|
28
27
|
...prev,
|
|
29
28
|
|
|
30
29
|
startRenamingItem: (itemId) => {
|
|
31
|
-
const config = instance.getConfig();
|
|
32
30
|
const item = instance.getItemInstance(itemId);
|
|
33
31
|
|
|
34
32
|
if (!item.canRename()) {
|
|
@@ -10,7 +10,6 @@ export const selectionFeature: FeatureImplementation<
|
|
|
10
10
|
MainFeatureDef | TreeFeatureDef<any> | SelectionFeatureDef<any>
|
|
11
11
|
> = {
|
|
12
12
|
key: "selection",
|
|
13
|
-
dependingFeatures: ["main", "tree"],
|
|
14
13
|
|
|
15
14
|
getInitialState: (initialState) => ({
|
|
16
15
|
selectedItems: [],
|
|
@@ -71,7 +70,7 @@ export const selectionFeature: FeatureImplementation<
|
|
|
71
70
|
const newSelectedItems = tree
|
|
72
71
|
.getItems()
|
|
73
72
|
.slice(a, b + 1)
|
|
74
|
-
.map((
|
|
73
|
+
.map((treeItem) => treeItem.getItemMeta().itemId);
|
|
75
74
|
|
|
76
75
|
if (!ctrl) {
|
|
77
76
|
tree.setSelectedItems(newSelectedItems);
|
package/src/types/core.ts
CHANGED
|
@@ -128,7 +128,8 @@ export type FeatureImplementation<
|
|
|
128
128
|
F extends FeatureDef = EmptyFeatureDef
|
|
129
129
|
> = {
|
|
130
130
|
key?: string;
|
|
131
|
-
|
|
131
|
+
deps?: string[];
|
|
132
|
+
overwrites?: string[];
|
|
132
133
|
|
|
133
134
|
stateHandlerNames?: Partial<
|
|
134
135
|
Record<keyof MergedFeatures<F>["state"], keyof MergedFeatures<F>["config"]>
|