@headless-tree/core 0.0.1 → 0.0.2

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 (115) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/lib/{features → cjs/features}/drag-and-drop/feature.js +0 -46
  3. package/lib/{features → cjs/features}/drag-and-drop/types.d.ts +1 -1
  4. package/lib/{features → cjs/features}/drag-and-drop/utils.d.ts +0 -1
  5. package/lib/{features → cjs/features}/drag-and-drop/utils.js +1 -60
  6. package/lib/{features → cjs/features}/hotkeys-core/feature.js +0 -1
  7. package/lib/{features → cjs/features}/tree/feature.js +0 -2
  8. package/lib/esm/core/create-tree.d.ts +2 -0
  9. package/lib/esm/core/create-tree.js +112 -0
  10. package/lib/esm/data-adapters/nested-data-adapter.d.ts +9 -0
  11. package/lib/esm/data-adapters/nested-data-adapter.js +28 -0
  12. package/lib/esm/data-adapters/types.d.ts +7 -0
  13. package/lib/esm/data-adapters/types.js +1 -0
  14. package/lib/esm/features/async-data-loader/feature.d.ts +5 -0
  15. package/lib/esm/features/async-data-loader/feature.js +77 -0
  16. package/lib/esm/features/async-data-loader/types.d.ts +41 -0
  17. package/lib/esm/features/async-data-loader/types.js +1 -0
  18. package/lib/esm/features/drag-and-drop/feature.d.ts +3 -0
  19. package/lib/esm/features/drag-and-drop/feature.js +95 -0
  20. package/lib/esm/features/drag-and-drop/types.d.ts +49 -0
  21. package/lib/esm/features/drag-and-drop/types.js +6 -0
  22. package/lib/esm/features/drag-and-drop/utils.d.ts +6 -0
  23. package/lib/esm/features/drag-and-drop/utils.js +55 -0
  24. package/lib/esm/features/expand-all/feature.d.ts +6 -0
  25. package/lib/esm/features/expand-all/feature.js +36 -0
  26. package/lib/esm/features/expand-all/types.d.ts +17 -0
  27. package/lib/esm/features/expand-all/types.js +1 -0
  28. package/lib/esm/features/hotkeys-core/feature.d.ts +4 -0
  29. package/lib/esm/features/hotkeys-core/feature.js +69 -0
  30. package/lib/esm/features/hotkeys-core/types.d.ts +25 -0
  31. package/lib/esm/features/hotkeys-core/types.js +1 -0
  32. package/lib/esm/features/main/types.d.ts +36 -0
  33. package/lib/esm/features/main/types.js +1 -0
  34. package/lib/esm/features/renaming/feature.d.ts +5 -0
  35. package/lib/esm/features/renaming/feature.js +62 -0
  36. package/lib/esm/features/renaming/types.d.ts +27 -0
  37. package/lib/esm/features/renaming/types.js +1 -0
  38. package/lib/esm/features/search/feature.d.ts +5 -0
  39. package/lib/esm/features/search/feature.js +87 -0
  40. package/lib/esm/features/search/types.d.ts +33 -0
  41. package/lib/esm/features/search/types.js +1 -0
  42. package/lib/esm/features/selection/feature.d.ts +5 -0
  43. package/lib/esm/features/selection/feature.js +109 -0
  44. package/lib/esm/features/selection/types.d.ts +21 -0
  45. package/lib/esm/features/selection/types.js +1 -0
  46. package/lib/esm/features/sync-data-loader/feature.d.ts +4 -0
  47. package/lib/esm/features/sync-data-loader/feature.js +6 -0
  48. package/lib/esm/features/sync-data-loader/types.d.ts +19 -0
  49. package/lib/esm/features/sync-data-loader/types.js +1 -0
  50. package/lib/esm/features/tree/feature.d.ts +6 -0
  51. package/lib/esm/features/tree/feature.js +211 -0
  52. package/lib/esm/features/tree/types.d.ts +57 -0
  53. package/lib/esm/features/tree/types.js +1 -0
  54. package/lib/esm/index.d.ts +21 -0
  55. package/lib/esm/index.js +21 -0
  56. package/lib/esm/mddocs-entry.d.ts +21 -0
  57. package/lib/esm/mddocs-entry.js +1 -0
  58. package/lib/esm/types/core.d.ts +68 -0
  59. package/lib/esm/types/core.js +1 -0
  60. package/lib/esm/types/deep-merge.d.ts +13 -0
  61. package/lib/esm/types/deep-merge.js +1 -0
  62. package/lib/esm/utils.d.ts +9 -0
  63. package/lib/esm/utils.js +96 -0
  64. package/package.json +11 -4
  65. package/tsconfig.json +7 -7
  66. /package/lib/{core → cjs/core}/create-tree.d.ts +0 -0
  67. /package/lib/{core → cjs/core}/create-tree.js +0 -0
  68. /package/lib/{data-adapters → cjs/data-adapters}/nested-data-adapter.d.ts +0 -0
  69. /package/lib/{data-adapters → cjs/data-adapters}/nested-data-adapter.js +0 -0
  70. /package/lib/{data-adapters → cjs/data-adapters}/types.d.ts +0 -0
  71. /package/lib/{data-adapters → cjs/data-adapters}/types.js +0 -0
  72. /package/lib/{features → cjs/features}/async-data-loader/feature.d.ts +0 -0
  73. /package/lib/{features → cjs/features}/async-data-loader/feature.js +0 -0
  74. /package/lib/{features → cjs/features}/async-data-loader/types.d.ts +0 -0
  75. /package/lib/{features → cjs/features}/async-data-loader/types.js +0 -0
  76. /package/lib/{features → cjs/features}/drag-and-drop/feature.d.ts +0 -0
  77. /package/lib/{features → cjs/features}/drag-and-drop/types.js +0 -0
  78. /package/lib/{features → cjs/features}/expand-all/feature.d.ts +0 -0
  79. /package/lib/{features → cjs/features}/expand-all/feature.js +0 -0
  80. /package/lib/{features → cjs/features}/expand-all/types.d.ts +0 -0
  81. /package/lib/{features → cjs/features}/expand-all/types.js +0 -0
  82. /package/lib/{features → cjs/features}/hotkeys-core/feature.d.ts +0 -0
  83. /package/lib/{features → cjs/features}/hotkeys-core/types.d.ts +0 -0
  84. /package/lib/{features → cjs/features}/hotkeys-core/types.js +0 -0
  85. /package/lib/{features → cjs/features}/main/types.d.ts +0 -0
  86. /package/lib/{features → cjs/features}/main/types.js +0 -0
  87. /package/lib/{features → cjs/features}/renaming/feature.d.ts +0 -0
  88. /package/lib/{features → cjs/features}/renaming/feature.js +0 -0
  89. /package/lib/{features → cjs/features}/renaming/types.d.ts +0 -0
  90. /package/lib/{features → cjs/features}/renaming/types.js +0 -0
  91. /package/lib/{features → cjs/features}/search/feature.d.ts +0 -0
  92. /package/lib/{features → cjs/features}/search/feature.js +0 -0
  93. /package/lib/{features → cjs/features}/search/types.d.ts +0 -0
  94. /package/lib/{features → cjs/features}/search/types.js +0 -0
  95. /package/lib/{features → cjs/features}/selection/feature.d.ts +0 -0
  96. /package/lib/{features → cjs/features}/selection/feature.js +0 -0
  97. /package/lib/{features → cjs/features}/selection/types.d.ts +0 -0
  98. /package/lib/{features → cjs/features}/selection/types.js +0 -0
  99. /package/lib/{features → cjs/features}/sync-data-loader/feature.d.ts +0 -0
  100. /package/lib/{features → cjs/features}/sync-data-loader/feature.js +0 -0
  101. /package/lib/{features → cjs/features}/sync-data-loader/types.d.ts +0 -0
  102. /package/lib/{features → cjs/features}/sync-data-loader/types.js +0 -0
  103. /package/lib/{features → cjs/features}/tree/feature.d.ts +0 -0
  104. /package/lib/{features → cjs/features}/tree/types.d.ts +0 -0
  105. /package/lib/{features → cjs/features}/tree/types.js +0 -0
  106. /package/lib/{index.d.ts → cjs/index.d.ts} +0 -0
  107. /package/lib/{index.js → cjs/index.js} +0 -0
  108. /package/lib/{mddocs-entry.d.ts → cjs/mddocs-entry.d.ts} +0 -0
  109. /package/lib/{mddocs-entry.js → cjs/mddocs-entry.js} +0 -0
  110. /package/lib/{types → cjs/types}/core.d.ts +0 -0
  111. /package/lib/{types → cjs/types}/core.js +0 -0
  112. /package/lib/{types → cjs/types}/deep-merge.d.ts +0 -0
  113. /package/lib/{types → cjs/types}/deep-merge.js +0 -0
  114. /package/lib/{utils.d.ts → cjs/utils.d.ts} +0 -0
  115. /package/lib/{utils.js → cjs/utils.js} +0 -0
