@headless-tree/core 0.0.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.
Files changed (87) hide show
  1. package/lib/core/create-tree.d.ts +2 -0
  2. package/lib/core/create-tree.js +116 -0
  3. package/lib/data-adapters/nested-data-adapter.d.ts +9 -0
  4. package/lib/data-adapters/nested-data-adapter.js +32 -0
  5. package/lib/data-adapters/types.d.ts +7 -0
  6. package/lib/data-adapters/types.js +2 -0
  7. package/lib/features/async-data-loader/feature.d.ts +5 -0
  8. package/lib/features/async-data-loader/feature.js +80 -0
  9. package/lib/features/async-data-loader/types.d.ts +41 -0
  10. package/lib/features/async-data-loader/types.js +2 -0
  11. package/lib/features/drag-and-drop/feature.d.ts +3 -0
  12. package/lib/features/drag-and-drop/feature.js +144 -0
  13. package/lib/features/drag-and-drop/types.d.ts +49 -0
  14. package/lib/features/drag-and-drop/types.js +9 -0
  15. package/lib/features/drag-and-drop/utils.d.ts +7 -0
  16. package/lib/features/drag-and-drop/utils.js +121 -0
  17. package/lib/features/expand-all/feature.d.ts +6 -0
  18. package/lib/features/expand-all/feature.js +39 -0
  19. package/lib/features/expand-all/types.d.ts +17 -0
  20. package/lib/features/expand-all/types.js +2 -0
  21. package/lib/features/hotkeys-core/feature.d.ts +4 -0
  22. package/lib/features/hotkeys-core/feature.js +73 -0
  23. package/lib/features/hotkeys-core/types.d.ts +25 -0
  24. package/lib/features/hotkeys-core/types.js +2 -0
  25. package/lib/features/main/types.d.ts +36 -0
  26. package/lib/features/main/types.js +2 -0
  27. package/lib/features/renaming/feature.d.ts +5 -0
  28. package/lib/features/renaming/feature.js +65 -0
  29. package/lib/features/renaming/types.d.ts +27 -0
  30. package/lib/features/renaming/types.js +2 -0
  31. package/lib/features/search/feature.d.ts +5 -0
  32. package/lib/features/search/feature.js +90 -0
  33. package/lib/features/search/types.d.ts +33 -0
  34. package/lib/features/search/types.js +2 -0
  35. package/lib/features/selection/feature.d.ts +5 -0
  36. package/lib/features/selection/feature.js +112 -0
  37. package/lib/features/selection/types.d.ts +21 -0
  38. package/lib/features/selection/types.js +2 -0
  39. package/lib/features/sync-data-loader/feature.d.ts +4 -0
  40. package/lib/features/sync-data-loader/feature.js +9 -0
  41. package/lib/features/sync-data-loader/types.d.ts +19 -0
  42. package/lib/features/sync-data-loader/types.js +2 -0
  43. package/lib/features/tree/feature.d.ts +6 -0
  44. package/lib/features/tree/feature.js +216 -0
  45. package/lib/features/tree/types.d.ts +57 -0
  46. package/lib/features/tree/types.js +2 -0
  47. package/lib/index.d.ts +21 -0
  48. package/lib/index.js +37 -0
  49. package/lib/mddocs-entry.d.ts +21 -0
  50. package/lib/mddocs-entry.js +17 -0
  51. package/lib/types/core.d.ts +68 -0
  52. package/lib/types/core.js +2 -0
  53. package/lib/types/deep-merge.d.ts +13 -0
  54. package/lib/types/deep-merge.js +2 -0
  55. package/lib/utils.d.ts +9 -0
  56. package/lib/utils.js +105 -0
  57. package/package.json +15 -0
  58. package/src/core/create-tree.ts +195 -0
  59. package/src/data-adapters/nested-data-adapter.ts +48 -0
  60. package/src/data-adapters/types.ts +9 -0
  61. package/src/features/async-data-loader/feature.ts +117 -0
  62. package/src/features/async-data-loader/types.ts +41 -0
  63. package/src/features/drag-and-drop/feature.ts +153 -0
  64. package/src/features/drag-and-drop/types.ts +64 -0
  65. package/src/features/drag-and-drop/utils.ts +88 -0
  66. package/src/features/expand-all/feature.ts +62 -0
  67. package/src/features/expand-all/types.ts +13 -0
  68. package/src/features/hotkeys-core/feature.ts +111 -0
  69. package/src/features/hotkeys-core/types.ts +36 -0
  70. package/src/features/main/types.ts +41 -0
  71. package/src/features/renaming/feature.ts +102 -0
  72. package/src/features/renaming/types.ts +28 -0
  73. package/src/features/search/feature.ts +142 -0
  74. package/src/features/search/types.ts +39 -0
  75. package/src/features/selection/feature.ts +153 -0
  76. package/src/features/selection/types.ts +28 -0
  77. package/src/features/sync-data-loader/feature.ts +27 -0
  78. package/src/features/sync-data-loader/types.ts +20 -0
  79. package/src/features/tree/feature.ts +307 -0
  80. package/src/features/tree/types.ts +70 -0
  81. package/src/index.ts +23 -0
  82. package/src/mddocs-entry.ts +26 -0
  83. package/src/types/core.ts +182 -0
  84. package/src/types/deep-merge.ts +31 -0
  85. package/src/utils.ts +136 -0
  86. package/tsconfig.json +7 -0
  87. package/typedoc.json +4 -0
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.treeFeature = void 0;
13
+ const utils_1 = require("../../utils");
14
+ exports.treeFeature = {
15
+ key: "tree",
16
+ dependingFeatures: ["main"],
17
+ getInitialState: (initialState) => (Object.assign({ expandedItems: [], focusedItem: null }, initialState)),
18
+ getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setExpandedItems: (0, utils_1.makeStateUpdater)("expandedItems", tree), setFocusedItem: (0, utils_1.makeStateUpdater)("focusedItem", tree) }, defaultConfig)),
19
+ createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: () => {
20
+ throw new Error("No data-loader registered");
21
+ }, retrieveChildrenIds: () => {
22
+ throw new Error("No data-loader registered");
23
+ }, isItemExpanded: (itemId) => instance.getState().expandedItems.includes(itemId), getItemsMeta: () => {
24
+ const { rootItemId } = instance.getConfig();
25
+ const { expandedItems } = instance.getState();
26
+ // console.log("!", instance.getConfig());
27
+ const flatItems = [];
28
+ const recursiveAdd = (itemId, parentId, level, setSize, posInSet) => {
29
+ var _a;
30
+ flatItems.push({
31
+ itemId,
32
+ level,
33
+ index: flatItems.length,
34
+ parentId,
35
+ setSize,
36
+ posInSet,
37
+ });
38
+ if (expandedItems.includes(itemId)) {
39
+ const children = (_a = instance.retrieveChildrenIds(itemId)) !== null && _a !== void 0 ? _a : [];
40
+ let i = 0;
41
+ for (const childId of children) {
42
+ recursiveAdd(childId, itemId, level + 1, children.length, i++);
43
+ }
44
+ }
45
+ };
46
+ const children = instance.retrieveChildrenIds(rootItemId);
47
+ let i = 0;
48
+ for (const itemId of children) {
49
+ recursiveAdd(itemId, rootItemId, 0, children.length, i++);
50
+ }
51
+ return flatItems;
52
+ }, expandItem: (itemId) => {
53
+ var _a, _b, _c;
54
+ if (!instance.getItemInstance(itemId).isFolder()) {
55
+ return;
56
+ }
57
+ if ((_a = instance.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
58
+ return;
59
+ }
60
+ (_c = (_b = instance
61
+ .getConfig()).setExpandedItems) === null || _c === void 0 ? void 0 : _c.call(_b, (expandedItems) => [...expandedItems, itemId]);
62
+ instance.rebuildTree();
63
+ }, collapseItem: (itemId) => {
64
+ var _a, _b;
65
+ if (!instance.getItemInstance(itemId).isFolder()) {
66
+ return;
67
+ }
68
+ (_b = (_a = instance
69
+ .getConfig()).setExpandedItems) === null || _b === void 0 ? void 0 : _b.call(_a, (expandedItems) => expandedItems.filter((id) => id !== itemId));
70
+ instance.rebuildTree();
71
+ },
72
+ // TODO memo
73
+ getFocusedItem: () => {
74
+ var _a, _b;
75
+ return ((_b = instance.getItemInstance((_a = instance.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : instance.getItems()[0]);
76
+ }, focusItem: (itemId) => {
77
+ var _a, _b;
78
+ (_b = (_a = instance.getConfig()).setFocusedItem) === null || _b === void 0 ? void 0 : _b.call(_a, itemId);
79
+ }, focusNextItem: () => {
80
+ const { index } = instance.getFocusedItem().getItemMeta();
81
+ const nextIndex = Math.min(index + 1, instance.getItems().length - 1);
82
+ instance.focusItem(instance.getItems()[nextIndex].getId());
83
+ }, focusPreviousItem: () => {
84
+ const { index } = instance.getFocusedItem().getItemMeta();
85
+ const nextIndex = Math.max(index - 1, 0);
86
+ instance.focusItem(instance.getItems()[nextIndex].getId());
87
+ }, updateDomFocus: (scrollIntoView) => {
88
+ // Required because if the state is managed outside in react, the state only updated during next render
89
+ setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
90
+ var _a, _b;
91
+ const focusedItem = instance.getFocusedItem();
92
+ (_b = (_a = instance.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, focusedItem);
93
+ yield (0, utils_1.poll)(() => focusedItem.getElement() !== null, 20);
94
+ const focusedElement = focusedItem.getElement();
95
+ if (!focusedElement)
96
+ return;
97
+ focusedElement.focus();
98
+ // if (scrollIntoView) {
99
+ // focusedElement.scrollIntoView();
100
+ // }
101
+ }));
102
+ }, getContainerProps: () => {
103
+ var _a;
104
+ return (Object.assign(Object.assign({}, (_a = prev.getContainerProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "tree", ariaLabel: "", ariaActivedescendant: "" }));
105
+ } })),
106
+ createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { isLoading: () => {
107
+ throw new Error("No data-loader registered");
108
+ }, getId: () => item.getItemMeta().itemId, getProps: () => {
109
+ var _a;
110
+ const itemMeta = item.getItemMeta();
111
+ return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(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: (e) => {
112
+ item.setFocused();
113
+ item.primaryAction();
114
+ if (e.ctrlKey || e.shiftKey || e.metaKey) {
115
+ return;
116
+ }
117
+ if (!item.isFolder()) {
118
+ return;
119
+ }
120
+ if (item.isExpanded()) {
121
+ item.collapse();
122
+ }
123
+ else {
124
+ item.expand();
125
+ }
126
+ } });
127
+ }, expand: () => tree.expandItem(item.getItemMeta().itemId), collapse: () => tree.collapseItem(item.getItemMeta().itemId), getItemData: () => tree.retrieveItemData(item.getItemMeta().itemId), isExpanded: () => tree.getState().expandedItems.includes(item.getItemMeta().itemId), isFocused: () => tree.getState().focusedItem === item.getItemMeta().itemId ||
128
+ (tree.getState().focusedItem === null && item.getItemMeta().index === 0), isFolder: () => item.getItemMeta().level === -1 ||
129
+ tree.getConfig().isItemFolder(item), getItemName: () => {
130
+ const config = tree.getConfig();
131
+ return config.getItemName(item);
132
+ }, setFocused: () => tree.focusItem(item.getItemMeta().itemId), primaryAction: () => { var _a, _b; return (_b = (_a = tree.getConfig()).onPrimaryAction) === null || _b === void 0 ? void 0 : _b.call(_a, item); }, getParent: (0, utils_1.memo)((itemMeta) => {
133
+ for (let i = itemMeta.index - 1; i >= 0; i--) {
134
+ const potentialParent = tree.getItems()[i];
135
+ if (potentialParent.getItemMeta().level < itemMeta.level) {
136
+ return potentialParent;
137
+ }
138
+ }
139
+ return tree.getItemInstance(tree.getConfig().rootItemId);
140
+ }, () => [item.getItemMeta()]), getIndexInParent: () => {
141
+ var _a, _b;
142
+ return item.getItemMeta().index -
143
+ ((_b = (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.getItemMeta().index) !== null && _b !== void 0 ? _b : 0) -
144
+ 1;
145
+ }, getChildren: () => tree
146
+ .retrieveChildrenIds(item.getItemMeta().itemId)
147
+ .map((id) => tree.getItemInstance(id)), getTree: () => tree, getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1], getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1] })),
148
+ hotkeys: {
149
+ focusNextItem: {
150
+ hotkey: "ArrowDown",
151
+ canRepeat: true,
152
+ preventDefault: true,
153
+ isEnabled: (tree) => { var _a, _b; return !((_b = (_a = tree.isSearchOpen) === null || _a === void 0 ? void 0 : _a.call(tree)) !== null && _b !== void 0 ? _b : false) && !tree.getState().dnd; },
154
+ handler: (e, tree) => {
155
+ tree.focusNextItem();
156
+ tree.updateDomFocus();
157
+ },
158
+ },
159
+ focusPreviousItem: {
160
+ hotkey: "ArrowUp",
161
+ canRepeat: true,
162
+ preventDefault: true,
163
+ isEnabled: (tree) => { var _a, _b; return !((_b = (_a = tree.isSearchOpen) === null || _a === void 0 ? void 0 : _a.call(tree)) !== null && _b !== void 0 ? _b : false) && !tree.getState().dnd; },
164
+ handler: (e, tree) => {
165
+ tree.focusPreviousItem();
166
+ tree.updateDomFocus();
167
+ },
168
+ },
169
+ expandOrDown: {
170
+ hotkey: "ArrowRight",
171
+ canRepeat: true,
172
+ handler: (e, tree) => {
173
+ const item = tree.getFocusedItem();
174
+ if (item.isExpanded() || !item.isFolder()) {
175
+ tree.focusNextItem();
176
+ tree.updateDomFocus();
177
+ }
178
+ else {
179
+ item.expand();
180
+ }
181
+ },
182
+ },
183
+ collapseOrUp: {
184
+ hotkey: "ArrowLeft",
185
+ canRepeat: true,
186
+ handler: (e, tree) => {
187
+ var _a;
188
+ const item = tree.getFocusedItem();
189
+ if ((!item.isExpanded() || !item.isFolder()) &&
190
+ item.getItemMeta().level !== 0) {
191
+ (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.setFocused();
192
+ tree.updateDomFocus(true);
193
+ }
194
+ else {
195
+ item.collapse();
196
+ }
197
+ },
198
+ },
199
+ focusFirstItem: {
200
+ hotkey: "Home",
201
+ handler: (e, tree) => {
202
+ console.log("home", tree.getItems()[0], tree.getItems());
203
+ tree.focusItem(tree.getItems()[0].getId());
204
+ tree.updateDomFocus();
205
+ },
206
+ },
207
+ focusLastItem: {
208
+ hotkey: "End",
209
+ handler: (e, tree) => {
210
+ console.log("end");
211
+ tree.focusItem(tree.getItems()[tree.getItems().length - 1].getId());
212
+ tree.updateDomFocus();
213
+ },
214
+ },
215
+ },
216
+ };
@@ -0,0 +1,57 @@
1
+ import { ItemInstance, SetStateFn, TreeInstance } from "../../types/core";
2
+ export type ItemMeta = {
3
+ itemId: string;
4
+ parentId: string;
5
+ level: number;
6
+ index: number;
7
+ setSize: number;
8
+ posInSet: number;
9
+ };
10
+ export type TreeFeatureDef<T> = {
11
+ state: {
12
+ expandedItems: string[];
13
+ focusedItem: string | null;
14
+ };
15
+ config: {
16
+ isItemFolder: (item: ItemInstance<T>) => boolean;
17
+ getItemName: (item: ItemInstance<T>) => string;
18
+ onPrimaryAction?: (item: ItemInstance<T>) => void;
19
+ scrollToItem?: (item: ItemInstance<T>) => void;
20
+ setExpandedItems?: SetStateFn<string[]>;
21
+ setFocusedItem?: SetStateFn<string | null>;
22
+ };
23
+ treeInstance: {
24
+ /** @internal */
25
+ getItemsMeta: () => ItemMeta[];
26
+ expandItem: (itemId: string) => void;
27
+ collapseItem: (itemId: string) => void;
28
+ isItemExpanded: (itemId: string) => boolean;
29
+ focusItem: (itemId: string) => void;
30
+ getFocusedItem: () => ItemInstance<any>;
31
+ focusNextItem: () => void;
32
+ focusPreviousItem: () => void;
33
+ scrollToItem: (item: ItemInstance<any>) => void;
34
+ updateDomFocus: (scrollIntoView?: boolean) => void;
35
+ getContainerProps: () => Record<string, any>;
36
+ };
37
+ itemInstance: {
38
+ getId: () => string;
39
+ getProps: () => Record<string, any>;
40
+ getItemName: () => string;
41
+ getItemData: () => T;
42
+ expand: () => void;
43
+ collapse: () => void;
44
+ isExpanded: () => boolean;
45
+ isFocused: () => boolean;
46
+ isFolder: () => boolean;
47
+ setFocused: () => void;
48
+ getParent: () => ItemInstance<T>;
49
+ getChildren: () => ItemInstance<T>[];
50
+ getIndexInParent: () => number;
51
+ primaryAction: () => void;
52
+ getTree: () => TreeInstance<T>;
53
+ getItemAbove: () => ItemInstance<T> | null;
54
+ getItemBelow: () => ItemInstance<T> | null;
55
+ };
56
+ hotkeys: "focusNextItem" | "focusPreviousItem" | "expandOrDown" | "collapseOrUp" | "focusFirstItem" | "focusLastItem";
57
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/lib/index.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ export * from "./types/core";
2
+ export * from "./core/create-tree";
3
+ export * from "./features/tree/types";
4
+ export * from "./features/main/types";
5
+ export * from "./features/drag-and-drop/types";
6
+ export * from "./features/selection/types";
7
+ export * from "./features/async-data-loader/types";
8
+ export * from "./features/sync-data-loader/types";
9
+ export * from "./features/hotkeys-core/types";
10
+ export * from "./features/search/types";
11
+ export * from "./features/renaming/types";
12
+ export * from "./features/expand-all/types";
13
+ export * from "./features/selection/feature";
14
+ export * from "./features/hotkeys-core/feature";
15
+ export * from "./features/async-data-loader/feature";
16
+ export * from "./features/sync-data-loader/feature";
17
+ export * from "./features/drag-and-drop/feature";
18
+ export * from "./features/search/feature";
19
+ export * from "./features/renaming/feature";
20
+ export * from "./features/expand-all/feature";
21
+ export * from "./data-adapters/nested-data-adapter";
package/lib/index.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types/core"), exports);
18
+ __exportStar(require("./core/create-tree"), exports);
19
+ __exportStar(require("./features/tree/types"), exports);
20
+ __exportStar(require("./features/main/types"), exports);
21
+ __exportStar(require("./features/drag-and-drop/types"), exports);
22
+ __exportStar(require("./features/selection/types"), exports);
23
+ __exportStar(require("./features/async-data-loader/types"), exports);
24
+ __exportStar(require("./features/sync-data-loader/types"), exports);
25
+ __exportStar(require("./features/hotkeys-core/types"), exports);
26
+ __exportStar(require("./features/search/types"), exports);
27
+ __exportStar(require("./features/renaming/types"), exports);
28
+ __exportStar(require("./features/expand-all/types"), exports);
29
+ __exportStar(require("./features/selection/feature"), exports);
30
+ __exportStar(require("./features/hotkeys-core/feature"), exports);
31
+ __exportStar(require("./features/async-data-loader/feature"), exports);
32
+ __exportStar(require("./features/sync-data-loader/feature"), exports);
33
+ __exportStar(require("./features/drag-and-drop/feature"), exports);
34
+ __exportStar(require("./features/search/feature"), exports);
35
+ __exportStar(require("./features/renaming/feature"), exports);
36
+ __exportStar(require("./features/expand-all/feature"), exports);
37
+ __exportStar(require("./data-adapters/nested-data-adapter"), exports);
@@ -0,0 +1,21 @@
1
+ import { MainFeatureDef } from "./features/main/types";
2
+ import { DragAndDropFeatureDef } from "./features/drag-and-drop/types";
3
+ export * from ".";
4
+ /** @interface */
5
+ export type MainFeatureConfig = MainFeatureDef["config"];
6
+ /** @interface */
7
+ export type MainFeatureState = MainFeatureDef["state"];
8
+ /** @interface */
9
+ export type MainFeatureTreeInstance = MainFeatureDef["treeInstance"];
10
+ /** @interface */
11
+ export type MainFeatureItemInstance = MainFeatureDef["itemInstance"];
12
+ export type MainFeatureHotkeys = MainFeatureDef["hotkeys"];
13
+ /** @interface */
14
+ export type DragAndDropFeatureConfig<T> = DragAndDropFeatureDef<T>["config"];
15
+ /** @interface */
16
+ export type DragAndDropFeatureState<T> = DragAndDropFeatureDef<T>["state"];
17
+ /** @interface */
18
+ export type DragAndDropFeatureTreeInstance<T> = DragAndDropFeatureDef<T>["treeInstance"];
19
+ /** @interface */
20
+ export type DragAndDropFeatureItemInstance<T> = DragAndDropFeatureDef<T>["itemInstance"];
21
+ export type DragAndDropFeatureHotkeys<T> = DragAndDropFeatureDef<T>["hotkeys"];
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("."), exports);
@@ -0,0 +1,68 @@
1
+ import { DragAndDropFeatureDef } from "../features/drag-and-drop/types";
2
+ import { MainFeatureDef } from "../features/main/types";
3
+ import { SelectionFeatureDef } from "../features/selection/types";
4
+ import { TreeFeatureDef } from "../features/tree/types";
5
+ import { HotkeyConfig, HotkeysCoreFeatureDef } from "../features/hotkeys-core/types";
6
+ import { SyncDataLoaderFeatureDef } from "../features/sync-data-loader/types";
7
+ import { AsyncDataLoaderFeatureDef } from "../features/async-data-loader/types";
8
+ import { SearchFeatureDef } from "../features/search/types";
9
+ import { RenamingFeatureDef } from "../features/renaming/types";
10
+ import { ExpandAllFeatureDef } from "../features/expand-all/types";
11
+ export type Updater<T> = T | ((old: T) => T);
12
+ export type SetStateFn<T> = (updaterOrValue: Updater<T>) => void;
13
+ export type FeatureDef = {
14
+ state: object;
15
+ config: object;
16
+ treeInstance: object;
17
+ itemInstance: object;
18
+ hotkeys: string;
19
+ };
20
+ export type EmptyFeatureDef = {
21
+ state: {};
22
+ config: {};
23
+ treeInstance: {};
24
+ itemInstance: {};
25
+ hotkeys: never;
26
+ };
27
+ type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;
28
+ export type DefaultFeatures<T> = MainFeatureDef | TreeFeatureDef<T>;
29
+ export type FeatureDefs<T> = MainFeatureDef | TreeFeatureDef<T> | SelectionFeatureDef<T> | DragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef;
30
+ type MergedFeatures<F extends FeatureDef> = {
31
+ state: UnionToIntersection<F["state"]>;
32
+ config: UnionToIntersection<F["config"]>;
33
+ treeInstance: UnionToIntersection<F["treeInstance"]>;
34
+ itemInstance: UnionToIntersection<F["itemInstance"]>;
35
+ hotkeys: F["hotkeys"];
36
+ };
37
+ type TreeStateType<T> = MainFeatureDef["state"] & TreeFeatureDef<T>["state"] & SelectionFeatureDef<T>["state"] & DragAndDropFeatureDef<T>["state"] & HotkeysCoreFeatureDef<T>["state"] & SyncDataLoaderFeatureDef<T>["state"] & AsyncDataLoaderFeatureDef<T>["state"] & SearchFeatureDef<T>["state"] & RenamingFeatureDef<T>["state"] & ExpandAllFeatureDef["state"];
38
+ export interface TreeState<T> extends TreeStateType<T> {
39
+ }
40
+ type TreeConfigType<T> = MainFeatureDef["config"] & TreeFeatureDef<T>["config"] & SelectionFeatureDef<T>["config"] & DragAndDropFeatureDef<T>["config"] & HotkeysCoreFeatureDef<T>["config"] & SyncDataLoaderFeatureDef<T>["config"] & AsyncDataLoaderFeatureDef<T>["config"] & SearchFeatureDef<T>["config"] & RenamingFeatureDef<T>["config"] & ExpandAllFeatureDef["config"];
41
+ export interface TreeConfig<T> extends TreeConfigType<T> {
42
+ }
43
+ type TreeInstanceType<T> = MainFeatureDef["treeInstance"] & TreeFeatureDef<T>["treeInstance"] & SelectionFeatureDef<T>["treeInstance"] & DragAndDropFeatureDef<T>["treeInstance"] & HotkeysCoreFeatureDef<T>["treeInstance"] & SyncDataLoaderFeatureDef<T>["treeInstance"] & AsyncDataLoaderFeatureDef<T>["treeInstance"] & SearchFeatureDef<T>["treeInstance"] & RenamingFeatureDef<T>["treeInstance"] & ExpandAllFeatureDef["treeInstance"];
44
+ export interface TreeInstance<T> extends TreeInstanceType<T> {
45
+ }
46
+ type ItemInstanceType<T> = MainFeatureDef["itemInstance"] & TreeFeatureDef<T>["itemInstance"] & SelectionFeatureDef<T>["itemInstance"] & DragAndDropFeatureDef<T>["itemInstance"] & HotkeysCoreFeatureDef<T>["itemInstance"] & SyncDataLoaderFeatureDef<T>["itemInstance"] & AsyncDataLoaderFeatureDef<T>["itemInstance"] & SearchFeatureDef<T>["itemInstance"] & RenamingFeatureDef<T>["itemInstance"] & ExpandAllFeatureDef["itemInstance"];
47
+ export interface ItemInstance<T> extends ItemInstanceType<T> {
48
+ }
49
+ export type HotkeyName<F extends FeatureDef = FeatureDefs<any>> = MergedFeatures<F>["hotkeys"];
50
+ export type HotkeysConfig<T, F extends FeatureDef = FeatureDefs<T>> = Record<HotkeyName<F>, HotkeyConfig<T>>;
51
+ export type CustomHotkeysConfig<T, F extends FeatureDef = FeatureDefs<T>> = Partial<Record<HotkeyName<F> | `custom${string}`, Partial<HotkeyConfig<T>>>>;
52
+ export type FeatureImplementation<T = any, D extends FeatureDef = any, F extends FeatureDef = EmptyFeatureDef> = {
53
+ key?: string;
54
+ dependingFeatures?: string[];
55
+ getInitialState?: (initialState: Partial<MergedFeatures<F>["state"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["state"] & MergedFeatures<F>["state"]>;
56
+ getDefaultConfig?: (defaultConfig: Partial<MergedFeatures<F>["config"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["config"] & MergedFeatures<F>["config"]>;
57
+ createTreeInstance?: (prev: MergedFeatures<F>["treeInstance"], instance: MergedFeatures<F>["treeInstance"]) => D["treeInstance"] & MergedFeatures<F>["treeInstance"];
58
+ createItemInstance?: (prev: MergedFeatures<F>["itemInstance"], item: MergedFeatures<F>["itemInstance"], tree: MergedFeatures<F>["treeInstance"], itemId: string) => D["itemInstance"] & MergedFeatures<F>["itemInstance"];
59
+ onTreeMount?: (instance: MergedFeatures<F>["treeInstance"], treeElement: HTMLElement) => void;
60
+ onTreeUnmount?: (instance: MergedFeatures<F>["treeInstance"], treeElement: HTMLElement) => void;
61
+ onItemMount?: (instance: MergedFeatures<F>["itemInstance"], itemElement: HTMLElement, tree: MergedFeatures<F>["treeInstance"]) => void;
62
+ onItemUnmount?: (instance: MergedFeatures<F>["itemInstance"], itemElement: HTMLElement, tree: MergedFeatures<F>["treeInstance"]) => void;
63
+ setState?: (instance: MergedFeatures<F>["treeInstance"]) => void;
64
+ onConfigChange?: (instance: MergedFeatures<F>["treeInstance"]) => void;
65
+ onStateOrConfigChange?: (instance: MergedFeatures<F>["treeInstance"]) => void;
66
+ hotkeys?: HotkeysConfig<T, D>;
67
+ };
68
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ type TAllKeys<T> = T extends any ? keyof T : never;
2
+ type TIndexValue<T, K extends PropertyKey, D = never> = T extends any ? K extends keyof T ? T[K] : D : never;
3
+ type TPartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>> extends infer O ? {
4
+ [P in keyof O]: O[P];
5
+ } : never;
6
+ type TFunction = (...a: any[]) => any;
7
+ type TPrimitives = string | number | boolean | bigint | symbol | Date | TFunction;
8
+ export type TMerged<T> = [T] extends [Array<any>] ? {
9
+ [K in keyof T]: TMerged<T[K]>;
10
+ } : [T] extends [TPrimitives] ? T : [T] extends [object] ? TPartialKeys<{
11
+ [K in TAllKeys<T>]: TMerged<TIndexValue<T, K>>;
12
+ }, never> : T;
13
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/lib/utils.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { ItemInstance, TreeState, Updater } from "./types/core";
2
+ import { DropTarget } from "./features/drag-and-drop/types";
3
+ export type NoInfer<T> = [T][T extends any ? 0 : never];
4
+ export declare const memo: <D extends readonly any[], R>(fn: (...args_0: D) => R, deps: () => [...D]) => () => R;
5
+ export declare function functionalUpdate<T>(updater: Updater<T>, input: T): T;
6
+ export declare function makeStateUpdater<K extends keyof TreeState<any>>(key: K, instance: unknown): (updater: Updater<TreeState<any>[K]>) => void;
7
+ export declare const scrollIntoView: (element: Element | undefined | null) => void;
8
+ export declare const performItemsMove: <T>(items: ItemInstance<T>[], target: DropTarget<T>, onChangeChildren: (item: ItemInstance<T>, newChildren: ItemInstance<T>[]) => void) => void;
9
+ export declare const poll: (fn: () => boolean, interval?: number, timeout?: number) => Promise<void>;
package/lib/utils.js ADDED
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.poll = exports.performItemsMove = exports.scrollIntoView = exports.makeStateUpdater = exports.functionalUpdate = exports.memo = void 0;
4
+ const memo = (fn, deps) => {
5
+ let value;
6
+ let oldDeps = null;
7
+ return () => {
8
+ const newDeps = deps();
9
+ if (!value) {
10
+ value = fn(...newDeps);
11
+ oldDeps = newDeps;
12
+ return value;
13
+ }
14
+ const match = oldDeps &&
15
+ oldDeps.length === newDeps.length &&
16
+ !oldDeps.some((dep, i) => dep !== newDeps[i]);
17
+ if (match) {
18
+ return value;
19
+ }
20
+ value = fn(...newDeps);
21
+ oldDeps = newDeps;
22
+ return value;
23
+ };
24
+ };
25
+ exports.memo = memo;
26
+ function functionalUpdate(updater, input) {
27
+ return typeof updater === "function"
28
+ ? updater(input)
29
+ : updater;
30
+ }
31
+ exports.functionalUpdate = functionalUpdate;
32
+ function makeStateUpdater(key, instance) {
33
+ return (updater) => {
34
+ instance.setState((old) => {
35
+ return Object.assign(Object.assign({}, old), { [key]: functionalUpdate(updater, old[key]) });
36
+ });
37
+ };
38
+ }
39
+ exports.makeStateUpdater = makeStateUpdater;
40
+ const scrollIntoView = (element) => {
41
+ if (!element) {
42
+ return;
43
+ }
44
+ if (element.scrollIntoViewIfNeeded) {
45
+ element.scrollIntoViewIfNeeded();
46
+ }
47
+ else {
48
+ const boundingBox = element.getBoundingClientRect();
49
+ const isElementInViewport = boundingBox.top >= 0 &&
50
+ boundingBox.left >= 0 &&
51
+ boundingBox.bottom <=
52
+ (window.innerHeight || document.documentElement.clientHeight) &&
53
+ boundingBox.right <=
54
+ (window.innerWidth || document.documentElement.clientWidth);
55
+ if (!isElementInViewport) {
56
+ element.scrollIntoView();
57
+ }
58
+ }
59
+ };
60
+ exports.scrollIntoView = scrollIntoView;
61
+ const performItemsMove = (items, target, onChangeChildren) => {
62
+ var _a;
63
+ const numberOfDragItemsBeforeTarget = !target.childIndex
64
+ ? 0
65
+ : target.item
66
+ .getChildren()
67
+ .slice(0, target.childIndex)
68
+ .filter((child) => items.some((item) => item.getId() === child.getId()))
69
+ .length;
70
+ // TODO bulk sibling changes together
71
+ for (const item of items) {
72
+ const siblings = (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.getChildren();
73
+ if (siblings) {
74
+ onChangeChildren(item.getParent(), siblings.filter((sibling) => sibling.getId() !== item.getId()));
75
+ }
76
+ }
77
+ if (target.childIndex === null) {
78
+ onChangeChildren(target.item, [...target.item.getChildren(), ...items]);
79
+ items[0].getTree().rebuildTree();
80
+ return;
81
+ }
82
+ const oldChildren = target.item.getChildren();
83
+ const newChildren = [
84
+ ...oldChildren.slice(0, target.childIndex - numberOfDragItemsBeforeTarget),
85
+ ...items,
86
+ ...oldChildren.slice(target.childIndex - numberOfDragItemsBeforeTarget),
87
+ ];
88
+ onChangeChildren(target.item, newChildren);
89
+ items[0].getTree().rebuildTree();
90
+ };
91
+ exports.performItemsMove = performItemsMove;
92
+ const poll = (fn, interval = 100, timeout = 1000) => new Promise((resolve) => {
93
+ let clear;
94
+ const i = setInterval(() => {
95
+ if (fn()) {
96
+ resolve();
97
+ clearInterval(i);
98
+ clearTimeout(clear);
99
+ }
100
+ }, interval);
101
+ clear = setTimeout(() => {
102
+ clearInterval(i);
103
+ }, timeout);
104
+ });
105
+ exports.poll = poll;
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@headless-tree/core",
3
+ "version": "0.0.1",
4
+ "main": "lib/index.js",
5
+ "types": "lib/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "start": "tsc -w"
9
+ },
10
+ "author": "Lukas Bach <npm@lukasbach.com>",
11
+ "license": "MIT",
12
+ "devDependencies": {
13
+ "typescript": "^5.0.4"
14
+ }
15
+ }