@headless-tree/core 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/lib/cjs/core/build-static-instance.js +1 -2
- package/lib/cjs/core/create-tree.js +7 -4
- package/lib/cjs/features/async-data-loader/feature.d.ts +1 -4
- package/lib/cjs/features/async-data-loader/feature.js +5 -7
- package/lib/cjs/features/async-data-loader/types.d.ts +2 -5
- package/lib/cjs/features/drag-and-drop/feature.d.ts +2 -3
- package/lib/cjs/features/drag-and-drop/feature.js +27 -24
- package/lib/cjs/features/drag-and-drop/types.d.ts +3 -3
- package/lib/cjs/features/drag-and-drop/utils.d.ts +1 -1
- package/lib/cjs/features/drag-and-drop/utils.js +4 -4
- package/lib/cjs/features/expand-all/feature.d.ts +1 -5
- package/lib/cjs/features/hotkeys-core/feature.d.ts +1 -3
- package/lib/cjs/features/prop-memoization/feature.d.ts +2 -0
- package/lib/cjs/features/prop-memoization/feature.js +48 -0
- package/lib/cjs/features/prop-memoization/types.d.ts +10 -0
- package/lib/cjs/features/prop-memoization/types.js +2 -0
- package/lib/cjs/features/renaming/feature.d.ts +1 -4
- package/lib/cjs/features/renaming/feature.js +8 -9
- package/lib/cjs/features/renaming/types.d.ts +1 -1
- package/lib/cjs/features/search/feature.d.ts +1 -4
- package/lib/cjs/features/selection/feature.d.ts +1 -4
- package/lib/cjs/features/selection/feature.js +35 -25
- package/lib/cjs/features/selection/types.d.ts +1 -1
- package/lib/cjs/features/sync-data-loader/feature.d.ts +1 -3
- package/lib/cjs/features/tree/feature.d.ts +1 -6
- package/lib/cjs/features/tree/feature.js +40 -57
- package/lib/cjs/features/tree/types.d.ts +0 -5
- package/lib/cjs/index.d.ts +2 -0
- package/lib/cjs/index.js +2 -0
- package/lib/cjs/mddocs-entry.d.ts +10 -0
- package/lib/cjs/test-utils/test-tree-do.d.ts +1 -1
- package/lib/cjs/test-utils/test-tree-expect.d.ts +1 -1
- package/lib/cjs/test-utils/test-tree-expect.js +1 -1
- package/lib/cjs/test-utils/test-tree.d.ts +1 -1
- package/lib/cjs/test-utils/test-tree.js +9 -1
- package/lib/cjs/types/core.d.ts +29 -30
- package/lib/esm/core/build-static-instance.js +1 -2
- package/lib/esm/core/create-tree.js +7 -4
- package/lib/esm/features/async-data-loader/feature.d.ts +1 -4
- package/lib/esm/features/async-data-loader/feature.js +5 -7
- package/lib/esm/features/async-data-loader/types.d.ts +2 -5
- package/lib/esm/features/drag-and-drop/feature.d.ts +2 -3
- package/lib/esm/features/drag-and-drop/feature.js +27 -24
- package/lib/esm/features/drag-and-drop/types.d.ts +3 -3
- package/lib/esm/features/drag-and-drop/utils.d.ts +1 -1
- package/lib/esm/features/drag-and-drop/utils.js +4 -4
- package/lib/esm/features/expand-all/feature.d.ts +1 -5
- package/lib/esm/features/hotkeys-core/feature.d.ts +1 -3
- package/lib/esm/features/prop-memoization/feature.d.ts +2 -0
- package/lib/esm/features/prop-memoization/feature.js +45 -0
- package/lib/esm/features/prop-memoization/types.d.ts +10 -0
- package/lib/esm/features/prop-memoization/types.js +1 -0
- package/lib/esm/features/renaming/feature.d.ts +1 -4
- package/lib/esm/features/renaming/feature.js +8 -9
- package/lib/esm/features/renaming/types.d.ts +1 -1
- package/lib/esm/features/search/feature.d.ts +1 -4
- package/lib/esm/features/selection/feature.d.ts +1 -4
- package/lib/esm/features/selection/feature.js +35 -25
- package/lib/esm/features/selection/types.d.ts +1 -1
- package/lib/esm/features/sync-data-loader/feature.d.ts +1 -3
- package/lib/esm/features/tree/feature.d.ts +1 -6
- package/lib/esm/features/tree/feature.js +40 -57
- package/lib/esm/features/tree/types.d.ts +0 -5
- package/lib/esm/index.d.ts +2 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/mddocs-entry.d.ts +10 -0
- package/lib/esm/test-utils/test-tree-do.d.ts +1 -1
- package/lib/esm/test-utils/test-tree-expect.d.ts +1 -1
- package/lib/esm/test-utils/test-tree-expect.js +1 -1
- package/lib/esm/test-utils/test-tree.d.ts +1 -1
- package/lib/esm/test-utils/test-tree.js +9 -1
- package/lib/esm/types/core.d.ts +29 -30
- package/package.json +1 -1
- package/src/core/build-proxified-instance.ts +5 -3
- package/src/core/build-static-instance.ts +1 -2
- package/src/core/core.spec.ts +210 -0
- package/src/core/create-tree.ts +13 -16
- package/src/features/async-data-loader/async-data-loader.spec.ts +12 -31
- package/src/features/async-data-loader/feature.ts +8 -20
- package/src/features/async-data-loader/types.ts +2 -6
- package/src/features/drag-and-drop/drag-and-drop.spec.ts +4 -3
- package/src/features/drag-and-drop/feature.ts +87 -86
- package/src/features/drag-and-drop/types.ts +4 -4
- package/src/features/drag-and-drop/utils.ts +4 -4
- package/src/features/expand-all/expand-all.spec.ts +5 -1
- package/src/features/expand-all/feature.ts +1 -12
- package/src/features/hotkeys-core/feature.ts +4 -13
- package/src/features/prop-memoization/feature.ts +51 -0
- package/src/features/prop-memoization/prop-memoization.spec.ts +68 -0
- package/src/features/prop-memoization/types.ts +11 -0
- package/src/features/renaming/feature.ts +11 -20
- package/src/features/renaming/renaming.spec.ts +11 -9
- package/src/features/renaming/types.ts +1 -1
- package/src/features/search/feature.ts +2 -8
- package/src/features/search/search.spec.ts +3 -1
- package/src/features/selection/feature.ts +45 -47
- package/src/features/selection/selection.spec.ts +13 -14
- package/src/features/selection/types.ts +0 -2
- package/src/features/sync-data-loader/feature.ts +1 -7
- package/src/features/tree/feature.ts +47 -85
- package/src/features/tree/tree.spec.ts +24 -64
- package/src/features/tree/types.ts +0 -6
- package/src/index.ts +2 -0
- package/src/mddocs-entry.ts +13 -0
- package/src/test-utils/test-tree-expect.ts +1 -1
- package/src/test-utils/test-tree.ts +11 -1
- package/src/types/core.ts +56 -147
|
@@ -17,7 +17,6 @@ export const treeFeature = {
|
|
|
17
17
|
focusedItem: "setFocusedItem",
|
|
18
18
|
},
|
|
19
19
|
treeInstance: {
|
|
20
|
-
isItemExpanded: ({ tree }, itemId) => tree.getState().expandedItems.includes(itemId),
|
|
21
20
|
getItemsMeta: ({ tree }) => {
|
|
22
21
|
const { rootItemId } = tree.getConfig();
|
|
23
22
|
const { expandedItems } = tree.getState();
|
|
@@ -49,44 +48,22 @@ export const treeFeature = {
|
|
|
49
48
|
}
|
|
50
49
|
return flatItems;
|
|
51
50
|
},
|
|
52
|
-
expandItem: ({ tree }, itemId) => {
|
|
53
|
-
var _a;
|
|
54
|
-
if (!tree.getItemInstance(itemId).isFolder()) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if ((_a = tree.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
tree.applySubStateUpdate("expandedItems", (expandedItems) => [
|
|
61
|
-
...expandedItems,
|
|
62
|
-
itemId,
|
|
63
|
-
]);
|
|
64
|
-
tree.rebuildTree();
|
|
65
|
-
},
|
|
66
|
-
collapseItem: ({ tree }, itemId) => {
|
|
67
|
-
if (!tree.getItemInstance(itemId).isFolder()) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
tree.applySubStateUpdate("expandedItems", (expandedItems) => expandedItems.filter((id) => id !== itemId));
|
|
71
|
-
tree.rebuildTree();
|
|
72
|
-
},
|
|
73
51
|
// TODO memo
|
|
74
52
|
getFocusedItem: ({ tree }) => {
|
|
75
53
|
var _a, _b;
|
|
76
54
|
return ((_b = tree.getItemInstance((_a = tree.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : tree.getItems()[0]);
|
|
77
55
|
},
|
|
78
|
-
focusItem: ({ tree }, itemId) => {
|
|
79
|
-
tree.applySubStateUpdate("focusedItem", itemId);
|
|
80
|
-
},
|
|
81
56
|
focusNextItem: ({ tree }) => {
|
|
57
|
+
var _a;
|
|
82
58
|
const { index } = tree.getFocusedItem().getItemMeta();
|
|
83
59
|
const nextIndex = Math.min(index + 1, tree.getItems().length - 1);
|
|
84
|
-
|
|
60
|
+
(_a = tree.getItems()[nextIndex]) === null || _a === void 0 ? void 0 : _a.setFocused();
|
|
85
61
|
},
|
|
86
62
|
focusPreviousItem: ({ tree }) => {
|
|
63
|
+
var _a;
|
|
87
64
|
const { index } = tree.getFocusedItem().getItemMeta();
|
|
88
65
|
const nextIndex = Math.max(index - 1, 0);
|
|
89
|
-
|
|
66
|
+
(_a = tree.getItems()[nextIndex]) === null || _a === void 0 ? void 0 : _a.setFocused();
|
|
90
67
|
},
|
|
91
68
|
updateDomFocus: ({ tree }) => {
|
|
92
69
|
// Required because if the state is managed outside in react, the state only updated during next render
|
|
@@ -101,7 +78,8 @@ export const treeFeature = {
|
|
|
101
78
|
focusedElement.focus();
|
|
102
79
|
}));
|
|
103
80
|
},
|
|
104
|
-
|
|
81
|
+
// TODO add label parameter
|
|
82
|
+
getContainerProps: ({ prev, tree }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { role: "tree", "aria-label": "", ref: tree.registerElement })),
|
|
105
83
|
// relevant for hotkeys of this feature
|
|
106
84
|
isSearchOpen: () => false,
|
|
107
85
|
},
|
|
@@ -112,10 +90,10 @@ export const treeFeature = {
|
|
|
112
90
|
yield poll(() => item.getElement() !== null, 20);
|
|
113
91
|
(_d = item.getElement()) === null || _d === void 0 ? void 0 : _d.scrollIntoView(scrollIntoViewArg);
|
|
114
92
|
}),
|
|
115
|
-
getId: ({
|
|
93
|
+
getId: ({ itemId }) => itemId,
|
|
116
94
|
getProps: ({ item, prev }) => {
|
|
117
95
|
const itemMeta = item.getItemMeta();
|
|
118
|
-
return Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { 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:
|
|
96
|
+
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) => {
|
|
119
97
|
item.setFocused();
|
|
120
98
|
item.primaryAction();
|
|
121
99
|
if (e.ctrlKey || e.shiftKey || e.metaKey) {
|
|
@@ -130,18 +108,37 @@ export const treeFeature = {
|
|
|
130
108
|
else {
|
|
131
109
|
item.expand();
|
|
132
110
|
}
|
|
133
|
-
}
|
|
111
|
+
} });
|
|
112
|
+
},
|
|
113
|
+
expand: ({ tree, item, itemId }) => {
|
|
114
|
+
var _a;
|
|
115
|
+
if (!item.isFolder()) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if ((_a = tree.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
tree.applySubStateUpdate("expandedItems", (expandedItems) => [
|
|
122
|
+
...expandedItems,
|
|
123
|
+
itemId,
|
|
124
|
+
]);
|
|
125
|
+
tree.rebuildTree();
|
|
134
126
|
},
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
collapse: ({ tree, item, itemId }) => {
|
|
128
|
+
if (!item.isFolder()) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
tree.applySubStateUpdate("expandedItems", (expandedItems) => expandedItems.filter((id) => id !== itemId));
|
|
132
|
+
tree.rebuildTree();
|
|
133
|
+
},
|
|
134
|
+
getItemData: ({ tree, itemId }) => tree.retrieveItemData(itemId),
|
|
138
135
|
equals: ({ item }, other) => item.getId() === (other === null || other === void 0 ? void 0 : other.getId()),
|
|
139
|
-
isExpanded: ({ tree,
|
|
136
|
+
isExpanded: ({ tree, itemId }) => tree.getState().expandedItems.includes(itemId),
|
|
140
137
|
isDescendentOf: ({ item }, parentId) => {
|
|
141
138
|
const parent = item.getParent();
|
|
142
139
|
return Boolean((parent === null || parent === void 0 ? void 0 : parent.getId()) === parentId || (parent === null || parent === void 0 ? void 0 : parent.isDescendentOf(parentId)));
|
|
143
140
|
},
|
|
144
|
-
isFocused: ({ tree, item }) => tree.getState().focusedItem ===
|
|
141
|
+
isFocused: ({ tree, item, itemId }) => tree.getState().focusedItem === itemId ||
|
|
145
142
|
(tree.getState().focusedItem === null && item.getItemMeta().index === 0),
|
|
146
143
|
isFolder: ({ tree, item }) => item.getItemMeta().level === -1 ||
|
|
147
144
|
tree.getConfig().isItemFolder(item),
|
|
@@ -149,12 +146,13 @@ export const treeFeature = {
|
|
|
149
146
|
const config = tree.getConfig();
|
|
150
147
|
return config.getItemName(item);
|
|
151
148
|
},
|
|
152
|
-
setFocused: ({ tree,
|
|
149
|
+
setFocused: ({ tree, itemId }) => {
|
|
150
|
+
tree.applySubStateUpdate("focusedItem", itemId);
|
|
151
|
+
},
|
|
153
152
|
primaryAction: ({ tree, item }) => { var _a, _b; return (_b = (_a = tree.getConfig()).onPrimaryAction) === null || _b === void 0 ? void 0 : _b.call(_a, item); },
|
|
154
153
|
getParent: ({ tree, item }) => item.getItemMeta().parentId
|
|
155
154
|
? tree.getItemInstance(item.getItemMeta().parentId)
|
|
156
155
|
: undefined,
|
|
157
|
-
// TODO remove
|
|
158
156
|
getIndexInParent: ({ item }) => item.getItemMeta().posInSet,
|
|
159
157
|
getChildren: ({ tree, item }) => tree
|
|
160
158
|
.retrieveChildrenIds(item.getItemMeta().itemId)
|
|
@@ -162,23 +160,6 @@ export const treeFeature = {
|
|
|
162
160
|
getTree: ({ tree }) => tree,
|
|
163
161
|
getItemAbove: ({ tree, item }) => tree.getItems()[item.getItemMeta().index - 1],
|
|
164
162
|
getItemBelow: ({ tree, item }) => tree.getItems()[item.getItemMeta().index + 1],
|
|
165
|
-
getMemoizedProp: ({ item }, name, create, deps) => {
|
|
166
|
-
var _a, _b, _c, _d, _e;
|
|
167
|
-
var _f, _g;
|
|
168
|
-
const data = item.getDataRef();
|
|
169
|
-
const memoizedValue = (_a = data.current.memoizedValues) === null || _a === void 0 ? void 0 : _a[name];
|
|
170
|
-
if (memoizedValue &&
|
|
171
|
-
(!deps ||
|
|
172
|
-
((_c = (_b = data.current.memoizedDeps) === null || _b === void 0 ? void 0 : _b[name]) === null || _c === void 0 ? void 0 : _c.every((d, i) => d === deps[i])))) {
|
|
173
|
-
return memoizedValue;
|
|
174
|
-
}
|
|
175
|
-
(_d = (_f = data.current).memoizedDeps) !== null && _d !== void 0 ? _d : (_f.memoizedDeps = {});
|
|
176
|
-
(_e = (_g = data.current).memoizedValues) !== null && _e !== void 0 ? _e : (_g.memoizedValues = {});
|
|
177
|
-
const value = create();
|
|
178
|
-
data.current.memoizedDeps[name] = deps;
|
|
179
|
-
data.current.memoizedValues[name] = value;
|
|
180
|
-
return value;
|
|
181
|
-
},
|
|
182
163
|
},
|
|
183
164
|
hotkeys: {
|
|
184
165
|
focusNextItem: {
|
|
@@ -234,14 +215,16 @@ export const treeFeature = {
|
|
|
234
215
|
focusFirstItem: {
|
|
235
216
|
hotkey: "Home",
|
|
236
217
|
handler: (e, tree) => {
|
|
237
|
-
|
|
218
|
+
var _a;
|
|
219
|
+
(_a = tree.getItems()[0]) === null || _a === void 0 ? void 0 : _a.setFocused();
|
|
238
220
|
tree.updateDomFocus();
|
|
239
221
|
},
|
|
240
222
|
},
|
|
241
223
|
focusLastItem: {
|
|
242
224
|
hotkey: "End",
|
|
243
225
|
handler: (e, tree) => {
|
|
244
|
-
|
|
226
|
+
var _a;
|
|
227
|
+
(_a = tree.getItems()[tree.getItems().length - 1]) === null || _a === void 0 ? void 0 : _a.setFocused();
|
|
245
228
|
tree.updateDomFocus();
|
|
246
229
|
},
|
|
247
230
|
},
|
|
@@ -27,10 +27,6 @@ export type TreeFeatureDef<T> = {
|
|
|
27
27
|
treeInstance: {
|
|
28
28
|
/** @internal */
|
|
29
29
|
getItemsMeta: () => ItemMeta[];
|
|
30
|
-
expandItem: (itemId: string) => void;
|
|
31
|
-
collapseItem: (itemId: string) => void;
|
|
32
|
-
isItemExpanded: (itemId: string) => boolean;
|
|
33
|
-
focusItem: (itemId: string) => void;
|
|
34
30
|
getFocusedItem: () => ItemInstance<any>;
|
|
35
31
|
focusNextItem: () => void;
|
|
36
32
|
focusPreviousItem: () => void;
|
|
@@ -57,7 +53,6 @@ export type TreeFeatureDef<T> = {
|
|
|
57
53
|
getTree: () => TreeInstance<T>;
|
|
58
54
|
getItemAbove: () => ItemInstance<T> | undefined;
|
|
59
55
|
getItemBelow: () => ItemInstance<T> | undefined;
|
|
60
|
-
getMemoizedProp: <X>(name: string, create: () => X, deps?: any[]) => X;
|
|
61
56
|
scrollTo: (scrollIntoViewArg?: boolean | ScrollIntoViewOptions) => Promise<void>;
|
|
62
57
|
};
|
|
63
58
|
hotkeys: "focusNextItem" | "focusPreviousItem" | "expandOrDown" | "collapseOrUp" | "focusFirstItem" | "focusLastItem";
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./features/hotkeys-core/types";
|
|
|
10
10
|
export * from "./features/search/types";
|
|
11
11
|
export * from "./features/renaming/types";
|
|
12
12
|
export * from "./features/expand-all/types";
|
|
13
|
+
export * from "./features/prop-memoization/types";
|
|
13
14
|
export * from "./features/selection/feature";
|
|
14
15
|
export * from "./features/hotkeys-core/feature";
|
|
15
16
|
export * from "./features/async-data-loader/feature";
|
|
@@ -18,6 +19,7 @@ export * from "./features/drag-and-drop/feature";
|
|
|
18
19
|
export * from "./features/search/feature";
|
|
19
20
|
export * from "./features/renaming/feature";
|
|
20
21
|
export * from "./features/expand-all/feature";
|
|
22
|
+
export * from "./features/prop-memoization/feature";
|
|
21
23
|
export * from "./utilities/create-on-drop-handler";
|
|
22
24
|
export * from "./utilities/insert-items-at-target";
|
|
23
25
|
export * from "./utilities/remove-items-from-parents";
|
package/lib/esm/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./features/hotkeys-core/types";
|
|
|
9
9
|
export * from "./features/search/types";
|
|
10
10
|
export * from "./features/renaming/types";
|
|
11
11
|
export * from "./features/expand-all/types";
|
|
12
|
+
export * from "./features/prop-memoization/types";
|
|
12
13
|
export * from "./features/selection/feature";
|
|
13
14
|
export * from "./features/hotkeys-core/feature";
|
|
14
15
|
export * from "./features/async-data-loader/feature";
|
|
@@ -17,6 +18,7 @@ export * from "./features/drag-and-drop/feature";
|
|
|
17
18
|
export * from "./features/search/feature";
|
|
18
19
|
export * from "./features/renaming/feature";
|
|
19
20
|
export * from "./features/expand-all/feature";
|
|
21
|
+
export * from "./features/prop-memoization/feature";
|
|
20
22
|
export * from "./utilities/create-on-drop-handler";
|
|
21
23
|
export * from "./utilities/insert-items-at-target";
|
|
22
24
|
export * from "./utilities/remove-items-from-parents";
|
|
@@ -8,6 +8,7 @@ import { SearchFeatureDef } from "./features/search/types";
|
|
|
8
8
|
import { SelectionFeatureDef } from "./features/selection/types";
|
|
9
9
|
import { SyncDataLoaderFeatureDef } from "./features/sync-data-loader/types";
|
|
10
10
|
import { TreeFeatureDef } from "./features/tree/types";
|
|
11
|
+
import { PropMemoizationFeatureDef } from "./features/prop-memoization/types";
|
|
11
12
|
export * from ".";
|
|
12
13
|
/** @interface */
|
|
13
14
|
export type AsyncDataLoaderFeatureConfig<T> = AsyncDataLoaderFeatureDef<T>["config"];
|
|
@@ -55,6 +56,15 @@ export type MainFeatureTreeInstance = MainFeatureDef["treeInstance"];
|
|
|
55
56
|
export type MainFeatureItemInstance = MainFeatureDef["itemInstance"];
|
|
56
57
|
export type MainFeatureHotkeys = MainFeatureDef["hotkeys"];
|
|
57
58
|
/** @interface */
|
|
59
|
+
export type PropMemoizationConfig = PropMemoizationFeatureDef["config"];
|
|
60
|
+
/** @interface */
|
|
61
|
+
export type PropMemoizationState = PropMemoizationFeatureDef["state"];
|
|
62
|
+
/** @interface */
|
|
63
|
+
export type PropMemoizationTreeInstance = PropMemoizationFeatureDef["treeInstance"];
|
|
64
|
+
/** @interface */
|
|
65
|
+
export type PropMemoizationItemInstance = PropMemoizationFeatureDef["itemInstance"];
|
|
66
|
+
export type PropMemoizationHotkeys = PropMemoizationFeatureDef["hotkeys"];
|
|
67
|
+
/** @interface */
|
|
58
68
|
export type RenamingFeatureConfig<T> = RenamingFeatureDef<T>["config"];
|
|
59
69
|
/** @interface */
|
|
60
70
|
export type RenamingFeatureState<T> = RenamingFeatureDef<T>["state"];
|
|
@@ -3,7 +3,7 @@ import { TestTree } from "./test-tree";
|
|
|
3
3
|
import { HotkeyName } from "../types/core";
|
|
4
4
|
export declare class TestTreeDo<T> {
|
|
5
5
|
protected tree: TestTree<T>;
|
|
6
|
-
protected itemInstance(itemId: string): import("../types/core").ItemInstance<
|
|
6
|
+
protected itemInstance(itemId: string): import("../types/core").ItemInstance<T>;
|
|
7
7
|
protected itemProps(itemId: string): Record<string, any>;
|
|
8
8
|
constructor(tree: TestTree<T>);
|
|
9
9
|
selectItem(id: string): void;
|
|
@@ -3,7 +3,7 @@ import { TestTree } from "./test-tree";
|
|
|
3
3
|
import { DropTarget } from "../features/drag-and-drop/types";
|
|
4
4
|
export declare class TestTreeExpect<T> {
|
|
5
5
|
private tree;
|
|
6
|
-
protected itemInstance(itemId: string): import("..").ItemInstance<
|
|
6
|
+
protected itemInstance(itemId: string): import("..").ItemInstance<T>;
|
|
7
7
|
protected itemProps(itemId: string): Record<string, any>;
|
|
8
8
|
constructor(tree: TestTree<T>);
|
|
9
9
|
foldersExpanded(...itemIds: string[]): void;
|
|
@@ -37,7 +37,7 @@ export declare class TestTree<T = string> {
|
|
|
37
37
|
createTestCaseTree(): Promise<this>;
|
|
38
38
|
withFeatures(...features: any): TestTree<T>;
|
|
39
39
|
mockedHandler(handlerName: keyof TreeConfig<T>): import("vitest").Mock<(...args: any[]) => any>;
|
|
40
|
-
item(itemId: string): import("../types/core").ItemInstance<
|
|
40
|
+
item(itemId: string): import("../types/core").ItemInstance<T>;
|
|
41
41
|
reset(): void;
|
|
42
42
|
debug(): void;
|
|
43
43
|
setElementBoundingBox(itemId: string, bb?: Partial<DOMRect>): void;
|
|
@@ -160,10 +160,18 @@ export class TestTree {
|
|
|
160
160
|
}
|
|
161
161
|
setElementBoundingBox(itemId, bb = {
|
|
162
162
|
left: 0,
|
|
163
|
-
|
|
163
|
+
width: 100,
|
|
164
164
|
top: 0,
|
|
165
165
|
height: 20,
|
|
166
166
|
}) {
|
|
167
|
+
this.instance.registerElement({
|
|
168
|
+
getBoundingClientRect: () => ({
|
|
169
|
+
left: 0,
|
|
170
|
+
width: 100,
|
|
171
|
+
top: 0,
|
|
172
|
+
height: 10000,
|
|
173
|
+
}),
|
|
174
|
+
});
|
|
167
175
|
this.instance.getItemInstance(itemId).registerElement({
|
|
168
176
|
getBoundingClientRect: () => bb,
|
|
169
177
|
});
|
package/lib/esm/types/core.d.ts
CHANGED
|
@@ -8,14 +8,14 @@ import { AsyncDataLoaderFeatureDef } from "../features/async-data-loader/types";
|
|
|
8
8
|
import { SearchFeatureDef } from "../features/search/types";
|
|
9
9
|
import { RenamingFeatureDef } from "../features/renaming/types";
|
|
10
10
|
import { ExpandAllFeatureDef } from "../features/expand-all/types";
|
|
11
|
+
import { PropMemoizationFeatureDef } from "../features/prop-memoization/types";
|
|
11
12
|
export type Updater<T> = T | ((old: T) => T);
|
|
12
13
|
export type SetStateFn<T> = (updaterOrValue: Updater<T>) => void;
|
|
13
|
-
type FunctionMap = Record<string, (...args: any[]) => any>;
|
|
14
14
|
export type FeatureDef = {
|
|
15
15
|
state: any;
|
|
16
16
|
config: any;
|
|
17
|
-
treeInstance:
|
|
18
|
-
itemInstance:
|
|
17
|
+
treeInstance: any;
|
|
18
|
+
itemInstance: any;
|
|
19
19
|
hotkeys: string;
|
|
20
20
|
};
|
|
21
21
|
export type EmptyFeatureDef = {
|
|
@@ -26,8 +26,6 @@ export type EmptyFeatureDef = {
|
|
|
26
26
|
hotkeys: never;
|
|
27
27
|
};
|
|
28
28
|
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;
|
|
29
|
-
export type DefaultFeatures<T> = MainFeatureDef | TreeFeatureDef<T>;
|
|
30
|
-
export type FeatureDefs<T> = MainFeatureDef | TreeFeatureDef<T> | SelectionFeatureDef<T> | DragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef;
|
|
31
29
|
type MergedFeatures<F extends FeatureDef> = {
|
|
32
30
|
state: UnionToIntersection<F["state"]>;
|
|
33
31
|
config: UnionToIntersection<F["config"]>;
|
|
@@ -35,49 +33,50 @@ type MergedFeatures<F extends FeatureDef> = {
|
|
|
35
33
|
itemInstance: UnionToIntersection<F["itemInstance"]>;
|
|
36
34
|
hotkeys: F["hotkeys"];
|
|
37
35
|
};
|
|
38
|
-
type
|
|
36
|
+
export type RegisteredFeatures<T> = MainFeatureDef<T> | TreeFeatureDef<T> | SelectionFeatureDef<T> | DragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef | PropMemoizationFeatureDef;
|
|
37
|
+
type TreeStateType<T> = MergedFeatures<RegisteredFeatures<T>>["state"];
|
|
39
38
|
export interface TreeState<T> extends TreeStateType<T> {
|
|
40
39
|
}
|
|
41
|
-
type TreeConfigType<T> =
|
|
40
|
+
type TreeConfigType<T> = MergedFeatures<RegisteredFeatures<T>>["config"];
|
|
42
41
|
export interface TreeConfig<T> extends TreeConfigType<T> {
|
|
43
42
|
}
|
|
44
|
-
type TreeInstanceType<T> =
|
|
43
|
+
type TreeInstanceType<T> = MergedFeatures<RegisteredFeatures<T>>["treeInstance"];
|
|
45
44
|
export interface TreeInstance<T> extends TreeInstanceType<T> {
|
|
46
45
|
}
|
|
47
|
-
type ItemInstanceType<T> =
|
|
46
|
+
type ItemInstanceType<T> = MergedFeatures<RegisteredFeatures<T>>["itemInstance"];
|
|
48
47
|
export interface ItemInstance<T> extends ItemInstanceType<T> {
|
|
49
48
|
}
|
|
50
|
-
export type HotkeyName
|
|
51
|
-
export type HotkeysConfig<T
|
|
52
|
-
export type CustomHotkeysConfig<T
|
|
49
|
+
export type HotkeyName = MergedFeatures<RegisteredFeatures<any>>["hotkeys"];
|
|
50
|
+
export type HotkeysConfig<T> = Record<HotkeyName, HotkeyConfig<T>>;
|
|
51
|
+
export type CustomHotkeysConfig<T> = Partial<Record<HotkeyName | `custom${string}`, Partial<HotkeyConfig<T>>>>;
|
|
53
52
|
type MayReturnNull<T extends (...x: any[]) => any> = (...args: Parameters<T>) => ReturnType<T> | null;
|
|
54
|
-
export type ItemInstanceOpts<
|
|
55
|
-
item: ItemInstance
|
|
56
|
-
tree: TreeInstance
|
|
53
|
+
export type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
|
|
54
|
+
item: ItemInstance<any>;
|
|
55
|
+
tree: TreeInstance<any>;
|
|
57
56
|
itemId: string;
|
|
58
|
-
prev?: MayReturnNull<ItemInstance[Key]>;
|
|
57
|
+
prev?: MayReturnNull<ItemInstance<any>[Key]>;
|
|
59
58
|
};
|
|
60
|
-
export type TreeInstanceOpts<
|
|
61
|
-
tree: TreeInstance
|
|
62
|
-
prev?: MayReturnNull<TreeInstance[Key]>;
|
|
59
|
+
export type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
|
|
60
|
+
tree: TreeInstance<any>;
|
|
61
|
+
prev?: MayReturnNull<TreeInstance<any>[Key]>;
|
|
63
62
|
};
|
|
64
|
-
export type FeatureImplementation<T = any
|
|
63
|
+
export type FeatureImplementation<T = any> = {
|
|
65
64
|
key?: string;
|
|
66
65
|
deps?: string[];
|
|
67
66
|
overwrites?: string[];
|
|
68
|
-
stateHandlerNames?: Partial<Record<keyof
|
|
69
|
-
getInitialState?: (initialState: Partial<
|
|
70
|
-
getDefaultConfig?: (defaultConfig: Partial<
|
|
67
|
+
stateHandlerNames?: Partial<Record<keyof TreeState<T>, keyof TreeConfig<T>>>;
|
|
68
|
+
getInitialState?: (initialState: Partial<TreeState<T>>, tree: TreeInstance<T>) => Partial<TreeState<T>>;
|
|
69
|
+
getDefaultConfig?: (defaultConfig: Partial<TreeConfig<T>>, tree: TreeInstance<T>) => Partial<TreeConfig<T>>;
|
|
71
70
|
treeInstance?: {
|
|
72
|
-
[key in keyof
|
|
71
|
+
[key in keyof TreeInstance<T>]?: (opts: TreeInstanceOpts<key>, ...args: Parameters<TreeInstance<T>[key]>) => void;
|
|
73
72
|
};
|
|
74
73
|
itemInstance?: {
|
|
75
|
-
[key in keyof
|
|
74
|
+
[key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
|
|
76
75
|
};
|
|
77
|
-
onTreeMount?: (instance:
|
|
78
|
-
onTreeUnmount?: (instance:
|
|
79
|
-
onItemMount?: (instance:
|
|
80
|
-
onItemUnmount?: (instance:
|
|
81
|
-
hotkeys?: HotkeysConfig<T
|
|
76
|
+
onTreeMount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
|
|
77
|
+
onTreeUnmount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
|
|
78
|
+
onItemMount?: (instance: ItemInstance<T>, itemElement: HTMLElement, tree: TreeInstance<T>) => void;
|
|
79
|
+
onItemUnmount?: (instance: ItemInstance<T>, itemElement: HTMLElement, tree: TreeInstance<T>) => void;
|
|
80
|
+
hotkeys?: Partial<HotkeysConfig<T>>;
|
|
82
81
|
};
|
|
83
82
|
export {};
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@ const findPrevInstanceMethod = (
|
|
|
12
12
|
) => {
|
|
13
13
|
for (let i = featureSearchIndex; i >= 0; i--) {
|
|
14
14
|
const feature = features[i];
|
|
15
|
-
const itemInstanceMethod = feature[instanceType]?.[methodKey];
|
|
15
|
+
const itemInstanceMethod = (feature[instanceType] as any)?.[methodKey];
|
|
16
16
|
if (itemInstanceMethod) {
|
|
17
17
|
return i;
|
|
18
18
|
}
|
|
@@ -34,13 +34,15 @@ const invokeInstanceMethod = (
|
|
|
34
34
|
methodKey,
|
|
35
35
|
featureIndex - 1,
|
|
36
36
|
);
|
|
37
|
-
const itemInstanceMethod = features[featureIndex][instanceType]?.[
|
|
37
|
+
const itemInstanceMethod = (features[featureIndex][instanceType] as any)?.[
|
|
38
|
+
methodKey
|
|
39
|
+
]!;
|
|
38
40
|
return itemInstanceMethod(
|
|
39
41
|
{
|
|
40
42
|
...opts,
|
|
41
43
|
prev:
|
|
42
44
|
prevIndex !== null
|
|
43
|
-
? (...newArgs) =>
|
|
45
|
+
? (...newArgs: any[]) =>
|
|
44
46
|
invokeInstanceMethod(
|
|
45
47
|
features,
|
|
46
48
|
instanceType,
|
|
@@ -11,8 +11,7 @@ export const buildStaticInstance: InstanceBuilder = (
|
|
|
11
11
|
const finalize = () => {
|
|
12
12
|
const opts = buildOpts(instance);
|
|
13
13
|
featureLoop: for (let i = 0; i < features.length; i++) {
|
|
14
|
-
// Loop goes in forward order,
|
|
15
|
-
// TODO loop order correct? I think so...
|
|
14
|
+
// Loop goes in forward order, each features overwrite previous ones and wraps those in a prev() fn
|
|
16
15
|
const definition = features[i][instanceType];
|
|
17
16
|
if (!definition) continue featureLoop;
|
|
18
17
|
methodLoop: for (const [key, method] of Object.entries(definition)) {
|