@headless-tree/core 1.2.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 +8 -0
- package/lib/cjs/core/create-tree.js +9 -0
- 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/tree/feature.js +4 -0
- package/lib/cjs/features/tree/types.d.ts +2 -1
- package/lib/cjs/index.d.ts +2 -0
- package/lib/cjs/index.js +2 -0
- package/lib/cjs/types/core.d.ts +2 -1
- package/lib/esm/core/create-tree.js +9 -0
- 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/tree/feature.js +4 -0
- package/lib/esm/features/tree/types.d.ts +2 -1
- package/lib/esm/index.d.ts +2 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/types/core.d.ts +2 -1
- package/package.json +1 -1
- package/src/core/create-tree.ts +13 -0
- 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/tree/feature.ts +5 -0
- package/src/features/tree/types.ts +3 -2
- package/src/index.ts +2 -0
- package/src/types/core.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
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
|
+
|
|
3
11
|
## 1.2.0
|
|
4
12
|
|
|
5
13
|
### Minor Changes
|
|
@@ -112,6 +112,15 @@ const createTree = (initialConfig) => {
|
|
|
112
112
|
const externalStateSetter = config[stateHandlerNames[stateName]];
|
|
113
113
|
externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
|
|
114
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
|
+
},
|
|
115
124
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
116
125
|
rebuildTree: () => {
|
|
117
126
|
var _a;
|
|
@@ -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>>;
|
|
@@ -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();
|
|
@@ -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;
|
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";
|
package/lib/cjs/index.js
CHANGED
|
@@ -21,6 +21,7 @@ __exportStar(require("./features/tree/types"), exports);
|
|
|
21
21
|
__exportStar(require("./features/drag-and-drop/types"), exports);
|
|
22
22
|
__exportStar(require("./features/keyboard-drag-and-drop/types"), exports);
|
|
23
23
|
__exportStar(require("./features/selection/types"), exports);
|
|
24
|
+
__exportStar(require("./features/checkboxes/types"), exports);
|
|
24
25
|
__exportStar(require("./features/async-data-loader/types"), exports);
|
|
25
26
|
__exportStar(require("./features/sync-data-loader/types"), exports);
|
|
26
27
|
__exportStar(require("./features/hotkeys-core/types"), exports);
|
|
@@ -29,6 +30,7 @@ __exportStar(require("./features/renaming/types"), exports);
|
|
|
29
30
|
__exportStar(require("./features/expand-all/types"), exports);
|
|
30
31
|
__exportStar(require("./features/prop-memoization/types"), exports);
|
|
31
32
|
__exportStar(require("./features/selection/feature"), exports);
|
|
33
|
+
__exportStar(require("./features/checkboxes/feature"), exports);
|
|
32
34
|
__exportStar(require("./features/hotkeys-core/feature"), exports);
|
|
33
35
|
__exportStar(require("./features/async-data-loader/feature"), exports);
|
|
34
36
|
__exportStar(require("./features/sync-data-loader/feature"), exports);
|
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
|
}
|
|
@@ -109,6 +109,15 @@ export const createTree = (initialConfig) => {
|
|
|
109
109
|
const externalStateSetter = config[stateHandlerNames[stateName]];
|
|
110
110
|
externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
|
|
111
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
|
+
},
|
|
112
121
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
113
122
|
rebuildTree: () => {
|
|
114
123
|
var _a;
|
|
@@ -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]);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { makeStateUpdater } from "../../utils";
|
|
2
|
+
import { CheckedState } from "./types";
|
|
3
|
+
import { throwError } from "../../utilities/errors";
|
|
4
|
+
const getAllLoadedDescendants = (tree, itemId) => {
|
|
5
|
+
if (!tree.getConfig().isItemFolder(tree.buildItemInstance(itemId))) {
|
|
6
|
+
return [itemId];
|
|
7
|
+
}
|
|
8
|
+
return tree
|
|
9
|
+
.retrieveChildrenIds(itemId)
|
|
10
|
+
.map((child) => getAllLoadedDescendants(tree, child))
|
|
11
|
+
.flat();
|
|
12
|
+
};
|
|
13
|
+
export const checkboxesFeature = {
|
|
14
|
+
key: "checkboxes",
|
|
15
|
+
overwrites: ["selection"],
|
|
16
|
+
getInitialState: (initialState) => (Object.assign({ checkedItems: [] }, initialState)),
|
|
17
|
+
getDefaultConfig: (defaultConfig, tree) => {
|
|
18
|
+
var _a;
|
|
19
|
+
const hasAsyncLoader = (_a = defaultConfig.features) === null || _a === void 0 ? void 0 : _a.some((f) => f.key === "async-data-loader");
|
|
20
|
+
if (hasAsyncLoader && !defaultConfig.canCheckFolders) {
|
|
21
|
+
throwError(`!canCheckFolders not supported with async trees`);
|
|
22
|
+
}
|
|
23
|
+
return Object.assign({ setCheckedItems: makeStateUpdater("checkedItems", tree), canCheckFolders: hasAsyncLoader !== null && hasAsyncLoader !== void 0 ? hasAsyncLoader : false }, defaultConfig);
|
|
24
|
+
},
|
|
25
|
+
stateHandlerNames: {
|
|
26
|
+
checkedItems: "setCheckedItems",
|
|
27
|
+
},
|
|
28
|
+
treeInstance: {
|
|
29
|
+
setCheckedItems: ({ tree }, checkedItems) => {
|
|
30
|
+
tree.applySubStateUpdate("checkedItems", checkedItems);
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
itemInstance: {
|
|
34
|
+
getCheckboxProps: ({ item }) => {
|
|
35
|
+
const checkedState = item.getCheckedState();
|
|
36
|
+
return {
|
|
37
|
+
onChange: item.toggleCheckedState,
|
|
38
|
+
checked: checkedState === CheckedState.Checked,
|
|
39
|
+
ref: (r) => {
|
|
40
|
+
if (r) {
|
|
41
|
+
r.indeterminate = checkedState === CheckedState.Indeterminate;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
toggleCheckedState: ({ item }) => {
|
|
47
|
+
if (item.getCheckedState() === CheckedState.Checked) {
|
|
48
|
+
item.setUnchecked();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
item.setChecked();
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
getCheckedState: ({ item, tree, itemId }) => {
|
|
55
|
+
const { checkedItems } = tree.getState();
|
|
56
|
+
if (checkedItems.includes(itemId)) {
|
|
57
|
+
return CheckedState.Checked;
|
|
58
|
+
}
|
|
59
|
+
if (item.isFolder() && !tree.getConfig().canCheckFolders) {
|
|
60
|
+
const descendants = getAllLoadedDescendants(tree, itemId);
|
|
61
|
+
if (descendants.every((d) => checkedItems.includes(d))) {
|
|
62
|
+
return CheckedState.Checked;
|
|
63
|
+
}
|
|
64
|
+
if (descendants.some((d) => checkedItems.includes(d))) {
|
|
65
|
+
return CheckedState.Indeterminate;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return CheckedState.Unchecked;
|
|
69
|
+
},
|
|
70
|
+
setChecked: ({ item, tree, itemId }) => {
|
|
71
|
+
if (!item.isFolder() || tree.getConfig().canCheckFolders) {
|
|
72
|
+
tree.applySubStateUpdate("checkedItems", (items) => [...items, itemId]);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
tree.applySubStateUpdate("checkedItems", (items) => [
|
|
76
|
+
...items,
|
|
77
|
+
...getAllLoadedDescendants(tree, itemId),
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
setUnchecked: ({ item, tree, itemId }) => {
|
|
82
|
+
if (!item.isFolder() || tree.getConfig().canCheckFolders) {
|
|
83
|
+
tree.applySubStateUpdate("checkedItems", (items) => items.filter((id) => id !== itemId));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
const descendants = getAllLoadedDescendants(tree, itemId);
|
|
87
|
+
tree.applySubStateUpdate("checkedItems", (items) => items.filter((id) => !descendants.includes(id)));
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -65,14 +65,35 @@ export const dragAndDropFeature = {
|
|
|
65
65
|
}
|
|
66
66
|
: { display: "none" };
|
|
67
67
|
},
|
|
68
|
-
getContainerProps: ({ prev }, treeLabel) => {
|
|
68
|
+
getContainerProps: ({ prev, tree }, treeLabel) => {
|
|
69
69
|
const prevProps = prev === null || prev === void 0 ? void 0 : prev(treeLabel);
|
|
70
|
-
return Object.assign(Object.assign({}, prevProps), {
|
|
70
|
+
return Object.assign(Object.assign({}, prevProps), { onDragOver: (e) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
}, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
var _a, _b, _c;
|
|
74
|
+
// TODO merge implementation with itemInstance.onDrop
|
|
75
|
+
const dataRef = tree.getDataRef();
|
|
76
|
+
const target = { item: tree.getRootItem() };
|
|
77
|
+
if (!canDrop(e.dataTransfer, target, tree)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
const config = tree.getConfig();
|
|
82
|
+
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
83
|
+
dataRef.current.lastDragCode = undefined;
|
|
84
|
+
tree.applySubStateUpdate("dnd", null);
|
|
85
|
+
if (draggedItems) {
|
|
86
|
+
yield ((_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target));
|
|
87
|
+
}
|
|
88
|
+
else if (e.dataTransfer) {
|
|
89
|
+
yield ((_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target));
|
|
90
|
+
}
|
|
91
|
+
}), style: Object.assign(Object.assign({}, prevProps === null || prevProps === void 0 ? void 0 : prevProps.style), { position: "relative" }) });
|
|
71
92
|
},
|
|
72
93
|
},
|
|
73
94
|
itemInstance: {
|
|
74
|
-
getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: true, onDragStart: (e) => {
|
|
75
|
-
var _a, _b, _c;
|
|
95
|
+
getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: true, onDragEnter: (e) => e.preventDefault(), onDragStart: (e) => {
|
|
96
|
+
var _a, _b, _c, _d;
|
|
76
97
|
const selectedItems = tree.getSelectedItems();
|
|
77
98
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
78
99
|
const config = tree.getConfig();
|
|
@@ -83,9 +104,13 @@ export const dragAndDropFeature = {
|
|
|
83
104
|
e.preventDefault();
|
|
84
105
|
return;
|
|
85
106
|
}
|
|
107
|
+
if (config.setDragImage) {
|
|
108
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
109
|
+
(_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);
|
|
110
|
+
}
|
|
86
111
|
if (config.createForeignDragObject) {
|
|
87
112
|
const { format, data } = config.createForeignDragObject(items);
|
|
88
|
-
(
|
|
113
|
+
(_d = e.dataTransfer) === null || _d === void 0 ? void 0 : _d.setData(format, data);
|
|
89
114
|
}
|
|
90
115
|
tree.applySubStateUpdate("dnd", {
|
|
91
116
|
draggedItems: items,
|
|
@@ -131,6 +156,7 @@ export const dragAndDropFeature = {
|
|
|
131
156
|
(_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
|
|
132
157
|
}, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
133
158
|
var _a, _b, _c;
|
|
159
|
+
e.stopPropagation();
|
|
134
160
|
const dataRef = tree.getDataRef();
|
|
135
161
|
const target = getDragTarget(e, item, tree);
|
|
136
162
|
if (!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>>;
|
|
@@ -56,6 +56,10 @@ export const treeFeature = {
|
|
|
56
56
|
var _a, _b;
|
|
57
57
|
return ((_b = tree.getItemInstance((_a = tree.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : tree.getItems()[0]);
|
|
58
58
|
},
|
|
59
|
+
getRootItem: ({ tree }) => {
|
|
60
|
+
const { rootItemId } = tree.getConfig();
|
|
61
|
+
return tree.getItemInstance(rootItemId);
|
|
62
|
+
},
|
|
59
63
|
focusNextItem: ({ tree }) => {
|
|
60
64
|
var _a;
|
|
61
65
|
const focused = tree.getFocusedItem().getItemMeta();
|
|
@@ -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;
|
package/lib/esm/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";
|
package/lib/esm/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from "./features/tree/types";
|
|
|
4
4
|
export * from "./features/drag-and-drop/types";
|
|
5
5
|
export * from "./features/keyboard-drag-and-drop/types";
|
|
6
6
|
export * from "./features/selection/types";
|
|
7
|
+
export * from "./features/checkboxes/types";
|
|
7
8
|
export * from "./features/async-data-loader/types";
|
|
8
9
|
export * from "./features/sync-data-loader/types";
|
|
9
10
|
export * from "./features/hotkeys-core/types";
|
|
@@ -12,6 +13,7 @@ export * from "./features/renaming/types";
|
|
|
12
13
|
export * from "./features/expand-all/types";
|
|
13
14
|
export * from "./features/prop-memoization/types";
|
|
14
15
|
export * from "./features/selection/feature";
|
|
16
|
+
export * from "./features/checkboxes/feature";
|
|
15
17
|
export * from "./features/hotkeys-core/feature";
|
|
16
18
|
export * from "./features/async-data-loader/feature";
|
|
17
19
|
export * from "./features/sync-data-loader/feature";
|
package/lib/esm/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
|
}
|
package/package.json
CHANGED
package/src/core/create-tree.ts
CHANGED
|
@@ -170,6 +170,19 @@ export const createTree = <T>(
|
|
|
170
170
|
] as Function;
|
|
171
171
|
externalStateSetter?.(state[stateName]);
|
|
172
172
|
},
|
|
173
|
+
buildItemInstance: ({}, itemId) => {
|
|
174
|
+
const [instance, finalizeInstance] = buildInstance(
|
|
175
|
+
features,
|
|
176
|
+
"itemInstance",
|
|
177
|
+
(instance) => ({
|
|
178
|
+
item: instance,
|
|
179
|
+
tree: treeInstance,
|
|
180
|
+
itemId,
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
183
|
+
finalizeInstance();
|
|
184
|
+
return instance;
|
|
185
|
+
},
|
|
173
186
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
174
187
|
rebuildTree: () => {
|
|
175
188
|
rebuildItemMeta();
|
|
@@ -95,7 +95,7 @@ export const asyncDataLoaderFeature: FeatureImplementation = {
|
|
|
95
95
|
);
|
|
96
96
|
},
|
|
97
97
|
|
|
98
|
-
retrieveItemData: ({ tree }, itemId) => {
|
|
98
|
+
retrieveItemData: ({ tree }, itemId, skipFetch = false) => {
|
|
99
99
|
const config = tree.getConfig();
|
|
100
100
|
const dataRef = getDataRef(tree);
|
|
101
101
|
|
|
@@ -103,7 +103,7 @@ export const asyncDataLoaderFeature: FeatureImplementation = {
|
|
|
103
103
|
return dataRef.current.itemData[itemId];
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (!tree.getState().loadingItemData.includes(itemId)) {
|
|
106
|
+
if (!tree.getState().loadingItemData.includes(itemId) && !skipFetch) {
|
|
107
107
|
tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
|
|
108
108
|
...loadingItemData,
|
|
109
109
|
itemId,
|
|
@@ -115,13 +115,13 @@ export const asyncDataLoaderFeature: FeatureImplementation = {
|
|
|
115
115
|
return config.createLoadingItemData?.() ?? null;
|
|
116
116
|
},
|
|
117
117
|
|
|
118
|
-
retrieveChildrenIds: ({ tree }, itemId) => {
|
|
118
|
+
retrieveChildrenIds: ({ tree }, itemId, skipFetch = false) => {
|
|
119
119
|
const dataRef = getDataRef(tree);
|
|
120
120
|
if (dataRef.current.childrenIds[itemId]) {
|
|
121
121
|
return dataRef.current.childrenIds[itemId];
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
if (tree.getState().loadingItemChildrens.includes(itemId)) {
|
|
124
|
+
if (tree.getState().loadingItemChildrens.includes(itemId) || skipFetch) {
|
|
125
125
|
return [];
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { TestTree } from "../../test-utils/test-tree";
|
|
3
|
+
import { checkboxesFeature } from "./feature";
|
|
4
|
+
import { CheckedState } from "./types";
|
|
5
|
+
|
|
6
|
+
const factory = TestTree.default({})
|
|
7
|
+
.withFeatures(checkboxesFeature)
|
|
8
|
+
.suits.sync().tree;
|
|
9
|
+
|
|
10
|
+
describe("core-feature/checkboxes", () => {
|
|
11
|
+
it("should initialize with no checked items", async () => {
|
|
12
|
+
const tree = await factory.createTestCaseTree();
|
|
13
|
+
expect(tree.instance.getState().checkedItems).toEqual([]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should check items", async () => {
|
|
17
|
+
const tree = await factory.createTestCaseTree();
|
|
18
|
+
tree.item("x111").setChecked();
|
|
19
|
+
tree.item("x112").setChecked();
|
|
20
|
+
expect(tree.instance.getState().checkedItems).toEqual(["x111", "x112"]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should uncheck an item", async () => {
|
|
24
|
+
const tree = await factory
|
|
25
|
+
.with({ state: { checkedItems: ["x111"] } })
|
|
26
|
+
.createTestCaseTree();
|
|
27
|
+
tree.item("x111").setUnchecked();
|
|
28
|
+
expect(tree.instance.getState().checkedItems).not.toContain("x111");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should toggle checked state", async () => {
|
|
32
|
+
const tree = await factory.createTestCaseTree();
|
|
33
|
+
const item = tree.item("x111");
|
|
34
|
+
|
|
35
|
+
item.toggleCheckedState();
|
|
36
|
+
expect(tree.instance.getState().checkedItems).toContain("x111");
|
|
37
|
+
|
|
38
|
+
item.toggleCheckedState();
|
|
39
|
+
expect(tree.instance.getState().checkedItems).not.toContain("x111");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("props", () => {
|
|
43
|
+
it("should toggle checked state", async () => {
|
|
44
|
+
const tree = await factory.createTestCaseTree();
|
|
45
|
+
const item = tree.item("x111");
|
|
46
|
+
|
|
47
|
+
item.getCheckboxProps().onChange();
|
|
48
|
+
expect(tree.instance.getState().checkedItems).toContain("x111");
|
|
49
|
+
|
|
50
|
+
item.getCheckboxProps().onChange();
|
|
51
|
+
expect(tree.instance.getState().checkedItems).not.toContain("x111");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should return checked state in props", async () => {
|
|
55
|
+
const tree = await factory.createTestCaseTree();
|
|
56
|
+
tree.item("x111").setChecked();
|
|
57
|
+
expect(tree.item("x111").getCheckboxProps().checked).toBe(true);
|
|
58
|
+
expect(tree.item("x112").getCheckboxProps().checked).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should create indeterminate state", async () => {
|
|
62
|
+
const tree = await factory.createTestCaseTree();
|
|
63
|
+
tree.item("x111").setChecked();
|
|
64
|
+
const refObject = { indeterminate: undefined };
|
|
65
|
+
tree.item("x11").getCheckboxProps().ref(refObject);
|
|
66
|
+
expect(refObject.indeterminate).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should not create indeterminate state", async () => {
|
|
70
|
+
const tree = await factory.createTestCaseTree();
|
|
71
|
+
const refObject = { indeterminate: undefined };
|
|
72
|
+
tree.item("x11").getCheckboxProps().ref(refObject);
|
|
73
|
+
expect(refObject.indeterminate).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should handle folder checking when canCheckFolders is true", async () => {
|
|
78
|
+
const tree = await factory
|
|
79
|
+
.with({ canCheckFolders: true })
|
|
80
|
+
.createTestCaseTree();
|
|
81
|
+
|
|
82
|
+
tree.item("x11").setChecked();
|
|
83
|
+
expect(tree.instance.getState().checkedItems).toContain("x11");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should handle folder checking when canCheckFolders is false", async () => {
|
|
87
|
+
const tree = await factory.createTestCaseTree();
|
|
88
|
+
|
|
89
|
+
tree.item("x11").setChecked();
|
|
90
|
+
expect(tree.instance.getState().checkedItems).toEqual(
|
|
91
|
+
expect.arrayContaining(["x111", "x112", "x113", "x114"]),
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should turn folder indeterminate", async () => {
|
|
96
|
+
const tree = await factory.createTestCaseTree();
|
|
97
|
+
|
|
98
|
+
tree.item("x111").setChecked();
|
|
99
|
+
expect(tree.item("x11").getCheckedState()).toBe(CheckedState.Indeterminate);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should turn folder checked if all children are checked", async () => {
|
|
103
|
+
const tree = await factory
|
|
104
|
+
.with({
|
|
105
|
+
isItemFolder: (item) => item.getItemData().length < 4,
|
|
106
|
+
})
|
|
107
|
+
.createTestCaseTree();
|
|
108
|
+
|
|
109
|
+
tree.item("x11").setChecked();
|
|
110
|
+
tree.item("x12").setChecked();
|
|
111
|
+
tree.item("x13").setChecked();
|
|
112
|
+
expect(tree.item("x1").getCheckedState()).toBe(CheckedState.Indeterminate);
|
|
113
|
+
tree.do.selectItem("x14");
|
|
114
|
+
tree.item("x141").setChecked();
|
|
115
|
+
tree.item("x142").setChecked();
|
|
116
|
+
tree.item("x143").setChecked();
|
|
117
|
+
expect(tree.item("x1").getCheckedState()).toBe(CheckedState.Indeterminate);
|
|
118
|
+
tree.item("x144").setChecked();
|
|
119
|
+
expect(tree.item("x1").getCheckedState()).toBe(CheckedState.Checked);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should return correct checked state for items", async () => {
|
|
123
|
+
const tree = await factory.createTestCaseTree();
|
|
124
|
+
const item = tree.instance.getItemInstance("x111");
|
|
125
|
+
|
|
126
|
+
expect(item.getCheckedState()).toBe(CheckedState.Unchecked);
|
|
127
|
+
|
|
128
|
+
item.setChecked();
|
|
129
|
+
expect(item.getCheckedState()).toBe(CheckedState.Checked);
|
|
130
|
+
|
|
131
|
+
item.setUnchecked();
|
|
132
|
+
expect(item.getCheckedState()).toBe(CheckedState.Unchecked);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { FeatureImplementation, TreeInstance } from "../../types/core";
|
|
2
|
+
import { makeStateUpdater } from "../../utils";
|
|
3
|
+
import { CheckedState } from "./types";
|
|
4
|
+
import { throwError } from "../../utilities/errors";
|
|
5
|
+
|
|
6
|
+
const getAllLoadedDescendants = <T>(
|
|
7
|
+
tree: TreeInstance<T>,
|
|
8
|
+
itemId: string,
|
|
9
|
+
): string[] => {
|
|
10
|
+
if (!tree.getConfig().isItemFolder(tree.buildItemInstance(itemId))) {
|
|
11
|
+
return [itemId];
|
|
12
|
+
}
|
|
13
|
+
return tree
|
|
14
|
+
.retrieveChildrenIds(itemId)
|
|
15
|
+
.map((child) => getAllLoadedDescendants(tree, child))
|
|
16
|
+
.flat();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const checkboxesFeature: FeatureImplementation = {
|
|
20
|
+
key: "checkboxes",
|
|
21
|
+
|
|
22
|
+
overwrites: ["selection"],
|
|
23
|
+
|
|
24
|
+
getInitialState: (initialState) => ({
|
|
25
|
+
checkedItems: [],
|
|
26
|
+
...initialState,
|
|
27
|
+
}),
|
|
28
|
+
|
|
29
|
+
getDefaultConfig: (defaultConfig, tree) => {
|
|
30
|
+
const hasAsyncLoader = defaultConfig.features?.some(
|
|
31
|
+
(f) => f.key === "async-data-loader",
|
|
32
|
+
);
|
|
33
|
+
if (hasAsyncLoader && !defaultConfig.canCheckFolders) {
|
|
34
|
+
throwError(`!canCheckFolders not supported with async trees`);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
setCheckedItems: makeStateUpdater("checkedItems", tree),
|
|
38
|
+
canCheckFolders: hasAsyncLoader ?? false,
|
|
39
|
+
...defaultConfig,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
stateHandlerNames: {
|
|
44
|
+
checkedItems: "setCheckedItems",
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
treeInstance: {
|
|
48
|
+
setCheckedItems: ({ tree }, checkedItems) => {
|
|
49
|
+
tree.applySubStateUpdate("checkedItems", checkedItems);
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
itemInstance: {
|
|
54
|
+
getCheckboxProps: ({ item }) => {
|
|
55
|
+
const checkedState = item.getCheckedState();
|
|
56
|
+
return {
|
|
57
|
+
onChange: item.toggleCheckedState,
|
|
58
|
+
checked: checkedState === CheckedState.Checked,
|
|
59
|
+
ref: (r: any) => {
|
|
60
|
+
if (r) {
|
|
61
|
+
r.indeterminate = checkedState === CheckedState.Indeterminate;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
toggleCheckedState: ({ item }) => {
|
|
68
|
+
if (item.getCheckedState() === CheckedState.Checked) {
|
|
69
|
+
item.setUnchecked();
|
|
70
|
+
} else {
|
|
71
|
+
item.setChecked();
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
getCheckedState: ({ item, tree, itemId }) => {
|
|
76
|
+
const { checkedItems } = tree.getState();
|
|
77
|
+
|
|
78
|
+
if (checkedItems.includes(itemId)) {
|
|
79
|
+
return CheckedState.Checked;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (item.isFolder() && !tree.getConfig().canCheckFolders) {
|
|
83
|
+
const descendants = getAllLoadedDescendants(tree, itemId);
|
|
84
|
+
if (descendants.every((d) => checkedItems.includes(d))) {
|
|
85
|
+
return CheckedState.Checked;
|
|
86
|
+
}
|
|
87
|
+
if (descendants.some((d) => checkedItems.includes(d))) {
|
|
88
|
+
return CheckedState.Indeterminate;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return CheckedState.Unchecked;
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
setChecked: ({ item, tree, itemId }) => {
|
|
96
|
+
if (!item.isFolder() || tree.getConfig().canCheckFolders) {
|
|
97
|
+
tree.applySubStateUpdate("checkedItems", (items) => [...items, itemId]);
|
|
98
|
+
} else {
|
|
99
|
+
tree.applySubStateUpdate("checkedItems", (items) => [
|
|
100
|
+
...items,
|
|
101
|
+
...getAllLoadedDescendants(tree, itemId),
|
|
102
|
+
]);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
setUnchecked: ({ item, tree, itemId }) => {
|
|
107
|
+
if (!item.isFolder() || tree.getConfig().canCheckFolders) {
|
|
108
|
+
tree.applySubStateUpdate("checkedItems", (items) =>
|
|
109
|
+
items.filter((id) => id !== itemId),
|
|
110
|
+
);
|
|
111
|
+
} else {
|
|
112
|
+
const descendants = getAllLoadedDescendants(tree, itemId);
|
|
113
|
+
tree.applySubStateUpdate("checkedItems", (items) =>
|
|
114
|
+
items.filter((id) => !descendants.includes(id)),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SetStateFn } from "../../types/core";
|
|
2
|
+
|
|
3
|
+
export enum CheckedState {
|
|
4
|
+
Checked = "checked",
|
|
5
|
+
Unchecked = "unchecked",
|
|
6
|
+
Indeterminate = "indeterminate",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type CheckboxesFeatureDef<T> = {
|
|
10
|
+
state: {
|
|
11
|
+
checkedItems: string[];
|
|
12
|
+
};
|
|
13
|
+
config: {
|
|
14
|
+
setCheckedItems?: SetStateFn<string[]>;
|
|
15
|
+
canCheckFolders?: boolean;
|
|
16
|
+
};
|
|
17
|
+
treeInstance: {
|
|
18
|
+
setCheckedItems: (checkedItems: string[]) => void;
|
|
19
|
+
};
|
|
20
|
+
itemInstance: {
|
|
21
|
+
setChecked: () => void;
|
|
22
|
+
setUnchecked: () => void;
|
|
23
|
+
toggleCheckedState: () => void;
|
|
24
|
+
getCheckedState: () => CheckedState;
|
|
25
|
+
getCheckboxProps: () => Record<string, any>;
|
|
26
|
+
};
|
|
27
|
+
hotkeys: never;
|
|
28
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FeatureImplementation } from "../../types/core";
|
|
2
|
-
import { DndDataRef, DragLineData } from "./types";
|
|
2
|
+
import { DndDataRef, DragLineData, DragTarget } from "./types";
|
|
3
3
|
import {
|
|
4
4
|
canDrop,
|
|
5
5
|
getDragCode,
|
|
@@ -83,10 +83,38 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
83
83
|
: { display: "none" };
|
|
84
84
|
},
|
|
85
85
|
|
|
86
|
-
getContainerProps: ({ prev }, treeLabel) => {
|
|
86
|
+
getContainerProps: ({ prev, tree }, treeLabel) => {
|
|
87
87
|
const prevProps = prev?.(treeLabel);
|
|
88
88
|
return {
|
|
89
89
|
...prevProps,
|
|
90
|
+
|
|
91
|
+
onDragOver: (e: DragEvent) => {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
onDrop: async (e: DragEvent) => {
|
|
96
|
+
// TODO merge implementation with itemInstance.onDrop
|
|
97
|
+
const dataRef = tree.getDataRef<DndDataRef>();
|
|
98
|
+
const target: DragTarget<any> = { item: tree.getRootItem() };
|
|
99
|
+
|
|
100
|
+
if (!canDrop(e.dataTransfer, target, tree)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
const config = tree.getConfig();
|
|
106
|
+
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
107
|
+
|
|
108
|
+
dataRef.current.lastDragCode = undefined;
|
|
109
|
+
tree.applySubStateUpdate("dnd", null);
|
|
110
|
+
|
|
111
|
+
if (draggedItems) {
|
|
112
|
+
await config.onDrop?.(draggedItems, target);
|
|
113
|
+
} else if (e.dataTransfer) {
|
|
114
|
+
await config.onDropForeignDragObject?.(e.dataTransfer, target);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
|
|
90
118
|
style: {
|
|
91
119
|
...prevProps?.style,
|
|
92
120
|
position: "relative",
|
|
@@ -101,6 +129,8 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
101
129
|
|
|
102
130
|
draggable: true,
|
|
103
131
|
|
|
132
|
+
onDragEnter: (e: DragEvent) => e.preventDefault(),
|
|
133
|
+
|
|
104
134
|
onDragStart: (e: DragEvent) => {
|
|
105
135
|
const selectedItems = tree.getSelectedItems();
|
|
106
136
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
@@ -115,6 +145,11 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
115
145
|
return;
|
|
116
146
|
}
|
|
117
147
|
|
|
148
|
+
if (config.setDragImage) {
|
|
149
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
150
|
+
e.dataTransfer?.setDragImage(imgElement, xOffset ?? 0, yOffset ?? 0);
|
|
151
|
+
}
|
|
152
|
+
|
|
118
153
|
if (config.createForeignDragObject) {
|
|
119
154
|
const { format, data } = config.createForeignDragObject(items);
|
|
120
155
|
e.dataTransfer?.setData(format, data);
|
|
@@ -186,6 +221,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
186
221
|
},
|
|
187
222
|
|
|
188
223
|
onDrop: async (e: DragEvent) => {
|
|
224
|
+
e.stopPropagation();
|
|
189
225
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
190
226
|
const target = getDragTarget(e, item, tree);
|
|
191
227
|
|
|
@@ -58,6 +58,11 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
58
58
|
format: string;
|
|
59
59
|
data: any;
|
|
60
60
|
};
|
|
61
|
+
setDragImage?: (items: ItemInstance<T>[]) => {
|
|
62
|
+
imgElement: Element;
|
|
63
|
+
xOffset?: number;
|
|
64
|
+
yOffset?: number;
|
|
65
|
+
};
|
|
61
66
|
canDropForeignDragObject?: (
|
|
62
67
|
dataTransfer: DataTransfer,
|
|
63
68
|
target: DragTarget<T>,
|
|
@@ -36,6 +36,8 @@ export type MainFeatureDef<T = any> = {
|
|
|
36
36
|
stateName: K,
|
|
37
37
|
updater: Updater<TreeState<T>[K]>,
|
|
38
38
|
) => void;
|
|
39
|
+
/** @internal */
|
|
40
|
+
buildItemInstance: (itemId: string) => ItemInstance<T>;
|
|
39
41
|
setState: SetStateFn<TreeState<T>>;
|
|
40
42
|
getState: () => TreeState<T>;
|
|
41
43
|
setConfig: SetStateFn<TreeConfig<T>>;
|
|
@@ -82,6 +82,11 @@ export const treeFeature: FeatureImplementation<any> = {
|
|
|
82
82
|
);
|
|
83
83
|
},
|
|
84
84
|
|
|
85
|
+
getRootItem: ({ tree }) => {
|
|
86
|
+
const { rootItemId } = tree.getConfig();
|
|
87
|
+
return tree.getItemInstance(rootItemId);
|
|
88
|
+
},
|
|
89
|
+
|
|
85
90
|
focusNextItem: ({ tree }) => {
|
|
86
91
|
const focused = tree.getFocusedItem().getItemMeta();
|
|
87
92
|
if (!focused) return;
|
|
@@ -20,7 +20,7 @@ export type TreeFeatureDef<T> = {
|
|
|
20
20
|
focusedItem: string | null;
|
|
21
21
|
};
|
|
22
22
|
config: {
|
|
23
|
-
isItemFolder: (item: ItemInstance<T>) => boolean;
|
|
23
|
+
isItemFolder: (item: ItemInstance<T>) => boolean; // TODO:breaking use item data as payload
|
|
24
24
|
getItemName: (item: ItemInstance<T>) => string;
|
|
25
25
|
|
|
26
26
|
onPrimaryAction?: (item: ItemInstance<T>) => void;
|
|
@@ -33,7 +33,8 @@ export type TreeFeatureDef<T> = {
|
|
|
33
33
|
/** @internal */
|
|
34
34
|
getItemsMeta: () => ItemMeta[];
|
|
35
35
|
|
|
36
|
-
getFocusedItem: () => ItemInstance<
|
|
36
|
+
getFocusedItem: () => ItemInstance<T>;
|
|
37
|
+
getRootItem: () => ItemInstance<T>;
|
|
37
38
|
focusNextItem: () => void;
|
|
38
39
|
focusPreviousItem: () => void;
|
|
39
40
|
updateDomFocus: () => void;
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { MainFeatureDef, InstanceBuilder } from "./features/main/types";
|
|
|
6
6
|
export * from "./features/drag-and-drop/types";
|
|
7
7
|
export * from "./features/keyboard-drag-and-drop/types";
|
|
8
8
|
export * from "./features/selection/types";
|
|
9
|
+
export * from "./features/checkboxes/types";
|
|
9
10
|
export * from "./features/async-data-loader/types";
|
|
10
11
|
export * from "./features/sync-data-loader/types";
|
|
11
12
|
export * from "./features/hotkeys-core/types";
|
|
@@ -15,6 +16,7 @@ export * from "./features/expand-all/types";
|
|
|
15
16
|
export * from "./features/prop-memoization/types";
|
|
16
17
|
|
|
17
18
|
export * from "./features/selection/feature";
|
|
19
|
+
export * from "./features/checkboxes/feature";
|
|
18
20
|
export * from "./features/hotkeys-core/feature";
|
|
19
21
|
export * from "./features/async-data-loader/feature";
|
|
20
22
|
export * from "./features/sync-data-loader/feature";
|
package/src/types/core.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { RenamingFeatureDef } from "../features/renaming/types";
|
|
|
13
13
|
import { ExpandAllFeatureDef } from "../features/expand-all/types";
|
|
14
14
|
import { PropMemoizationFeatureDef } from "../features/prop-memoization/types";
|
|
15
15
|
import { KeyboardDragAndDropFeatureDef } from "../features/keyboard-drag-and-drop/types";
|
|
16
|
+
import { CheckboxesFeatureDef } from "../features/checkboxes/types";
|
|
16
17
|
|
|
17
18
|
export type Updater<T> = T | ((old: T) => T);
|
|
18
19
|
export type SetStateFn<T> = (updaterOrValue: Updater<T>) => void;
|
|
@@ -53,6 +54,7 @@ export type RegisteredFeatures<T> =
|
|
|
53
54
|
| MainFeatureDef<T>
|
|
54
55
|
| TreeFeatureDef<T>
|
|
55
56
|
| SelectionFeatureDef<T>
|
|
57
|
+
| CheckboxesFeatureDef<T>
|
|
56
58
|
| DragAndDropFeatureDef<T>
|
|
57
59
|
| KeyboardDragAndDropFeatureDef<T>
|
|
58
60
|
| HotkeysCoreFeatureDef<T>
|