@@ -0,0 +1,19 @@
1
+ export type SyncTreeDataLoader<T> = {
2
+ getItem: (itemId: string) => T;
3
+ getChildren: (itemId: string) => string[];
4
+ };
5
+ export type SyncDataLoaderFeatureDef<T> = {
6
+ state: {};
7
+ config: {
8
+ rootItemId: string;
9
+ dataLoader: SyncTreeDataLoader<T>;
10
+ };
11
+ treeInstance: {
12
+ retrieveItemData: (itemId: string) => T;
13
+ retrieveChildrenIds: (itemId: string) => string[];
14
+ };
15
+ itemInstance: {
16
+ isLoading: () => boolean;
17
+ };
18
+ hotkeys: never;
19
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import { FeatureImplementation } from "../../types/core";
2
+ import { TreeFeatureDef } from "./types";
3
+ import { MainFeatureDef } from "../main/types";
4
+ import { HotkeysCoreFeatureDef } from "../hotkeys-core/types";
5
+ import { SyncDataLoaderFeatureDef } from "../sync-data-loader/types";
6
+ export declare const treeFeature: FeatureImplementation<any, TreeFeatureDef<any>, MainFeatureDef | TreeFeatureDef<any> | HotkeysCoreFeatureDef<any> | SyncDataLoaderFeatureDef<any>>;
@@ -0,0 +1,211 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { makeStateUpdater, memo, poll } from "../../utils";
11
+ export const treeFeature = {
12
+ key: "tree",
13
+ dependingFeatures: ["main"],
14
+ getInitialState: (initialState) => (Object.assign({ expandedItems: [], focusedItem: null }, initialState)),
15
+ getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setExpandedItems: makeStateUpdater("expandedItems", tree), setFocusedItem: makeStateUpdater("focusedItem", tree) }, defaultConfig)),
16
+ createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: () => {
17
+ throw new Error("No data-loader registered");
18
+ }, retrieveChildrenIds: () => {
19
+ throw new Error("No data-loader registered");
20
+ }, isItemExpanded: (itemId) => instance.getState().expandedItems.includes(itemId), getItemsMeta: () => {
21
+ const { rootItemId } = instance.getConfig();
22
+ const { expandedItems } = instance.getState();
23
+ // console.log("!", instance.getConfig());
24
+ const flatItems = [];
25
+ const recursiveAdd = (itemId, parentId, level, setSize, posInSet) => {
26
+ var _a;
27
+ flatItems.push({
28
+ itemId,
29
+ level,
30
+ index: flatItems.length,
31
+ parentId,
32
+ setSize,
33
+ posInSet,
34
+ });
35
+ if (expandedItems.includes(itemId)) {
36
+ const children = (_a = instance.retrieveChildrenIds(itemId)) !== null && _a !== void 0 ? _a : [];
37
+ let i = 0;
38
+ for (const childId of children) {
39
+ recursiveAdd(childId, itemId, level + 1, children.length, i++);
40
+ }
41
+ }
42
+ };
43
+ const children = instance.retrieveChildrenIds(rootItemId);
44
+ let i = 0;
45
+ for (const itemId of children) {
46
+ recursiveAdd(itemId, rootItemId, 0, children.length, i++);
47
+ }
48
+ return flatItems;
49
+ }, expandItem: (itemId) => {
50
+ var _a, _b, _c;
51
+ if (!instance.getItemInstance(itemId).isFolder()) {
52
+ return;
53
+ }
54
+ if ((_a = instance.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
55
+ return;
56
+ }
57
+ (_c = (_b = instance
58
+ .getConfig()).setExpandedItems) === null || _c === void 0 ? void 0 : _c.call(_b, (expandedItems) => [...expandedItems, itemId]);
59
+ instance.rebuildTree();
60
+ }, collapseItem: (itemId) => {
61
+ var _a, _b;
62
+ if (!instance.getItemInstance(itemId).isFolder()) {
63
+ return;
64
+ }
65
+ (_b = (_a = instance
66
+ .getConfig()).setExpandedItems) === null || _b === void 0 ? void 0 : _b.call(_a, (expandedItems) => expandedItems.filter((id) => id !== itemId));
67
+ instance.rebuildTree();
68
+ },
69
+ // TODO memo
70
+ getFocusedItem: () => {
71
+ var _a, _b;
72
+ return ((_b = instance.getItemInstance((_a = instance.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : instance.getItems()[0]);
73
+ }, focusItem: (itemId) => {
74
+ var _a, _b;
75
+ (_b = (_a = instance.getConfig()).setFocusedItem) === null || _b === void 0 ? void 0 : _b.call(_a, itemId);
76
+ }, focusNextItem: () => {
77
+ const { index } = instance.getFocusedItem().getItemMeta();
78
+ const nextIndex = Math.min(index + 1, instance.getItems().length - 1);
79
+ instance.focusItem(instance.getItems()[nextIndex].getId());
80
+ }, focusPreviousItem: () => {
81
+ const { index } = instance.getFocusedItem().getItemMeta();
82
+ const nextIndex = Math.max(index - 1, 0);
83
+ instance.focusItem(instance.getItems()[nextIndex].getId());
84
+ }, updateDomFocus: (scrollIntoView) => {
85
+ // Required because if the state is managed outside in react, the state only updated during next render
86
+ setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
87
+ var _a, _b;
88
+ const focusedItem = instance.getFocusedItem();
89
+ (_b = (_a = instance.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, focusedItem);
90
+ yield poll(() => focusedItem.getElement() !== null, 20);
91
+ const focusedElement = focusedItem.getElement();
92
+ if (!focusedElement)
93
+ return;
94
+ focusedElement.focus();
95
+ // if (scrollIntoView) {
96
+ // focusedElement.scrollIntoView();
97
+ // }
98
+ }));
99
+ }, getContainerProps: () => {
100
+ var _a;
101
+ return (Object.assign(Object.assign({}, (_a = prev.getContainerProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "tree", ariaLabel: "", ariaActivedescendant: "" }));
102
+ } })),
103
+ createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { isLoading: () => {
104
+ throw new Error("No data-loader registered");
105
+ }, getId: () => item.getItemMeta().itemId, getProps: () => {
106
+ var _a;
107
+ const itemMeta = item.getItemMeta();
108
+ 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) => {
109
+ item.setFocused();
110
+ item.primaryAction();
111
+ if (e.ctrlKey || e.shiftKey || e.metaKey) {
112
+ return;
113
+ }
114
+ if (!item.isFolder()) {
115
+ return;
116
+ }
117
+ if (item.isExpanded()) {
118
+ item.collapse();
119
+ }
120
+ else {
121
+ item.expand();
122
+ }
123
+ } });
124
+ }, 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 ||
125
+ (tree.getState().focusedItem === null && item.getItemMeta().index === 0), isFolder: () => item.getItemMeta().level === -1 ||
126
+ tree.getConfig().isItemFolder(item), getItemName: () => {
127
+ const config = tree.getConfig();
128
+ return config.getItemName(item);
129
+ }, 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: memo((itemMeta) => {
130
+ for (let i = itemMeta.index - 1; i >= 0; i--) {
131
+ const potentialParent = tree.getItems()[i];
132
+ if (potentialParent.getItemMeta().level < itemMeta.level) {
133
+ return potentialParent;
134
+ }
135
+ }
136
+ return tree.getItemInstance(tree.getConfig().rootItemId);
137
+ }, () => [item.getItemMeta()]), getIndexInParent: () => {
138
+ var _a, _b;
139
+ return item.getItemMeta().index -
140
+ ((_b = (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.getItemMeta().index) !== null && _b !== void 0 ? _b : 0) -
141
+ 1;
142
+ }, getChildren: () => tree
143
+ .retrieveChildrenIds(item.getItemMeta().itemId)
144
+ .map((id) => tree.getItemInstance(id)), getTree: () => tree, getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1], getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1] })),
145
+ hotkeys: {
146
+ focusNextItem: {
147
+ hotkey: "ArrowDown",
148
+ canRepeat: true,
149
+ preventDefault: true,
150
+ 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; },
151
+ handler: (e, tree) => {
152
+ tree.focusNextItem();
153
+ tree.updateDomFocus();
154
+ },
155
+ },
156
+ focusPreviousItem: {
157
+ hotkey: "ArrowUp",
158
+ canRepeat: true,
159
+ preventDefault: true,
160
+ 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; },
161
+ handler: (e, tree) => {
162
+ tree.focusPreviousItem();
163
+ tree.updateDomFocus();
164
+ },
165
+ },
166
+ expandOrDown: {
167
+ hotkey: "ArrowRight",
168
+ canRepeat: true,
169
+ handler: (e, tree) => {
170
+ const item = tree.getFocusedItem();
171
+ if (item.isExpanded() || !item.isFolder()) {
172
+ tree.focusNextItem();
173
+ tree.updateDomFocus();
174
+ }
175
+ else {
176
+ item.expand();
177
+ }
178
+ },
179
+ },
180
+ collapseOrUp: {
181
+ hotkey: "ArrowLeft",
182
+ canRepeat: true,
183
+ handler: (e, tree) => {
184
+ var _a;
185
+ const item = tree.getFocusedItem();
186
+ if ((!item.isExpanded() || !item.isFolder()) &&
187
+ item.getItemMeta().level !== 0) {
188
+ (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.setFocused();
189
+ tree.updateDomFocus(true);
190
+ }
191
+ else {
192
+ item.collapse();
193
+ }
194
+ },
195
+ },
196
+ focusFirstItem: {
197
+ hotkey: "Home",
198
+ handler: (e, tree) => {
199
+ tree.focusItem(tree.getItems()[0].getId());
200
+ tree.updateDomFocus();
201
+ },
202
+ },
203
+ focusLastItem: {
204
+ hotkey: "End",
205
+ handler: (e, tree) => {
206
+ tree.focusItem(tree.getItems()[tree.getItems().length - 1].getId());
207
+ tree.updateDomFocus();
208
+ },
209
+ },
210
+ },
211
+ };
@@ -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 @@
1
+ export {};
@@ -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";
@@ -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";
@@ -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 @@
1
+ export * from ".";
@@ -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 @@
1
+ export {};
@@ -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 @@
1
+ export {};
@@ -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>;
@@ -0,0 +1,96 @@
1
+ export const memo = (fn, deps) => {
2
+ let value;
3
+ let oldDeps = null;
4
+ return () => {
5
+ const newDeps = deps();
6
+ if (!value) {
7
+ value = fn(...newDeps);
8
+ oldDeps = newDeps;
9
+ return value;
10
+ }
11
+ const match = oldDeps &&
12
+ oldDeps.length === newDeps.length &&
13
+ !oldDeps.some((dep, i) => dep !== newDeps[i]);
14
+ if (match) {
15
+ return value;
16
+ }
17
+ value = fn(...newDeps);
18
+ oldDeps = newDeps;
19
+ return value;
20
+ };
21
+ };
22
+ export function functionalUpdate(updater, input) {
23
+ return typeof updater === "function"
24
+ ? updater(input)
25
+ : updater;
26
+ }
27
+ export function makeStateUpdater(key, instance) {
28
+ return (updater) => {
29
+ instance.setState((old) => {
30
+ return Object.assign(Object.assign({}, old), { [key]: functionalUpdate(updater, old[key]) });
31
+ });
32
+ };
33
+ }
34
+ export const scrollIntoView = (element) => {
35
+ if (!element) {
36
+ return;
37
+ }
38
+ if (element.scrollIntoViewIfNeeded) {
39
+ element.scrollIntoViewIfNeeded();
40
+ }
41
+ else {
42
+ const boundingBox = element.getBoundingClientRect();
43
+ const isElementInViewport = boundingBox.top >= 0 &&
44
+ boundingBox.left >= 0 &&
45
+ boundingBox.bottom <=
46
+ (window.innerHeight || document.documentElement.clientHeight) &&
47
+ boundingBox.right <=
48
+ (window.innerWidth || document.documentElement.clientWidth);
49
+ if (!isElementInViewport) {
50
+ element.scrollIntoView();
51
+ }
52
+ }
53
+ };
54
+ export const performItemsMove = (items, target, onChangeChildren) => {
55
+ var _a;
56
+ const numberOfDragItemsBeforeTarget = !target.childIndex
57
+ ? 0
58
+ : target.item
59
+ .getChildren()
60
+ .slice(0, target.childIndex)
61
+ .filter((child) => items.some((item) => item.getId() === child.getId()))
62
+ .length;
63
+ // TODO bulk sibling changes together
64
+ for (const item of items) {
65
+ const siblings = (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.getChildren();
66
+ if (siblings) {
67
+ onChangeChildren(item.getParent(), siblings.filter((sibling) => sibling.getId() !== item.getId()));
68
+ }
69
+ }
70
+ if (target.childIndex === null) {
71
+ onChangeChildren(target.item, [...target.item.getChildren(), ...items]);
72
+ items[0].getTree().rebuildTree();
73
+ return;
74
+ }
75
+ const oldChildren = target.item.getChildren();
76
+ const newChildren = [
77
+ ...oldChildren.slice(0, target.childIndex - numberOfDragItemsBeforeTarget),
78
+ ...items,
79
+ ...oldChildren.slice(target.childIndex - numberOfDragItemsBeforeTarget),
80
+ ];
81
+ onChangeChildren(target.item, newChildren);
82
+ items[0].getTree().rebuildTree();
83
+ };
84
+ export const poll = (fn, interval = 100, timeout = 1000) => new Promise((resolve) => {
85
+ let clear;
86
+ const i = setInterval(() => {
87
+ if (fn()) {
88
+ resolve();
89
+ clearInterval(i);
90
+ clearTimeout(clear);
91
+ }
92
+ }, interval);
93
+ clear = setTimeout(() => {
94
+ clearInterval(i);
95
+ }, timeout);
96
+ });
package/package.json CHANGED
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "@headless-tree/core",
3
- "version": "0.0.1",
4
- "main": "lib/index.js",
5
- "types": "lib/index.d.ts",
3
+ "version": "0.0.2",
4
+ "main": "lib/cjs/index.js",
5
+ "module": "lib/esm/index.js",
6
+ "types": "lib/esm/index.d.ts",
6
7
  "scripts": {
7
- "build": "tsc",
8
+ "build:cjs": "tsc",
9
+ "build:esm": "tsc -m es2015 --outDir lib/esm",
8
10
  "start": "tsc -w"
9
11
  },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git@github.com:lukasbach/headless-tree.git",
15
+ "directory": "packages/core"
16
+ },
10
17
  "author": "Lukas Bach <npm@lukasbach.com>",
11
18
  "license": "MIT",
12
19
  "devDependencies": {
package/tsconfig.json CHANGED
@@ -1,7 +1,7 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "include": ["./src/**/*"],
4
- "compilerOptions": {
5
- "outDir": "lib"
6
- }
7
- }
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "include": ["./src/**/*"],
4
+ "compilerOptions": {
5
+ "outDir": "lib/cjs"
6
+ }
7
+ }
File without changes
File without changes