@headless-tree/core 0.0.0-20250511185653 → 0.0.0-20250511194715

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +2 -1
  2. package/lib/cjs/core/create-tree.js +0 -9
  3. package/lib/cjs/features/async-data-loader/feature.js +20 -41
  4. package/lib/cjs/features/async-data-loader/types.d.ts +4 -4
  5. package/lib/cjs/features/expand-all/feature.js +2 -2
  6. package/lib/cjs/features/hotkeys-core/feature.js +27 -13
  7. package/lib/cjs/features/keyboard-drag-and-drop/feature.js +1 -1
  8. package/lib/cjs/features/main/types.d.ts +0 -2
  9. package/lib/cjs/features/selection/feature.js +1 -1
  10. package/lib/cjs/features/sync-data-loader/feature.js +2 -0
  11. package/lib/cjs/index.d.ts +0 -2
  12. package/lib/cjs/index.js +0 -2
  13. package/lib/cjs/types/core.d.ts +1 -2
  14. package/lib/esm/core/create-tree.js +0 -9
  15. package/lib/esm/features/async-data-loader/feature.js +20 -41
  16. package/lib/esm/features/async-data-loader/types.d.ts +4 -4
  17. package/lib/esm/features/expand-all/feature.js +2 -2
  18. package/lib/esm/features/hotkeys-core/feature.js +27 -13
  19. package/lib/esm/features/keyboard-drag-and-drop/feature.js +1 -1
  20. package/lib/esm/features/main/types.d.ts +0 -2
  21. package/lib/esm/features/selection/feature.js +1 -1
  22. package/lib/esm/features/sync-data-loader/feature.js +2 -0
  23. package/lib/esm/index.d.ts +0 -2
  24. package/lib/esm/index.js +0 -2
  25. package/lib/esm/types/core.d.ts +1 -2
  26. package/package.json +1 -1
  27. package/src/core/create-tree.ts +0 -13
  28. package/src/features/async-data-loader/feature.ts +24 -35
  29. package/src/features/async-data-loader/types.ts +4 -4
  30. package/src/features/expand-all/feature.ts +2 -2
  31. package/src/features/hotkeys-core/feature.ts +33 -15
  32. package/src/features/keyboard-drag-and-drop/feature.ts +1 -1
  33. package/src/features/main/types.ts +0 -2
  34. package/src/features/selection/feature.ts +1 -1
  35. package/src/features/sync-data-loader/feature.ts +3 -0
  36. package/src/features/tree/types.ts +1 -1
  37. package/src/index.ts +0 -2
  38. package/src/types/core.ts +0 -2
  39. package/lib/cjs/features/checkboxes/feature.d.ts +0 -2
  40. package/lib/cjs/features/checkboxes/feature.js +0 -94
  41. package/lib/cjs/features/checkboxes/types.d.ts +0 -26
  42. package/lib/cjs/features/checkboxes/types.js +0 -9
  43. package/lib/esm/features/checkboxes/feature.d.ts +0 -2
  44. package/lib/esm/features/checkboxes/feature.js +0 -91
  45. package/lib/esm/features/checkboxes/types.d.ts +0 -26
  46. package/lib/esm/features/checkboxes/types.js +0 -6
  47. package/src/features/checkboxes/checkboxes.spec.ts +0 -134
  48. package/src/features/checkboxes/feature.ts +0 -119
  49. package/src/features/checkboxes/types.ts +0 -28
@@ -1,91 +0,0 @@
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
- };
@@ -1,26 +0,0 @@
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
- };
@@ -1,6 +0,0 @@
1
- export var CheckedState;
2
- (function (CheckedState) {
3
- CheckedState["Checked"] = "checked";
4
- CheckedState["Unchecked"] = "unchecked";
5
- CheckedState["Indeterminate"] = "indeterminate";
6
- })(CheckedState || (CheckedState = {}));
@@ -1,134 +0,0 @@
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
- });
@@ -1,119 +0,0 @@
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
- };
@@ -1,28 +0,0 @@
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
- };