@headless-tree/core 1.1.0 → 1.2.1
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 +28 -0
- package/lib/cjs/core/create-tree.js +22 -2
- package/lib/cjs/features/async-data-loader/feature.js +4 -4
- package/lib/cjs/features/checkboxes/feature.d.ts +2 -0
- package/lib/cjs/features/checkboxes/feature.js +94 -0
- package/lib/cjs/features/checkboxes/types.d.ts +26 -0
- package/lib/cjs/features/checkboxes/types.js +9 -0
- package/lib/cjs/features/drag-and-drop/feature.js +31 -5
- package/lib/cjs/features/drag-and-drop/types.d.ts +5 -0
- package/lib/cjs/features/main/types.d.ts +2 -0
- package/lib/cjs/features/renaming/feature.js +8 -0
- package/lib/cjs/features/tree/feature.js +5 -0
- package/lib/cjs/features/tree/types.d.ts +3 -1
- package/lib/cjs/index.d.ts +4 -0
- package/lib/cjs/index.js +7 -0
- package/lib/cjs/test-utils/test-tree.js +1 -0
- package/lib/cjs/types/core.d.ts +2 -1
- package/lib/esm/core/create-tree.js +22 -2
- package/lib/esm/features/async-data-loader/feature.js +4 -4
- package/lib/esm/features/checkboxes/feature.d.ts +2 -0
- package/lib/esm/features/checkboxes/feature.js +91 -0
- package/lib/esm/features/checkboxes/types.d.ts +26 -0
- package/lib/esm/features/checkboxes/types.js +6 -0
- package/lib/esm/features/drag-and-drop/feature.js +31 -5
- package/lib/esm/features/drag-and-drop/types.d.ts +5 -0
- package/lib/esm/features/main/types.d.ts +2 -0
- package/lib/esm/features/renaming/feature.js +8 -0
- package/lib/esm/features/tree/feature.js +5 -0
- package/lib/esm/features/tree/types.d.ts +3 -1
- package/lib/esm/index.d.ts +4 -0
- package/lib/esm/index.js +4 -0
- package/lib/esm/test-utils/test-tree.js +1 -0
- package/lib/esm/types/core.d.ts +2 -1
- package/package.json +7 -2
- package/readme.md +157 -0
- package/src/core/create-tree.ts +33 -2
- package/src/features/async-data-loader/feature.ts +4 -4
- package/src/features/checkboxes/checkboxes.spec.ts +134 -0
- package/src/features/checkboxes/feature.ts +119 -0
- package/src/features/checkboxes/types.ts +28 -0
- package/src/features/drag-and-drop/feature.ts +38 -2
- package/src/features/drag-and-drop/types.ts +5 -0
- package/src/features/main/types.ts +2 -0
- package/src/features/renaming/feature.ts +13 -0
- package/src/features/renaming/renaming.spec.ts +31 -0
- package/src/features/tree/feature.ts +6 -0
- package/src/features/tree/types.ts +4 -2
- package/src/index.ts +5 -0
- package/src/test-utils/test-tree.ts +1 -0
- package/src/types/core.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 344011a: fixed an issue where dropping items on an empty tree didn't trigger any events
|
|
8
|
+
- 9f418f8: support setting the drag preview with the `setDragImage` option (#115)
|
|
9
|
+
- 309feba: fixed an issue where the drag-forbidden cursor is shown briefly between changing drag targets (#114)
|
|
10
|
+
|
|
11
|
+
## 1.2.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- 647a072: Fixed incorrect package.json exports configurations to proper ESM and CJS exports (#104)
|
|
16
|
+
- 349d36e: change package.json["module"] to commonjs to fix inconsistent package definitiuons (#104)
|
|
17
|
+
- e2faf37: Fixed an issue async data loaders that resolve data before the tree is mounted can cause the tree to not render at all
|
|
18
|
+
|
|
19
|
+
Note: When using the `createTree()` API directly instead of going through the React `useTree` API, an additional call
|
|
20
|
+
to `tree.rebuildItems()` afterwards will be necessary. This change is marked as minor release regardless, since `createTree` is
|
|
21
|
+
currently not a publically documented feature.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 727c982: export makeStateUpdater from core package
|
|
26
|
+
- c041a3f: expose `isOrderedDragTarget` as utility method to differentiate between ordered and unordered drag targets (#108)
|
|
27
|
+
- 2887b0c: Added a `item.getKey()` utility method to use for generating React keys. For now, this just returns the item id, so no migration is needed from using `item.getId()` as React keys.
|
|
28
|
+
- 4e79bc7: Fixed a bug where `feature.overwrites` is not always respected when features are sorted during tree initialization
|
|
29
|
+
- 0669580: Fixed a bug where items that call `item.getProps` while being renamed, can be dragged while being renamed (#110)
|
|
30
|
+
|
|
3
31
|
## 1.1.0
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
|
@@ -14,6 +14,18 @@ const verifyFeatures = (features) => {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
|
+
// Check all possible pairs and sort the array
|
|
18
|
+
const exhaustiveSort = (arr, compareFn) => {
|
|
19
|
+
const n = arr.length;
|
|
20
|
+
for (let i = 0; i < n; i++) {
|
|
21
|
+
for (let j = i + 1; j < n; j++) {
|
|
22
|
+
if (compareFn(arr[j], arr[i]) < 0) {
|
|
23
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return arr;
|
|
28
|
+
};
|
|
17
29
|
const compareFeatures = (originalOrder) => (feature1, feature2) => {
|
|
18
30
|
var _a, _b;
|
|
19
31
|
if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
|
|
@@ -24,7 +36,7 @@ const compareFeatures = (originalOrder) => (feature1, feature2) => {
|
|
|
24
36
|
}
|
|
25
37
|
return originalOrder.indexOf(feature1) - originalOrder.indexOf(feature2);
|
|
26
38
|
};
|
|
27
|
-
const sortFeatures = (features = []) => features
|
|
39
|
+
const sortFeatures = (features = []) => exhaustiveSort(features, compareFeatures(features));
|
|
28
40
|
const createTree = (initialConfig) => {
|
|
29
41
|
var _a, _b, _c, _d;
|
|
30
42
|
const buildInstance = (_a = initialConfig.instanceBuilder) !== null && _a !== void 0 ? _a : build_static_instance_1.buildStaticInstance;
|
|
@@ -100,6 +112,15 @@ const createTree = (initialConfig) => {
|
|
|
100
112
|
const externalStateSetter = config[stateHandlerNames[stateName]];
|
|
101
113
|
externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
|
|
102
114
|
},
|
|
115
|
+
buildItemInstance: ({}, itemId) => {
|
|
116
|
+
const [instance, finalizeInstance] = buildInstance(features, "itemInstance", (instance) => ({
|
|
117
|
+
item: instance,
|
|
118
|
+
tree: treeInstance,
|
|
119
|
+
itemId,
|
|
120
|
+
}));
|
|
121
|
+
finalizeInstance();
|
|
122
|
+
return instance;
|
|
123
|
+
},
|
|
103
124
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
104
125
|
rebuildTree: () => {
|
|
105
126
|
var _a;
|
|
@@ -165,7 +186,6 @@ const createTree = (initialConfig) => {
|
|
|
165
186
|
Object.assign(hotkeyPresets, (_d = feature.hotkeys) !== null && _d !== void 0 ? _d : {});
|
|
166
187
|
}
|
|
167
188
|
finalizeTree();
|
|
168
|
-
rebuildItemMeta();
|
|
169
189
|
return treeInstance;
|
|
170
190
|
};
|
|
171
191
|
exports.createTree = createTree;
|
|
@@ -75,14 +75,14 @@ exports.asyncDataLoaderFeature = {
|
|
|
75
75
|
var _b;
|
|
76
76
|
return ((_b = getDataRef(tree).current.childrenIds[itemId]) !== null && _b !== void 0 ? _b : (yield loadChildrenIds(tree, itemId)));
|
|
77
77
|
}),
|
|
78
|
-
retrieveItemData: ({ tree }, itemId) => {
|
|
78
|
+
retrieveItemData: ({ tree }, itemId, skipFetch = false) => {
|
|
79
79
|
var _a, _b;
|
|
80
80
|
const config = tree.getConfig();
|
|
81
81
|
const dataRef = getDataRef(tree);
|
|
82
82
|
if (dataRef.current.itemData[itemId]) {
|
|
83
83
|
return dataRef.current.itemData[itemId];
|
|
84
84
|
}
|
|
85
|
-
if (!tree.getState().loadingItemData.includes(itemId)) {
|
|
85
|
+
if (!tree.getState().loadingItemData.includes(itemId) && !skipFetch) {
|
|
86
86
|
tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
|
|
87
87
|
...loadingItemData,
|
|
88
88
|
itemId,
|
|
@@ -91,12 +91,12 @@ exports.asyncDataLoaderFeature = {
|
|
|
91
91
|
}
|
|
92
92
|
return (_b = (_a = config.createLoadingItemData) === null || _a === void 0 ? void 0 : _a.call(config)) !== null && _b !== void 0 ? _b : null;
|
|
93
93
|
},
|
|
94
|
-
retrieveChildrenIds: ({ tree }, itemId) => {
|
|
94
|
+
retrieveChildrenIds: ({ tree }, itemId, skipFetch = false) => {
|
|
95
95
|
const dataRef = getDataRef(tree);
|
|
96
96
|
if (dataRef.current.childrenIds[itemId]) {
|
|
97
97
|
return dataRef.current.childrenIds[itemId];
|
|
98
98
|
}
|
|
99
|
-
if (tree.getState().loadingItemChildrens.includes(itemId)) {
|
|
99
|
+
if (tree.getState().loadingItemChildrens.includes(itemId) || skipFetch) {
|
|
100
100
|
return [];
|
|
101
101
|
}
|
|
102
102
|
tree.applySubStateUpdate("loadingItemChildrens", (loadingItemChildrens) => [...loadingItemChildrens, itemId]);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkboxesFeature = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const errors_1 = require("../../utilities/errors");
|
|
7
|
+
const getAllLoadedDescendants = (tree, itemId) => {
|
|
8
|
+
if (!tree.getConfig().isItemFolder(tree.buildItemInstance(itemId))) {
|
|
9
|
+
return [itemId];
|
|
10
|
+
}
|
|
11
|
+
return tree
|
|
12
|
+
.retrieveChildrenIds(itemId)
|
|
13
|
+
.map((child) => getAllLoadedDescendants(tree, child))
|
|
14
|
+
.flat();
|
|
15
|
+
};
|
|
16
|
+
exports.checkboxesFeature = {
|
|
17
|
+
key: "checkboxes",
|
|
18
|
+
overwrites: ["selection"],
|
|
19
|
+
getInitialState: (initialState) => (Object.assign({ checkedItems: [] }, initialState)),
|
|
20
|
+
getDefaultConfig: (defaultConfig, tree) => {
|
|
21
|
+
var _a;
|
|
22
|
+
const hasAsyncLoader = (_a = defaultConfig.features) === null || _a === void 0 ? void 0 : _a.some((f) => f.key === "async-data-loader");
|
|
23
|
+
if (hasAsyncLoader && !defaultConfig.canCheckFolders) {
|
|
24
|
+
(0, errors_1.throwError)(`!canCheckFolders not supported with async trees`);
|
|
25
|
+
}
|
|
26
|
+
return Object.assign({ setCheckedItems: (0, utils_1.makeStateUpdater)("checkedItems", tree), canCheckFolders: hasAsyncLoader !== null && hasAsyncLoader !== void 0 ? hasAsyncLoader : false }, defaultConfig);
|
|
27
|
+
},
|
|
28
|
+
stateHandlerNames: {
|
|
29
|
+
checkedItems: "setCheckedItems",
|
|
30
|
+
},
|
|
31
|
+
treeInstance: {
|
|
32
|
+
setCheckedItems: ({ tree }, checkedItems) => {
|
|
33
|
+
tree.applySubStateUpdate("checkedItems", checkedItems);
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
itemInstance: {
|
|
37
|
+
getCheckboxProps: ({ item }) => {
|
|
38
|
+
const checkedState = item.getCheckedState();
|
|
39
|
+
return {
|
|
40
|
+
onChange: item.toggleCheckedState,
|
|
41
|
+
checked: checkedState === types_1.CheckedState.Checked,
|
|
42
|
+
ref: (r) => {
|
|
43
|
+
if (r) {
|
|
44
|
+
r.indeterminate = checkedState === types_1.CheckedState.Indeterminate;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
toggleCheckedState: ({ item }) => {
|
|
50
|
+
if (item.getCheckedState() === types_1.CheckedState.Checked) {
|
|
51
|
+
item.setUnchecked();
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
item.setChecked();
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
getCheckedState: ({ item, tree, itemId }) => {
|
|
58
|
+
const { checkedItems } = tree.getState();
|
|
59
|
+
if (checkedItems.includes(itemId)) {
|
|
60
|
+
return types_1.CheckedState.Checked;
|
|
61
|
+
}
|
|
62
|
+
if (item.isFolder() && !tree.getConfig().canCheckFolders) {
|
|
63
|
+
const descendants = getAllLoadedDescendants(tree, itemId);
|
|
64
|
+
if (descendants.every((d) => checkedItems.includes(d))) {
|
|
65
|
+
return types_1.CheckedState.Checked;
|
|
66
|
+
}
|
|
67
|
+
if (descendants.some((d) => checkedItems.includes(d))) {
|
|
68
|
+
return types_1.CheckedState.Indeterminate;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return types_1.CheckedState.Unchecked;
|
|
72
|
+
},
|
|
73
|
+
setChecked: ({ item, tree, itemId }) => {
|
|
74
|
+
if (!item.isFolder() || tree.getConfig().canCheckFolders) {
|
|
75
|
+
tree.applySubStateUpdate("checkedItems", (items) => [...items, itemId]);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
tree.applySubStateUpdate("checkedItems", (items) => [
|
|
79
|
+
...items,
|
|
80
|
+
...getAllLoadedDescendants(tree, itemId),
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
setUnchecked: ({ item, tree, itemId }) => {
|
|
85
|
+
if (!item.isFolder() || tree.getConfig().canCheckFolders) {
|
|
86
|
+
tree.applySubStateUpdate("checkedItems", (items) => items.filter((id) => id !== itemId));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const descendants = getAllLoadedDescendants(tree, itemId);
|
|
90
|
+
tree.applySubStateUpdate("checkedItems", (items) => items.filter((id) => !descendants.includes(id)));
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SetStateFn } from "../../types/core";
|
|
2
|
+
export declare enum CheckedState {
|
|
3
|
+
Checked = "checked",
|
|
4
|
+
Unchecked = "unchecked",
|
|
5
|
+
Indeterminate = "indeterminate"
|
|
6
|
+
}
|
|
7
|
+
export type CheckboxesFeatureDef<T> = {
|
|
8
|
+
state: {
|
|
9
|
+
checkedItems: string[];
|
|
10
|
+
};
|
|
11
|
+
config: {
|
|
12
|
+
setCheckedItems?: SetStateFn<string[]>;
|
|
13
|
+
canCheckFolders?: boolean;
|
|
14
|
+
};
|
|
15
|
+
treeInstance: {
|
|
16
|
+
setCheckedItems: (checkedItems: string[]) => void;
|
|
17
|
+
};
|
|
18
|
+
itemInstance: {
|
|
19
|
+
setChecked: () => void;
|
|
20
|
+
setUnchecked: () => void;
|
|
21
|
+
toggleCheckedState: () => void;
|
|
22
|
+
getCheckedState: () => CheckedState;
|
|
23
|
+
getCheckboxProps: () => Record<string, any>;
|
|
24
|
+
};
|
|
25
|
+
hotkeys: never;
|
|
26
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CheckedState = void 0;
|
|
4
|
+
var CheckedState;
|
|
5
|
+
(function (CheckedState) {
|
|
6
|
+
CheckedState["Checked"] = "checked";
|
|
7
|
+
CheckedState["Unchecked"] = "unchecked";
|
|
8
|
+
CheckedState["Indeterminate"] = "indeterminate";
|
|
9
|
+
})(CheckedState || (exports.CheckedState = CheckedState = {}));
|
|
@@ -68,14 +68,35 @@ exports.dragAndDropFeature = {
|
|
|
68
68
|
}
|
|
69
69
|
: { display: "none" };
|
|
70
70
|
},
|
|
71
|
-
getContainerProps: ({ prev }, treeLabel) => {
|
|
71
|
+
getContainerProps: ({ prev, tree }, treeLabel) => {
|
|
72
72
|
const prevProps = prev === null || prev === void 0 ? void 0 : prev(treeLabel);
|
|
73
|
-
return Object.assign(Object.assign({}, prevProps), {
|
|
73
|
+
return Object.assign(Object.assign({}, prevProps), { onDragOver: (e) => {
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
}, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
var _a, _b, _c;
|
|
77
|
+
// TODO merge implementation with itemInstance.onDrop
|
|
78
|
+
const dataRef = tree.getDataRef();
|
|
79
|
+
const target = { item: tree.getRootItem() };
|
|
80
|
+
if (!(0, utils_1.canDrop)(e.dataTransfer, target, tree)) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
const config = tree.getConfig();
|
|
85
|
+
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
86
|
+
dataRef.current.lastDragCode = undefined;
|
|
87
|
+
tree.applySubStateUpdate("dnd", null);
|
|
88
|
+
if (draggedItems) {
|
|
89
|
+
yield ((_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target));
|
|
90
|
+
}
|
|
91
|
+
else if (e.dataTransfer) {
|
|
92
|
+
yield ((_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target));
|
|
93
|
+
}
|
|
94
|
+
}), style: Object.assign(Object.assign({}, prevProps === null || prevProps === void 0 ? void 0 : prevProps.style), { position: "relative" }) });
|
|
74
95
|
},
|
|
75
96
|
},
|
|
76
97
|
itemInstance: {
|
|
77
|
-
getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: true, onDragStart: (e) => {
|
|
78
|
-
var _a, _b, _c;
|
|
98
|
+
getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: true, onDragEnter: (e) => e.preventDefault(), onDragStart: (e) => {
|
|
99
|
+
var _a, _b, _c, _d;
|
|
79
100
|
const selectedItems = tree.getSelectedItems();
|
|
80
101
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
81
102
|
const config = tree.getConfig();
|
|
@@ -86,9 +107,13 @@ exports.dragAndDropFeature = {
|
|
|
86
107
|
e.preventDefault();
|
|
87
108
|
return;
|
|
88
109
|
}
|
|
110
|
+
if (config.setDragImage) {
|
|
111
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
112
|
+
(_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.setDragImage(imgElement, xOffset !== null && xOffset !== void 0 ? xOffset : 0, yOffset !== null && yOffset !== void 0 ? yOffset : 0);
|
|
113
|
+
}
|
|
89
114
|
if (config.createForeignDragObject) {
|
|
90
115
|
const { format, data } = config.createForeignDragObject(items);
|
|
91
|
-
(
|
|
116
|
+
(_d = e.dataTransfer) === null || _d === void 0 ? void 0 : _d.setData(format, data);
|
|
92
117
|
}
|
|
93
118
|
tree.applySubStateUpdate("dnd", {
|
|
94
119
|
draggedItems: items,
|
|
@@ -134,6 +159,7 @@ exports.dragAndDropFeature = {
|
|
|
134
159
|
(_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
|
|
135
160
|
}, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
136
161
|
var _a, _b, _c;
|
|
162
|
+
e.stopPropagation();
|
|
137
163
|
const dataRef = tree.getDataRef();
|
|
138
164
|
const target = (0, utils_1.getDragTarget)(e, item, tree);
|
|
139
165
|
if (!(0, utils_1.canDrop)(e.dataTransfer, target, tree)) {
|
|
@@ -46,6 +46,11 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
46
46
|
format: string;
|
|
47
47
|
data: any;
|
|
48
48
|
};
|
|
49
|
+
setDragImage?: (items: ItemInstance<T>[]) => {
|
|
50
|
+
imgElement: Element;
|
|
51
|
+
xOffset?: number;
|
|
52
|
+
yOffset?: number;
|
|
53
|
+
};
|
|
49
54
|
canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
|
|
50
55
|
onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
|
|
51
56
|
onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
|
|
@@ -17,6 +17,8 @@ export type MainFeatureDef<T = any> = {
|
|
|
17
17
|
treeInstance: {
|
|
18
18
|
/** @internal */
|
|
19
19
|
applySubStateUpdate: <K extends keyof TreeState<any>>(stateName: K, updater: Updater<TreeState<T>[K]>) => void;
|
|
20
|
+
/** @internal */
|
|
21
|
+
buildItemInstance: (itemId: string) => ItemInstance<T>;
|
|
20
22
|
setState: SetStateFn<TreeState<T>>;
|
|
21
23
|
getState: () => TreeState<T>;
|
|
22
24
|
setConfig: SetStateFn<TreeConfig<T>>;
|
|
@@ -4,6 +4,7 @@ exports.renamingFeature = void 0;
|
|
|
4
4
|
const utils_1 = require("../../utils");
|
|
5
5
|
exports.renamingFeature = {
|
|
6
6
|
key: "renaming",
|
|
7
|
+
overwrites: ["drag-and-drop"],
|
|
7
8
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setRenamingItem: (0, utils_1.makeStateUpdater)("renamingItem", tree), setRenamingValue: (0, utils_1.makeStateUpdater)("renamingValue", tree), canRename: () => true }, defaultConfig)),
|
|
8
9
|
stateHandlerNames: {
|
|
9
10
|
renamingItem: "setRenamingItem",
|
|
@@ -50,6 +51,13 @@ exports.renamingFeature = {
|
|
|
50
51
|
}),
|
|
51
52
|
canRename: ({ tree, item }) => { var _a, _b, _c; return (_c = (_b = (_a = tree.getConfig()).canRename) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true; },
|
|
52
53
|
isRenaming: ({ tree, item }) => item.getId() === tree.getState().renamingItem,
|
|
54
|
+
getProps: ({ prev, item }) => {
|
|
55
|
+
var _a;
|
|
56
|
+
const isRenaming = item.isRenaming();
|
|
57
|
+
const prevProps = (_a = prev === null || prev === void 0 ? void 0 : prev()) !== null && _a !== void 0 ? _a : {};
|
|
58
|
+
return isRenaming
|
|
59
|
+
? Object.assign(Object.assign({}, prevProps), { draggable: false, onDragStart: () => { } }) : prevProps;
|
|
60
|
+
},
|
|
53
61
|
},
|
|
54
62
|
hotkeys: {
|
|
55
63
|
renameItem: {
|
|
@@ -59,6 +59,10 @@ exports.treeFeature = {
|
|
|
59
59
|
var _a, _b;
|
|
60
60
|
return ((_b = tree.getItemInstance((_a = tree.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : tree.getItems()[0]);
|
|
61
61
|
},
|
|
62
|
+
getRootItem: ({ tree }) => {
|
|
63
|
+
const { rootItemId } = tree.getConfig();
|
|
64
|
+
return tree.getItemInstance(rootItemId);
|
|
65
|
+
},
|
|
62
66
|
focusNextItem: ({ tree }) => {
|
|
63
67
|
var _a;
|
|
64
68
|
const focused = tree.getFocusedItem().getItemMeta();
|
|
@@ -100,6 +104,7 @@ exports.treeFeature = {
|
|
|
100
104
|
(_d = item.getElement()) === null || _d === void 0 ? void 0 : _d.scrollIntoView(scrollIntoViewArg);
|
|
101
105
|
}),
|
|
102
106
|
getId: ({ itemId }) => itemId,
|
|
107
|
+
getKey: ({ itemId }) => itemId, // TODO apply to all stories to use
|
|
103
108
|
getProps: ({ item, prev }) => {
|
|
104
109
|
const itemMeta = item.getItemMeta();
|
|
105
110
|
return Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { ref: item.registerElement, role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": "false", "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: (e) => {
|
|
@@ -27,7 +27,8 @@ export type TreeFeatureDef<T> = {
|
|
|
27
27
|
treeInstance: {
|
|
28
28
|
/** @internal */
|
|
29
29
|
getItemsMeta: () => ItemMeta[];
|
|
30
|
-
getFocusedItem: () => ItemInstance<
|
|
30
|
+
getFocusedItem: () => ItemInstance<T>;
|
|
31
|
+
getRootItem: () => ItemInstance<T>;
|
|
31
32
|
focusNextItem: () => void;
|
|
32
33
|
focusPreviousItem: () => void;
|
|
33
34
|
updateDomFocus: () => void;
|
|
@@ -37,6 +38,7 @@ export type TreeFeatureDef<T> = {
|
|
|
37
38
|
};
|
|
38
39
|
itemInstance: {
|
|
39
40
|
getId: () => string;
|
|
41
|
+
getKey: () => string;
|
|
40
42
|
getProps: () => Record<string, any>;
|
|
41
43
|
getItemName: () => string;
|
|
42
44
|
getItemData: () => T;
|
package/lib/cjs/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { MainFeatureDef, InstanceBuilder } from "./features/main/types";
|
|
|
5
5
|
export * from "./features/drag-and-drop/types";
|
|
6
6
|
export * from "./features/keyboard-drag-and-drop/types";
|
|
7
7
|
export * from "./features/selection/types";
|
|
8
|
+
export * from "./features/checkboxes/types";
|
|
8
9
|
export * from "./features/async-data-loader/types";
|
|
9
10
|
export * from "./features/sync-data-loader/types";
|
|
10
11
|
export * from "./features/hotkeys-core/types";
|
|
@@ -13,6 +14,7 @@ export * from "./features/renaming/types";
|
|
|
13
14
|
export * from "./features/expand-all/types";
|
|
14
15
|
export * from "./features/prop-memoization/types";
|
|
15
16
|
export * from "./features/selection/feature";
|
|
17
|
+
export * from "./features/checkboxes/feature";
|
|
16
18
|
export * from "./features/hotkeys-core/feature";
|
|
17
19
|
export * from "./features/async-data-loader/feature";
|
|
18
20
|
export * from "./features/sync-data-loader/feature";
|
|
@@ -27,3 +29,5 @@ export * from "./utilities/insert-items-at-target";
|
|
|
27
29
|
export * from "./utilities/remove-items-from-parents";
|
|
28
30
|
export * from "./core/build-proxified-instance";
|
|
29
31
|
export * from "./core/build-static-instance";
|
|
32
|
+
export { makeStateUpdater } from "./utils";
|
|
33
|
+
export { isOrderedDragTarget } from "./features/drag-and-drop/utils";
|
package/lib/cjs/index.js
CHANGED
|
@@ -14,12 +14,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.isOrderedDragTarget = exports.makeStateUpdater = void 0;
|
|
17
18
|
__exportStar(require("./types/core"), exports);
|
|
18
19
|
__exportStar(require("./core/create-tree"), exports);
|
|
19
20
|
__exportStar(require("./features/tree/types"), exports);
|
|
20
21
|
__exportStar(require("./features/drag-and-drop/types"), exports);
|
|
21
22
|
__exportStar(require("./features/keyboard-drag-and-drop/types"), exports);
|
|
22
23
|
__exportStar(require("./features/selection/types"), exports);
|
|
24
|
+
__exportStar(require("./features/checkboxes/types"), exports);
|
|
23
25
|
__exportStar(require("./features/async-data-loader/types"), exports);
|
|
24
26
|
__exportStar(require("./features/sync-data-loader/types"), exports);
|
|
25
27
|
__exportStar(require("./features/hotkeys-core/types"), exports);
|
|
@@ -28,6 +30,7 @@ __exportStar(require("./features/renaming/types"), exports);
|
|
|
28
30
|
__exportStar(require("./features/expand-all/types"), exports);
|
|
29
31
|
__exportStar(require("./features/prop-memoization/types"), exports);
|
|
30
32
|
__exportStar(require("./features/selection/feature"), exports);
|
|
33
|
+
__exportStar(require("./features/checkboxes/feature"), exports);
|
|
31
34
|
__exportStar(require("./features/hotkeys-core/feature"), exports);
|
|
32
35
|
__exportStar(require("./features/async-data-loader/feature"), exports);
|
|
33
36
|
__exportStar(require("./features/sync-data-loader/feature"), exports);
|
|
@@ -42,3 +45,7 @@ __exportStar(require("./utilities/insert-items-at-target"), exports);
|
|
|
42
45
|
__exportStar(require("./utilities/remove-items-from-parents"), exports);
|
|
43
46
|
__exportStar(require("./core/build-proxified-instance"), exports);
|
|
44
47
|
__exportStar(require("./core/build-static-instance"), exports);
|
|
48
|
+
var utils_1 = require("./utils");
|
|
49
|
+
Object.defineProperty(exports, "makeStateUpdater", { enumerable: true, get: function () { return utils_1.makeStateUpdater; } });
|
|
50
|
+
var utils_2 = require("./features/drag-and-drop/utils");
|
|
51
|
+
Object.defineProperty(exports, "isOrderedDragTarget", { enumerable: true, get: function () { return utils_2.isOrderedDragTarget; } });
|
package/lib/cjs/types/core.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { RenamingFeatureDef } from "../features/renaming/types";
|
|
|
10
10
|
import { ExpandAllFeatureDef } from "../features/expand-all/types";
|
|
11
11
|
import { PropMemoizationFeatureDef } from "../features/prop-memoization/types";
|
|
12
12
|
import { KeyboardDragAndDropFeatureDef } from "../features/keyboard-drag-and-drop/types";
|
|
13
|
+
import { CheckboxesFeatureDef } from "../features/checkboxes/types";
|
|
13
14
|
export type Updater<T> = T | ((old: T) => T);
|
|
14
15
|
export type SetStateFn<T> = (updaterOrValue: Updater<T>) => void;
|
|
15
16
|
export type FeatureDef = {
|
|
@@ -34,7 +35,7 @@ type MergedFeatures<F extends FeatureDef> = {
|
|
|
34
35
|
itemInstance: UnionToIntersection<F["itemInstance"]>;
|
|
35
36
|
hotkeys: F["hotkeys"];
|
|
36
37
|
};
|
|
37
|
-
export type RegisteredFeatures<T> = MainFeatureDef<T> | TreeFeatureDef<T> | SelectionFeatureDef<T> | DragAndDropFeatureDef<T> | KeyboardDragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef | PropMemoizationFeatureDef;
|
|
38
|
+
export type RegisteredFeatures<T> = MainFeatureDef<T> | TreeFeatureDef<T> | SelectionFeatureDef<T> | CheckboxesFeatureDef<T> | DragAndDropFeatureDef<T> | KeyboardDragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef | PropMemoizationFeatureDef;
|
|
38
39
|
type TreeStateType<T> = MergedFeatures<RegisteredFeatures<T>>["state"];
|
|
39
40
|
export interface TreeState<T> extends TreeStateType<T> {
|
|
40
41
|
}
|
|
@@ -11,6 +11,18 @@ const verifyFeatures = (features) => {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
|
+
// Check all possible pairs and sort the array
|
|
15
|
+
const exhaustiveSort = (arr, compareFn) => {
|
|
16
|
+
const n = arr.length;
|
|
17
|
+
for (let i = 0; i < n; i++) {
|
|
18
|
+
for (let j = i + 1; j < n; j++) {
|
|
19
|
+
if (compareFn(arr[j], arr[i]) < 0) {
|
|
20
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return arr;
|
|
25
|
+
};
|
|
14
26
|
const compareFeatures = (originalOrder) => (feature1, feature2) => {
|
|
15
27
|
var _a, _b;
|
|
16
28
|
if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
|
|
@@ -21,7 +33,7 @@ const compareFeatures = (originalOrder) => (feature1, feature2) => {
|
|
|
21
33
|
}
|
|
22
34
|
return originalOrder.indexOf(feature1) - originalOrder.indexOf(feature2);
|
|
23
35
|
};
|
|
24
|
-
const sortFeatures = (features = []) => features
|
|
36
|
+
const sortFeatures = (features = []) => exhaustiveSort(features, compareFeatures(features));
|
|
25
37
|
export const createTree = (initialConfig) => {
|
|
26
38
|
var _a, _b, _c, _d;
|
|
27
39
|
const buildInstance = (_a = initialConfig.instanceBuilder) !== null && _a !== void 0 ? _a : buildStaticInstance;
|
|
@@ -97,6 +109,15 @@ export const createTree = (initialConfig) => {
|
|
|
97
109
|
const externalStateSetter = config[stateHandlerNames[stateName]];
|
|
98
110
|
externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
|
|
99
111
|
},
|
|
112
|
+
buildItemInstance: ({}, itemId) => {
|
|
113
|
+
const [instance, finalizeInstance] = buildInstance(features, "itemInstance", (instance) => ({
|
|
114
|
+
item: instance,
|
|
115
|
+
tree: treeInstance,
|
|
116
|
+
itemId,
|
|
117
|
+
}));
|
|
118
|
+
finalizeInstance();
|
|
119
|
+
return instance;
|
|
120
|
+
},
|
|
100
121
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
101
122
|
rebuildTree: () => {
|
|
102
123
|
var _a;
|
|
@@ -162,6 +183,5 @@ export const createTree = (initialConfig) => {
|
|
|
162
183
|
Object.assign(hotkeyPresets, (_d = feature.hotkeys) !== null && _d !== void 0 ? _d : {});
|
|
163
184
|
}
|
|
164
185
|
finalizeTree();
|
|
165
|
-
rebuildItemMeta();
|
|
166
186
|
return treeInstance;
|
|
167
187
|
};
|
|
@@ -72,14 +72,14 @@ export const asyncDataLoaderFeature = {
|
|
|
72
72
|
var _b;
|
|
73
73
|
return ((_b = getDataRef(tree).current.childrenIds[itemId]) !== null && _b !== void 0 ? _b : (yield loadChildrenIds(tree, itemId)));
|
|
74
74
|
}),
|
|
75
|
-
retrieveItemData: ({ tree }, itemId) => {
|
|
75
|
+
retrieveItemData: ({ tree }, itemId, skipFetch = false) => {
|
|
76
76
|
var _a, _b;
|
|
77
77
|
const config = tree.getConfig();
|
|
78
78
|
const dataRef = getDataRef(tree);
|
|
79
79
|
if (dataRef.current.itemData[itemId]) {
|
|
80
80
|
return dataRef.current.itemData[itemId];
|
|
81
81
|
}
|
|
82
|
-
if (!tree.getState().loadingItemData.includes(itemId)) {
|
|
82
|
+
if (!tree.getState().loadingItemData.includes(itemId) && !skipFetch) {
|
|
83
83
|
tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
|
|
84
84
|
...loadingItemData,
|
|
85
85
|
itemId,
|
|
@@ -88,12 +88,12 @@ export const asyncDataLoaderFeature = {
|
|
|
88
88
|
}
|
|
89
89
|
return (_b = (_a = config.createLoadingItemData) === null || _a === void 0 ? void 0 : _a.call(config)) !== null && _b !== void 0 ? _b : null;
|
|
90
90
|
},
|
|
91
|
-
retrieveChildrenIds: ({ tree }, itemId) => {
|
|
91
|
+
retrieveChildrenIds: ({ tree }, itemId, skipFetch = false) => {
|
|
92
92
|
const dataRef = getDataRef(tree);
|
|
93
93
|
if (dataRef.current.childrenIds[itemId]) {
|
|
94
94
|
return dataRef.current.childrenIds[itemId];
|
|
95
95
|
}
|
|
96
|
-
if (tree.getState().loadingItemChildrens.includes(itemId)) {
|
|
96
|
+
if (tree.getState().loadingItemChildrens.includes(itemId) || skipFetch) {
|
|
97
97
|
return [];
|
|
98
98
|
}
|
|
99
99
|
tree.applySubStateUpdate("loadingItemChildrens", (loadingItemChildrens) => [...loadingItemChildrens, itemId]);
|