@headless-tree/core 0.0.0-20250921152257 → 0.0.0-20251013200210
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 +11 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -2
- package/dist/index.mjs +3 -2
- package/package.json +1 -1
- package/src/features/hotkeys-core/feature.ts +1 -0
- package/src/features/tree/feature.ts +2 -2
- package/src/features/tree/tree.spec.ts +37 -4
- package/src/test-utils/test-tree.ts +3 -3
- package/src/types/core.ts +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20251013200210
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 08f10f1: Fixed an issue where `isFolder` returns incorrect values for leafs if they are not visibly rendered (#166)
|
|
8
|
+
|
|
9
|
+
## 1.5.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
|
6
12
|
|
|
@@ -17,6 +23,10 @@
|
|
|
17
23
|
- 597faad: Checkbox propagation is now supported for trees with async data loaders!
|
|
18
24
|
- b0ee382: triggering a data refetch will now always set the loadingItemData/loadingItemChildrens state variable to the associated items if they where not apart of the cache before
|
|
19
25
|
|
|
26
|
+
### Sponsorship appreciation
|
|
27
|
+
|
|
28
|
+
Thanks for [Docmost](https://docmost.com/), who have supported the development of Headless Tree with a sponsor contribution. Docmost is a wiki-software that can be self-hosted or used in cloud. Thank you!
|
|
29
|
+
|
|
20
30
|
## 1.4.0
|
|
21
31
|
|
|
22
32
|
### Minor Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -527,11 +527,11 @@ type HotkeyName = MergedFeatures<RegisteredFeatures<any>>["hotkeys"];
|
|
|
527
527
|
type HotkeysConfig<T> = Record<HotkeyName, HotkeyConfig<T>>;
|
|
528
528
|
type CustomHotkeysConfig<T> = Partial<Record<HotkeyName | `custom${string}`, Partial<HotkeyConfig<T>>>>;
|
|
529
529
|
type MayReturnNull<T extends (...x: any[]) => any> = (...args: Parameters<T>) => ReturnType<T> | null;
|
|
530
|
-
type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
|
|
531
|
-
item: ItemInstance<
|
|
532
|
-
tree: TreeInstance<
|
|
530
|
+
type ItemInstanceOpts<T, Key extends keyof ItemInstance<any>> = {
|
|
531
|
+
item: ItemInstance<T>;
|
|
532
|
+
tree: TreeInstance<T>;
|
|
533
533
|
itemId: string;
|
|
534
|
-
prev?: MayReturnNull<ItemInstance<
|
|
534
|
+
prev?: MayReturnNull<ItemInstance<T>[Key]>;
|
|
535
535
|
};
|
|
536
536
|
type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
|
|
537
537
|
tree: TreeInstance<any>;
|
|
@@ -548,7 +548,7 @@ type FeatureImplementation<T = any> = {
|
|
|
548
548
|
[key in keyof TreeInstance<T>]?: (opts: TreeInstanceOpts<key>, ...args: Parameters<TreeInstance<T>[key]>) => void;
|
|
549
549
|
};
|
|
550
550
|
itemInstance?: {
|
|
551
|
-
[key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
|
|
551
|
+
[key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<T, key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
|
|
552
552
|
};
|
|
553
553
|
onTreeMount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
|
|
554
554
|
onTreeUnmount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -527,11 +527,11 @@ type HotkeyName = MergedFeatures<RegisteredFeatures<any>>["hotkeys"];
|
|
|
527
527
|
type HotkeysConfig<T> = Record<HotkeyName, HotkeyConfig<T>>;
|
|
528
528
|
type CustomHotkeysConfig<T> = Partial<Record<HotkeyName | `custom${string}`, Partial<HotkeyConfig<T>>>>;
|
|
529
529
|
type MayReturnNull<T extends (...x: any[]) => any> = (...args: Parameters<T>) => ReturnType<T> | null;
|
|
530
|
-
type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
|
|
531
|
-
item: ItemInstance<
|
|
532
|
-
tree: TreeInstance<
|
|
530
|
+
type ItemInstanceOpts<T, Key extends keyof ItemInstance<any>> = {
|
|
531
|
+
item: ItemInstance<T>;
|
|
532
|
+
tree: TreeInstance<T>;
|
|
533
533
|
itemId: string;
|
|
534
|
-
prev?: MayReturnNull<ItemInstance<
|
|
534
|
+
prev?: MayReturnNull<ItemInstance<T>[Key]>;
|
|
535
535
|
};
|
|
536
536
|
type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
|
|
537
537
|
tree: TreeInstance<any>;
|
|
@@ -548,7 +548,7 @@ type FeatureImplementation<T = any> = {
|
|
|
548
548
|
[key in keyof TreeInstance<T>]?: (opts: TreeInstanceOpts<key>, ...args: Parameters<TreeInstance<T>[key]>) => void;
|
|
549
549
|
};
|
|
550
550
|
itemInstance?: {
|
|
551
|
-
[key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
|
|
551
|
+
[key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<T, key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
|
|
552
552
|
};
|
|
553
553
|
onTreeMount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
|
|
554
554
|
onTreeUnmount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
|
package/dist/index.js
CHANGED
|
@@ -303,7 +303,7 @@ var treeFeature = {
|
|
|
303
303
|
);
|
|
304
304
|
},
|
|
305
305
|
isFocused: ({ tree, item, itemId }) => tree.getState().focusedItem === itemId || tree.getState().focusedItem === null && item.getItemMeta().index === 0,
|
|
306
|
-
isFolder: ({ tree, item }) =>
|
|
306
|
+
isFolder: ({ tree, item, itemId }) => itemId === tree.getConfig().rootItemId || tree.getConfig().isItemFolder(item),
|
|
307
307
|
getItemName: ({ tree, item }) => {
|
|
308
308
|
const config = tree.getConfig();
|
|
309
309
|
return config.getItemName(item);
|
|
@@ -1007,7 +1007,8 @@ var specialKeys = {
|
|
|
1007
1007
|
minus: /^(NumpadSubtract|Minus)$/,
|
|
1008
1008
|
control: /^(ControlLeft|ControlRight)$/,
|
|
1009
1009
|
shift: /^(ShiftLeft|ShiftRight)$/,
|
|
1010
|
-
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)
|
|
1010
|
+
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)$/,
|
|
1011
|
+
enter: /^(Enter|NumpadEnter)$/
|
|
1011
1012
|
};
|
|
1012
1013
|
var testHotkeyMatch = (pressedKeys, tree, hotkey) => {
|
|
1013
1014
|
const supposedKeys = hotkey.hotkey.toLowerCase().split("+");
|
package/dist/index.mjs
CHANGED
|
@@ -259,7 +259,7 @@ var treeFeature = {
|
|
|
259
259
|
);
|
|
260
260
|
},
|
|
261
261
|
isFocused: ({ tree, item, itemId }) => tree.getState().focusedItem === itemId || tree.getState().focusedItem === null && item.getItemMeta().index === 0,
|
|
262
|
-
isFolder: ({ tree, item }) =>
|
|
262
|
+
isFolder: ({ tree, item, itemId }) => itemId === tree.getConfig().rootItemId || tree.getConfig().isItemFolder(item),
|
|
263
263
|
getItemName: ({ tree, item }) => {
|
|
264
264
|
const config = tree.getConfig();
|
|
265
265
|
return config.getItemName(item);
|
|
@@ -963,7 +963,8 @@ var specialKeys = {
|
|
|
963
963
|
minus: /^(NumpadSubtract|Minus)$/,
|
|
964
964
|
control: /^(ControlLeft|ControlRight)$/,
|
|
965
965
|
shift: /^(ShiftLeft|ShiftRight)$/,
|
|
966
|
-
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)
|
|
966
|
+
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)$/,
|
|
967
|
+
enter: /^(Enter|NumpadEnter)$/
|
|
967
968
|
};
|
|
968
969
|
var testHotkeyMatch = (pressedKeys, tree, hotkey) => {
|
|
969
970
|
const supposedKeys = hotkey.hotkey.toLowerCase().split("+");
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ const specialKeys: Record<string, RegExp> = {
|
|
|
14
14
|
control: /^(ControlLeft|ControlRight)$/,
|
|
15
15
|
shift: /^(ShiftLeft|ShiftRight)$/,
|
|
16
16
|
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)$/,
|
|
17
|
+
enter: /^(Enter|NumpadEnter)$/,
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
const testHotkeyMatch = (
|
|
@@ -203,8 +203,8 @@ export const treeFeature: FeatureImplementation<any> = {
|
|
|
203
203
|
isFocused: ({ tree, item, itemId }) =>
|
|
204
204
|
tree.getState().focusedItem === itemId ||
|
|
205
205
|
(tree.getState().focusedItem === null && item.getItemMeta().index === 0),
|
|
206
|
-
isFolder: ({ tree, item }) =>
|
|
207
|
-
|
|
206
|
+
isFolder: ({ tree, item, itemId }) =>
|
|
207
|
+
itemId === tree.getConfig().rootItemId ||
|
|
208
208
|
tree.getConfig().isItemFolder(item as ItemInstance<any>),
|
|
209
209
|
getItemName: ({ tree, item }) => {
|
|
210
210
|
const config = tree.getConfig();
|
|
@@ -4,8 +4,8 @@ import { propMemoizationFeature } from "../prop-memoization/feature";
|
|
|
4
4
|
|
|
5
5
|
const factory = TestTree.default({}).withFeatures(propMemoizationFeature);
|
|
6
6
|
|
|
7
|
-
describe("core-feature/
|
|
8
|
-
factory.forSuits((tree) => {
|
|
7
|
+
describe("core-feature/tree", () => {
|
|
8
|
+
factory.forSuits((tree, title) => {
|
|
9
9
|
describe("expanded items", () => {
|
|
10
10
|
it("can expand via tree instance", () => {
|
|
11
11
|
const setExpandedItems = tree.mockedHandler("setExpandedItems");
|
|
@@ -156,6 +156,17 @@ describe("core-feature/selections", () => {
|
|
|
156
156
|
});
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
+
it("unloaded item", () => {
|
|
160
|
+
expect(tree.instance.getItemInstance("x444").getItemMeta()).toEqual({
|
|
161
|
+
index: -1,
|
|
162
|
+
itemId: "x444",
|
|
163
|
+
level: -1,
|
|
164
|
+
parentId: null,
|
|
165
|
+
posInSet: 0,
|
|
166
|
+
setSize: 1,
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
159
170
|
it("expanded container", () => {
|
|
160
171
|
expect(tree.instance.getItemInstance("x11").getItemMeta()).toEqual({
|
|
161
172
|
index: 1,
|
|
@@ -312,8 +323,30 @@ describe("core-feature/selections", () => {
|
|
|
312
323
|
expect(tree.instance.getItemInstance("x1").isFolder()).toBe(true);
|
|
313
324
|
});
|
|
314
325
|
|
|
315
|
-
it("returns correctly for
|
|
316
|
-
expect(tree.instance.getItemInstance("
|
|
326
|
+
it("returns correctly for true cases of isFolder() ", () => {
|
|
327
|
+
expect(tree.instance.getItemInstance("x1").isFolder()).toBe(true);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it("returns correct isFolder for hidden items", async () => {
|
|
331
|
+
if (title.toLocaleLowerCase().includes("async")) {
|
|
332
|
+
// async test tree defaults to "loading" item names
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const testTree = await tree
|
|
336
|
+
.with({
|
|
337
|
+
isItemFolder: (item: any) => item.getItemData().length < 4,
|
|
338
|
+
})
|
|
339
|
+
.createTestCaseTree();
|
|
340
|
+
|
|
341
|
+
// Reference: https://github.com/lukasbach/headless-tree/issues/166
|
|
342
|
+
expect(testTree.instance.getItemInstance("x44").isFolder()).toBe(true);
|
|
343
|
+
expect(testTree.instance.getItemInstance("x444").isFolder()).toBe(
|
|
344
|
+
false,
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it("returns isFolder=true for root item", () => {
|
|
349
|
+
expect(tree.instance.getItemInstance("x").isFolder()).toBe(true);
|
|
317
350
|
});
|
|
318
351
|
|
|
319
352
|
it("returns correctly for getParent()", () => {
|
|
@@ -63,15 +63,15 @@ export class TestTree<T = string> {
|
|
|
63
63
|
}),
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
forSuits(runSuite: (tree: TestTree<T
|
|
66
|
+
forSuits(runSuite: (tree: TestTree<T>, title: string) => void) {
|
|
67
67
|
describe.for([
|
|
68
68
|
this.suits.sync(),
|
|
69
69
|
this.suits.async(),
|
|
70
70
|
this.suits.proxifiedSync(),
|
|
71
71
|
this.suits.proxifiedAsync(),
|
|
72
|
-
])("$title", ({ tree }) => {
|
|
72
|
+
])("$title", ({ tree, title }) => {
|
|
73
73
|
tree.resetBeforeEach();
|
|
74
|
-
runSuite(tree);
|
|
74
|
+
runSuite(tree, title);
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
|
package/src/types/core.ts
CHANGED
|
@@ -93,11 +93,11 @@ type MayReturnNull<T extends (...x: any[]) => any> = (
|
|
|
93
93
|
...args: Parameters<T>
|
|
94
94
|
) => ReturnType<T> | null;
|
|
95
95
|
|
|
96
|
-
export type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
|
|
97
|
-
item: ItemInstance<
|
|
98
|
-
tree: TreeInstance<
|
|
96
|
+
export type ItemInstanceOpts<T, Key extends keyof ItemInstance<any>> = {
|
|
97
|
+
item: ItemInstance<T>;
|
|
98
|
+
tree: TreeInstance<T>;
|
|
99
99
|
itemId: string;
|
|
100
|
-
prev?: MayReturnNull<ItemInstance<
|
|
100
|
+
prev?: MayReturnNull<ItemInstance<T>[Key]>;
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
export type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
|
|
@@ -131,7 +131,7 @@ export type FeatureImplementation<T = any> = {
|
|
|
131
131
|
|
|
132
132
|
itemInstance?: {
|
|
133
133
|
[key in keyof ItemInstance<T>]?: (
|
|
134
|
-
opts: ItemInstanceOpts<key>,
|
|
134
|
+
opts: ItemInstanceOpts<T, key>,
|
|
135
135
|
...args: Parameters<ItemInstance<T>[key]>
|
|
136
136
|
) => void;
|
|
137
137
|
};
|