@headless-tree/core 0.0.10 → 0.0.12

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 (148) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/cjs/core/build-proxified-instance.d.ts +2 -0
  3. package/lib/cjs/core/build-proxified-instance.js +58 -0
  4. package/lib/cjs/core/build-static-instance.d.ts +2 -0
  5. package/lib/cjs/core/build-static-instance.js +26 -0
  6. package/lib/cjs/core/create-tree.js +62 -40
  7. package/lib/cjs/features/async-data-loader/feature.d.ts +1 -4
  8. package/lib/cjs/features/async-data-loader/feature.js +35 -23
  9. package/lib/cjs/features/async-data-loader/types.d.ts +4 -6
  10. package/lib/cjs/features/drag-and-drop/feature.d.ts +2 -3
  11. package/lib/cjs/features/drag-and-drop/feature.js +79 -44
  12. package/lib/cjs/features/drag-and-drop/types.d.ts +15 -6
  13. package/lib/cjs/features/drag-and-drop/utils.d.ts +2 -3
  14. package/lib/cjs/features/drag-and-drop/utils.js +140 -37
  15. package/lib/cjs/features/expand-all/feature.d.ts +1 -5
  16. package/lib/cjs/features/expand-all/feature.js +12 -6
  17. package/lib/cjs/features/hotkeys-core/feature.d.ts +1 -3
  18. package/lib/cjs/features/main/types.d.ts +8 -2
  19. package/lib/cjs/features/prop-memoization/feature.d.ts +2 -0
  20. package/lib/cjs/features/prop-memoization/feature.js +48 -0
  21. package/lib/cjs/features/prop-memoization/types.d.ts +10 -0
  22. package/lib/cjs/features/prop-memoization/types.js +2 -0
  23. package/lib/cjs/features/renaming/feature.d.ts +1 -4
  24. package/lib/cjs/features/renaming/feature.js +36 -22
  25. package/lib/cjs/features/renaming/types.d.ts +2 -2
  26. package/lib/cjs/features/search/feature.d.ts +1 -4
  27. package/lib/cjs/features/search/feature.js +38 -24
  28. package/lib/cjs/features/search/types.d.ts +0 -1
  29. package/lib/cjs/features/selection/feature.d.ts +1 -4
  30. package/lib/cjs/features/selection/feature.js +54 -35
  31. package/lib/cjs/features/selection/types.d.ts +1 -1
  32. package/lib/cjs/features/sync-data-loader/feature.d.ts +1 -3
  33. package/lib/cjs/features/sync-data-loader/feature.js +7 -2
  34. package/lib/cjs/features/tree/feature.d.ts +1 -5
  35. package/lib/cjs/features/tree/feature.js +97 -92
  36. package/lib/cjs/features/tree/types.d.ts +5 -8
  37. package/lib/cjs/index.d.ts +5 -1
  38. package/lib/cjs/index.js +4 -1
  39. package/lib/cjs/mddocs-entry.d.ts +10 -0
  40. package/lib/cjs/test-utils/test-tree-do.d.ts +23 -0
  41. package/lib/cjs/test-utils/test-tree-do.js +99 -0
  42. package/lib/cjs/test-utils/test-tree-expect.d.ts +15 -0
  43. package/lib/cjs/test-utils/test-tree-expect.js +62 -0
  44. package/lib/cjs/test-utils/test-tree.d.ts +47 -0
  45. package/lib/cjs/test-utils/test-tree.js +203 -0
  46. package/lib/cjs/types/core.d.ts +39 -24
  47. package/lib/cjs/utilities/errors.d.ts +1 -0
  48. package/lib/cjs/utilities/errors.js +5 -0
  49. package/lib/cjs/utilities/insert-items-at-target.js +10 -3
  50. package/lib/cjs/utilities/remove-items-from-parents.js +14 -8
  51. package/lib/cjs/utils.d.ts +3 -3
  52. package/lib/cjs/utils.js +6 -6
  53. package/lib/esm/core/build-proxified-instance.d.ts +2 -0
  54. package/lib/esm/core/build-proxified-instance.js +54 -0
  55. package/lib/esm/core/build-static-instance.d.ts +2 -0
  56. package/lib/esm/core/build-static-instance.js +22 -0
  57. package/lib/esm/core/create-tree.js +62 -40
  58. package/lib/esm/features/async-data-loader/feature.d.ts +1 -4
  59. package/lib/esm/features/async-data-loader/feature.js +35 -23
  60. package/lib/esm/features/async-data-loader/types.d.ts +4 -6
  61. package/lib/esm/features/drag-and-drop/feature.d.ts +2 -3
  62. package/lib/esm/features/drag-and-drop/feature.js +79 -44
  63. package/lib/esm/features/drag-and-drop/types.d.ts +15 -6
  64. package/lib/esm/features/drag-and-drop/utils.d.ts +2 -3
  65. package/lib/esm/features/drag-and-drop/utils.js +138 -34
  66. package/lib/esm/features/expand-all/feature.d.ts +1 -5
  67. package/lib/esm/features/expand-all/feature.js +12 -6
  68. package/lib/esm/features/hotkeys-core/feature.d.ts +1 -3
  69. package/lib/esm/features/main/types.d.ts +8 -2
  70. package/lib/esm/features/prop-memoization/feature.d.ts +2 -0
  71. package/lib/esm/features/prop-memoization/feature.js +45 -0
  72. package/lib/esm/features/prop-memoization/types.d.ts +10 -0
  73. package/lib/esm/features/prop-memoization/types.js +1 -0
  74. package/lib/esm/features/renaming/feature.d.ts +1 -4
  75. package/lib/esm/features/renaming/feature.js +36 -22
  76. package/lib/esm/features/renaming/types.d.ts +2 -2
  77. package/lib/esm/features/search/feature.d.ts +1 -4
  78. package/lib/esm/features/search/feature.js +38 -24
  79. package/lib/esm/features/search/types.d.ts +0 -1
  80. package/lib/esm/features/selection/feature.d.ts +1 -4
  81. package/lib/esm/features/selection/feature.js +54 -35
  82. package/lib/esm/features/selection/types.d.ts +1 -1
  83. package/lib/esm/features/sync-data-loader/feature.d.ts +1 -3
  84. package/lib/esm/features/sync-data-loader/feature.js +7 -2
  85. package/lib/esm/features/tree/feature.d.ts +1 -5
  86. package/lib/esm/features/tree/feature.js +98 -93
  87. package/lib/esm/features/tree/types.d.ts +5 -8
  88. package/lib/esm/index.d.ts +5 -1
  89. package/lib/esm/index.js +4 -1
  90. package/lib/esm/mddocs-entry.d.ts +10 -0
  91. package/lib/esm/test-utils/test-tree-do.d.ts +23 -0
  92. package/lib/esm/test-utils/test-tree-do.js +95 -0
  93. package/lib/esm/test-utils/test-tree-expect.d.ts +15 -0
  94. package/lib/esm/test-utils/test-tree-expect.js +58 -0
  95. package/lib/esm/test-utils/test-tree.d.ts +47 -0
  96. package/lib/esm/test-utils/test-tree.js +199 -0
  97. package/lib/esm/types/core.d.ts +39 -24
  98. package/lib/esm/utilities/errors.d.ts +1 -0
  99. package/lib/esm/utilities/errors.js +1 -0
  100. package/lib/esm/utilities/insert-items-at-target.js +10 -3
  101. package/lib/esm/utilities/remove-items-from-parents.js +14 -8
  102. package/lib/esm/utils.d.ts +3 -3
  103. package/lib/esm/utils.js +3 -3
  104. package/package.json +7 -3
  105. package/src/core/build-proxified-instance.ts +117 -0
  106. package/src/core/build-static-instance.ts +27 -0
  107. package/src/core/core.spec.ts +210 -0
  108. package/src/core/create-tree.ts +73 -78
  109. package/src/features/async-data-loader/async-data-loader.spec.ts +124 -0
  110. package/src/features/async-data-loader/feature.ts +34 -44
  111. package/src/features/async-data-loader/types.ts +4 -6
  112. package/src/features/drag-and-drop/drag-and-drop.spec.ts +717 -0
  113. package/src/features/drag-and-drop/feature.ts +88 -63
  114. package/src/features/drag-and-drop/types.ts +24 -10
  115. package/src/features/drag-and-drop/utils.ts +197 -56
  116. package/src/features/expand-all/expand-all.spec.ts +56 -0
  117. package/src/features/expand-all/feature.ts +9 -24
  118. package/src/features/hotkeys-core/feature.ts +5 -14
  119. package/src/features/main/types.ts +14 -1
  120. package/src/features/prop-memoization/feature.ts +51 -0
  121. package/src/features/prop-memoization/prop-memoization.spec.ts +68 -0
  122. package/src/features/prop-memoization/types.ts +11 -0
  123. package/src/features/renaming/feature.ts +37 -45
  124. package/src/features/renaming/renaming.spec.ts +127 -0
  125. package/src/features/renaming/types.ts +2 -2
  126. package/src/features/search/feature.ts +36 -46
  127. package/src/features/search/search.spec.ts +117 -0
  128. package/src/features/search/types.ts +0 -1
  129. package/src/features/selection/feature.ts +50 -53
  130. package/src/features/selection/selection.spec.ts +219 -0
  131. package/src/features/selection/types.ts +0 -2
  132. package/src/features/sync-data-loader/feature.ts +9 -18
  133. package/src/features/tree/feature.ts +101 -144
  134. package/src/features/tree/tree.spec.ts +475 -0
  135. package/src/features/tree/types.ts +5 -9
  136. package/src/index.ts +6 -1
  137. package/src/mddocs-entry.ts +13 -0
  138. package/src/test-utils/test-tree-do.ts +136 -0
  139. package/src/test-utils/test-tree-expect.ts +86 -0
  140. package/src/test-utils/test-tree.ts +227 -0
  141. package/src/types/core.ts +76 -108
  142. package/src/utilities/errors.ts +2 -0
  143. package/src/utilities/insert-items-at-target.ts +10 -3
  144. package/src/utilities/remove-items-from-parents.ts +15 -10
  145. package/src/utils.spec.ts +89 -0
  146. package/src/utils.ts +6 -6
  147. package/tsconfig.json +1 -0
  148. package/vitest.config.ts +6 -0
@@ -1,5 +1,2 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
- import { SelectionFeatureDef } from "./types";
3
- import { MainFeatureDef } from "../main/types";
4
- import { TreeFeatureDef } from "../tree/types";
5
- export declare const selectionFeature: FeatureImplementation<any, SelectionFeatureDef<any>, MainFeatureDef | TreeFeatureDef<any> | SelectionFeatureDef<any>>;
2
+ export declare const selectionFeature: FeatureImplementation;
@@ -9,25 +9,31 @@ exports.selectionFeature = {
9
9
  stateHandlerNames: {
10
10
  selectedItems: "setSelectedItems",
11
11
  },
12
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { setSelectedItems: (selectedItems) => {
13
- instance.applySubStateUpdate("selectedItems", selectedItems);
14
- },
12
+ treeInstance: {
13
+ setSelectedItems: ({ tree }, selectedItems) => {
14
+ tree.applySubStateUpdate("selectedItems", selectedItems);
15
+ },
15
16
  // TODO memo
16
- getSelectedItems: () => {
17
- return instance.getState().selectedItems.map(instance.getItemInstance);
18
- } })),
19
- createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { select: () => {
17
+ getSelectedItems: ({ tree }) => {
18
+ return tree.getState().selectedItems.map(tree.getItemInstance);
19
+ },
20
+ },
21
+ itemInstance: {
22
+ select: ({ tree, itemId }) => {
20
23
  const { selectedItems } = tree.getState();
21
- tree.setSelectedItems(selectedItems.includes(item.getItemMeta().itemId)
24
+ tree.setSelectedItems(selectedItems.includes(itemId)
22
25
  ? selectedItems
23
- : [...selectedItems, item.getItemMeta().itemId]);
24
- }, deselect: () => {
26
+ : [...selectedItems, itemId]);
27
+ },
28
+ deselect: ({ tree, itemId }) => {
25
29
  const { selectedItems } = tree.getState();
26
- tree.setSelectedItems(selectedItems.filter((id) => id !== item.getItemMeta().itemId));
27
- }, isSelected: () => {
30
+ tree.setSelectedItems(selectedItems.filter((id) => id !== itemId));
31
+ },
32
+ isSelected: ({ tree, item }) => {
28
33
  const { selectedItems } = tree.getState();
29
34
  return selectedItems.includes(item.getItemMeta().itemId);
30
- }, selectUpTo: (ctrl) => {
35
+ },
36
+ selectUpTo: ({ tree, item }, ctrl) => {
31
37
  const indexA = item.getItemMeta().index;
32
38
  // TODO dont use focused item as anchor, but last primary-clicked item
33
39
  const indexB = tree.getFocusedItem().getItemMeta().index;
@@ -45,14 +51,16 @@ exports.selectionFeature = {
45
51
  ...new Set([...selectedItems, ...newSelectedItems]),
46
52
  ];
47
53
  tree.setSelectedItems(uniqueSelectedItems);
48
- }, toggleSelect: () => {
54
+ },
55
+ toggleSelect: ({ item }) => {
49
56
  if (item.isSelected()) {
50
57
  item.deselect();
51
58
  }
52
59
  else {
53
60
  item.select();
54
61
  }
55
- }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { "aria-selected": item.isSelected() ? "true" : "false", onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
62
+ },
63
+ getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { "aria-selected": item.isSelected() ? "true" : "false", onClick: (e) => {
56
64
  var _a, _b;
57
65
  if (e.shiftKey) {
58
66
  item.selectUpTo(e.ctrlKey || e.metaKey);
@@ -63,8 +71,9 @@ exports.selectionFeature = {
63
71
  else {
64
72
  tree.setSelectedItems([item.getItemMeta().itemId]);
65
73
  }
66
- (_b = (_a = prev.getProps()).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
67
- }) })) })),
74
+ (_b = (_a = prev === null || prev === void 0 ? void 0 : prev()) === null || _a === void 0 ? void 0 : _a.onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
75
+ } })),
76
+ },
68
77
  hotkeys: {
69
78
  // setSelectedItem: {
70
79
  // hotkey: "space",
@@ -79,27 +88,37 @@ exports.selectionFeature = {
79
88
  },
80
89
  },
81
90
  selectUpwards: {
82
- hotkey: "shift+ArrowUp",
83
- handler: () => {
84
- // TODO
91
+ hotkey: "Shift+ArrowUp",
92
+ handler: (e, tree) => {
93
+ const focused = tree.getFocusedItem();
94
+ const above = focused.getItemAbove();
95
+ if (!above)
96
+ return;
97
+ if (focused.isSelected() && above.isSelected()) {
98
+ focused.deselect();
99
+ }
100
+ else {
101
+ above.select();
102
+ }
103
+ above.setFocused();
104
+ tree.updateDomFocus();
85
105
  },
86
106
  },
87
107
  selectDownwards: {
88
- hotkey: "shift+ArrowDown",
89
- handler: () => {
90
- // TODO
91
- },
92
- },
93
- selectUpwardsCtrl: {
94
- hotkey: "shift+ctrl+ArrowUp",
95
- handler: () => {
96
- // TODO
97
- },
98
- },
99
- selectDownwardsCtrl: {
100
- hotkey: "shift+ctrl+ArrowUp",
101
- handler: () => {
102
- // TODO
108
+ hotkey: "Shift+ArrowDown",
109
+ handler: (e, tree) => {
110
+ const focused = tree.getFocusedItem();
111
+ const below = focused.getItemBelow();
112
+ if (!below)
113
+ return;
114
+ if (focused.isSelected() && below.isSelected()) {
115
+ focused.deselect();
116
+ }
117
+ else {
118
+ below.select();
119
+ }
120
+ below.setFocused();
121
+ tree.updateDomFocus();
103
122
  },
104
123
  },
105
124
  selectAll: {
@@ -17,5 +17,5 @@ export type SelectionFeatureDef<T> = {
17
17
  isSelected: () => boolean;
18
18
  selectUpTo: (ctrl: boolean) => void;
19
19
  };
20
- hotkeys: "toggleSelectItem" | "selectUpwards" | "selectDownwards" | "selectUpwardsCtrl" | "selectDownwardsCtrl" | "selectAll";
20
+ hotkeys: "toggleSelectItem" | "selectUpwards" | "selectDownwards" | "selectAll";
21
21
  };
@@ -1,4 +1,2 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
- import { SyncDataLoaderFeatureDef } from "./types";
3
- import { MainFeatureDef } from "../main/types";
4
- export declare const syncDataLoaderFeature: FeatureImplementation<any, SyncDataLoaderFeatureDef<any>, MainFeatureDef | SyncDataLoaderFeatureDef<any>>;
2
+ export declare const syncDataLoaderFeature: FeatureImplementation;
@@ -9,6 +9,11 @@ exports.syncDataLoaderFeature = {
9
9
  stateHandlerNames: {
10
10
  loadingItems: "setLoadingItems",
11
11
  },
12
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: (itemId) => instance.getConfig().dataLoader.getItem(itemId), retrieveChildrenIds: (itemId) => instance.getConfig().dataLoader.getChildren(itemId) })),
13
- createItemInstance: (prev) => (Object.assign(Object.assign({}, prev), { isLoading: () => false })),
12
+ treeInstance: {
13
+ retrieveItemData: ({ tree }, itemId) => tree.getConfig().dataLoader.getItem(itemId),
14
+ retrieveChildrenIds: ({ tree }, itemId) => tree.getConfig().dataLoader.getChildren(itemId),
15
+ },
16
+ itemInstance: {
17
+ isLoading: () => false,
18
+ },
14
19
  };
@@ -1,6 +1,2 @@
1
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>>;
2
+ export declare const treeFeature: FeatureImplementation<any>;
@@ -19,14 +19,12 @@ exports.treeFeature = {
19
19
  expandedItems: "setExpandedItems",
20
20
  focusedItem: "setFocusedItem",
21
21
  },
22
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: () => {
23
- throw new Error("No data-loader registered");
24
- }, retrieveChildrenIds: () => {
25
- throw new Error("No data-loader registered");
26
- }, isItemExpanded: (itemId) => instance.getState().expandedItems.includes(itemId), getItemsMeta: () => {
27
- const { rootItemId } = instance.getConfig();
28
- const { expandedItems } = instance.getState();
22
+ treeInstance: {
23
+ getItemsMeta: ({ tree }) => {
24
+ const { rootItemId } = tree.getConfig();
25
+ const { expandedItems } = tree.getState();
29
26
  const flatItems = [];
27
+ const expandedItemsSet = new Set(expandedItems);
30
28
  const recursiveAdd = (itemId, parentId, level, setSize, posInSet) => {
31
29
  var _a;
32
30
  flatItems.push({
@@ -37,81 +35,68 @@ exports.treeFeature = {
37
35
  setSize,
38
36
  posInSet,
39
37
  });
40
- if (expandedItems.includes(itemId)) {
41
- const children = (_a = instance.retrieveChildrenIds(itemId)) !== null && _a !== void 0 ? _a : [];
38
+ if (expandedItemsSet.has(itemId)) {
39
+ // TODO THIS MADE A HUGE DIFFERENCE!
40
+ const children = (_a = tree.retrieveChildrenIds(itemId)) !== null && _a !== void 0 ? _a : [];
42
41
  let i = 0;
43
42
  for (const childId of children) {
44
43
  recursiveAdd(childId, itemId, level + 1, children.length, i++);
45
44
  }
46
45
  }
47
46
  };
48
- const children = instance.retrieveChildrenIds(rootItemId);
47
+ const children = tree.retrieveChildrenIds(rootItemId);
49
48
  let i = 0;
50
49
  for (const itemId of children) {
51
50
  recursiveAdd(itemId, rootItemId, 0, children.length, i++);
52
51
  }
53
52
  return flatItems;
54
- }, expandItem: (itemId) => {
55
- var _a;
56
- if (!instance.getItemInstance(itemId).isFolder()) {
57
- return;
58
- }
59
- if ((_a = instance.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
60
- return;
61
- }
62
- instance.applySubStateUpdate("expandedItems", (expandedItems) => [
63
- ...expandedItems,
64
- itemId,
65
- ]);
66
- instance.rebuildTree();
67
- }, collapseItem: (itemId) => {
68
- if (!instance.getItemInstance(itemId).isFolder()) {
69
- return;
70
- }
71
- instance.applySubStateUpdate("expandedItems", (expandedItems) => expandedItems.filter((id) => id !== itemId));
72
- instance.rebuildTree();
73
- },
53
+ },
74
54
  // TODO memo
75
- getFocusedItem: () => {
55
+ getFocusedItem: ({ tree }) => {
76
56
  var _a, _b;
77
- return ((_b = instance.getItemInstance((_a = instance.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : instance.getItems()[0]);
78
- }, focusItem: (itemId) => {
79
- instance.applySubStateUpdate("focusedItem", itemId);
80
- }, focusNextItem: () => {
81
- const { index } = instance.getFocusedItem().getItemMeta();
82
- const nextIndex = Math.min(index + 1, instance.getItems().length - 1);
83
- instance.focusItem(instance.getItems()[nextIndex].getId());
84
- }, focusPreviousItem: () => {
85
- const { index } = instance.getFocusedItem().getItemMeta();
57
+ return ((_b = tree.getItemInstance((_a = tree.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : tree.getItems()[0]);
58
+ },
59
+ focusNextItem: ({ tree }) => {
60
+ var _a;
61
+ const { index } = tree.getFocusedItem().getItemMeta();
62
+ const nextIndex = Math.min(index + 1, tree.getItems().length - 1);
63
+ (_a = tree.getItems()[nextIndex]) === null || _a === void 0 ? void 0 : _a.setFocused();
64
+ },
65
+ focusPreviousItem: ({ tree }) => {
66
+ var _a;
67
+ const { index } = tree.getFocusedItem().getItemMeta();
86
68
  const nextIndex = Math.max(index - 1, 0);
87
- instance.focusItem(instance.getItems()[nextIndex].getId());
88
- }, updateDomFocus: () => {
69
+ (_a = tree.getItems()[nextIndex]) === null || _a === void 0 ? void 0 : _a.setFocused();
70
+ },
71
+ updateDomFocus: ({ tree }) => {
89
72
  // Required because if the state is managed outside in react, the state only updated during next render
90
73
  setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
91
74
  var _a, _b;
92
- const focusedItem = instance.getFocusedItem();
93
- (_b = (_a = instance.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, focusedItem);
75
+ const focusedItem = tree.getFocusedItem();
76
+ (_b = (_a = tree.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, focusedItem);
94
77
  yield (0, utils_1.poll)(() => focusedItem.getElement() !== null, 20);
95
78
  const focusedElement = focusedItem.getElement();
96
79
  if (!focusedElement)
97
80
  return;
98
81
  focusedElement.focus();
99
82
  }));
100
- }, getContainerProps: () => {
101
- var _a;
102
- return (Object.assign(Object.assign({}, (_a = prev.getContainerProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "tree", ariaLabel: "", ariaActivedescendant: "" }));
103
- } })),
104
- createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { isLoading: () => {
105
- throw new Error("No data-loader registered");
106
- }, scrollTo: (scrollIntoViewArg) => __awaiter(void 0, void 0, void 0, function* () {
107
- var _a, _b;
108
- (_b = (_a = tree.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, item);
83
+ },
84
+ // TODO add label parameter
85
+ getContainerProps: ({ prev, tree }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { role: "tree", "aria-label": "", ref: tree.registerElement })),
86
+ // relevant for hotkeys of this feature
87
+ isSearchOpen: () => false,
88
+ },
89
+ itemInstance: {
90
+ scrollTo: (_a, scrollIntoViewArg_1) => __awaiter(void 0, [_a, scrollIntoViewArg_1], void 0, function* ({ tree, item }, scrollIntoViewArg) {
91
+ var _b, _c, _d;
92
+ (_c = (_b = tree.getConfig()).scrollToItem) === null || _c === void 0 ? void 0 : _c.call(_b, item);
109
93
  yield (0, utils_1.poll)(() => item.getElement() !== null, 20);
110
- item.getElement().scrollIntoView(scrollIntoViewArg);
111
- }), getId: () => item.getItemMeta().itemId, getProps: () => {
112
- var _a;
94
+ (_d = item.getElement()) === null || _d === void 0 ? void 0 : _d.scrollIntoView(scrollIntoViewArg);
95
+ }),
96
+ getId: ({ itemId }) => itemId,
97
+ getProps: ({ item, prev }) => {
113
98
  const itemMeta = item.getItemMeta();
114
- 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: item.getMemoizedProp("tree/onClick", () => (e) => {
99
+ return Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { ref: item.registerElement, role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": "false", "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: (e) => {
115
100
  item.setFocused();
116
101
  item.primaryAction();
117
102
  if (e.ctrlKey || e.shiftKey || e.metaKey) {
@@ -126,47 +111,65 @@ exports.treeFeature = {
126
111
  else {
127
112
  item.expand();
128
113
  }
129
- }) });
130
- }, 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 ||
131
- (tree.getState().focusedItem === null && item.getItemMeta().index === 0), isFolder: () => item.getItemMeta().level === -1 ||
132
- tree.getConfig().isItemFolder(item), getItemName: () => {
114
+ } });
115
+ },
116
+ expand: ({ tree, item, itemId }) => {
117
+ var _a;
118
+ if (!item.isFolder()) {
119
+ return;
120
+ }
121
+ if ((_a = tree.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
122
+ return;
123
+ }
124
+ tree.applySubStateUpdate("expandedItems", (expandedItems) => [
125
+ ...expandedItems,
126
+ itemId,
127
+ ]);
128
+ tree.rebuildTree();
129
+ },
130
+ collapse: ({ tree, item, itemId }) => {
131
+ if (!item.isFolder()) {
132
+ return;
133
+ }
134
+ tree.applySubStateUpdate("expandedItems", (expandedItems) => expandedItems.filter((id) => id !== itemId));
135
+ tree.rebuildTree();
136
+ },
137
+ getItemData: ({ tree, itemId }) => tree.retrieveItemData(itemId),
138
+ equals: ({ item }, other) => item.getId() === (other === null || other === void 0 ? void 0 : other.getId()),
139
+ isExpanded: ({ tree, itemId }) => tree.getState().expandedItems.includes(itemId),
140
+ isDescendentOf: ({ item }, parentId) => {
141
+ const parent = item.getParent();
142
+ return Boolean((parent === null || parent === void 0 ? void 0 : parent.getId()) === parentId || (parent === null || parent === void 0 ? void 0 : parent.isDescendentOf(parentId)));
143
+ },
144
+ isFocused: ({ tree, item, itemId }) => tree.getState().focusedItem === itemId ||
145
+ (tree.getState().focusedItem === null && item.getItemMeta().index === 0),
146
+ isFolder: ({ tree, item }) => item.getItemMeta().level === -1 ||
147
+ tree.getConfig().isItemFolder(item),
148
+ getItemName: ({ tree, item }) => {
133
149
  const config = tree.getConfig();
134
150
  return config.getItemName(item);
135
- }, 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) => {
136
- for (let i = itemMeta.index - 1; i >= 0; i--) {
137
- const potentialParent = tree.getItems()[i];
138
- if (potentialParent.getItemMeta().level < itemMeta.level) {
139
- return potentialParent;
140
- }
141
- }
142
- return tree.getItemInstance(tree.getConfig().rootItemId);
143
- }, () => [item.getItemMeta()]),
144
- // TODO remove
145
- getIndexInParent: () => item.getItemMeta().posInSet, getChildren: () => tree
151
+ },
152
+ setFocused: ({ tree, itemId }) => {
153
+ tree.applySubStateUpdate("focusedItem", itemId);
154
+ },
155
+ primaryAction: ({ tree, item }) => { var _a, _b; return (_b = (_a = tree.getConfig()).onPrimaryAction) === null || _b === void 0 ? void 0 : _b.call(_a, item); },
156
+ getParent: ({ tree, item }) => item.getItemMeta().parentId
157
+ ? tree.getItemInstance(item.getItemMeta().parentId)
158
+ : undefined,
159
+ getIndexInParent: ({ item }) => item.getItemMeta().posInSet,
160
+ getChildren: ({ tree, item }) => tree
146
161
  .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], getMemoizedProp: (name, create, deps) => {
148
- var _a, _b, _c, _d, _e;
149
- var _f, _g;
150
- const data = item.getDataRef();
151
- const memoizedValue = (_a = data.current.memoizedValues) === null || _a === void 0 ? void 0 : _a[name];
152
- if (memoizedValue &&
153
- (!deps ||
154
- ((_c = (_b = data.current.memoizedDeps) === null || _b === void 0 ? void 0 : _b[name]) === null || _c === void 0 ? void 0 : _c.every((d, i) => d === deps[i])))) {
155
- return memoizedValue;
156
- }
157
- (_d = (_f = data.current).memoizedDeps) !== null && _d !== void 0 ? _d : (_f.memoizedDeps = {});
158
- (_e = (_g = data.current).memoizedValues) !== null && _e !== void 0 ? _e : (_g.memoizedValues = {});
159
- const value = create();
160
- data.current.memoizedDeps[name] = deps;
161
- data.current.memoizedValues[name] = value;
162
- return value;
163
- } })),
162
+ .map((id) => tree.getItemInstance(id)),
163
+ getTree: ({ tree }) => tree,
164
+ getItemAbove: ({ tree, item }) => tree.getItems()[item.getItemMeta().index - 1],
165
+ getItemBelow: ({ tree, item }) => tree.getItems()[item.getItemMeta().index + 1],
166
+ },
164
167
  hotkeys: {
165
168
  focusNextItem: {
166
169
  hotkey: "ArrowDown",
167
170
  canRepeat: true,
168
171
  preventDefault: true,
169
- 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; },
172
+ 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; }, // TODO what happens when the feature doesnt exist? proxy method still claims to exist
170
173
  handler: (e, tree) => {
171
174
  tree.focusNextItem();
172
175
  tree.updateDomFocus();
@@ -215,14 +218,16 @@ exports.treeFeature = {
215
218
  focusFirstItem: {
216
219
  hotkey: "Home",
217
220
  handler: (e, tree) => {
218
- tree.focusItem(tree.getItems()[0].getId());
221
+ var _a;
222
+ (_a = tree.getItems()[0]) === null || _a === void 0 ? void 0 : _a.setFocused();
219
223
  tree.updateDomFocus();
220
224
  },
221
225
  },
222
226
  focusLastItem: {
223
227
  hotkey: "End",
224
228
  handler: (e, tree) => {
225
- tree.focusItem(tree.getItems()[tree.getItems().length - 1].getId());
229
+ var _a;
230
+ (_a = tree.getItems()[tree.getItems().length - 1]) === null || _a === void 0 ? void 0 : _a.setFocused();
226
231
  tree.updateDomFocus();
227
232
  },
228
233
  },
@@ -27,10 +27,6 @@ export type TreeFeatureDef<T> = {
27
27
  treeInstance: {
28
28
  /** @internal */
29
29
  getItemsMeta: () => ItemMeta[];
30
- expandItem: (itemId: string) => void;
31
- collapseItem: (itemId: string) => void;
32
- isItemExpanded: (itemId: string) => boolean;
33
- focusItem: (itemId: string) => void;
34
30
  getFocusedItem: () => ItemInstance<any>;
35
31
  focusNextItem: () => void;
36
32
  focusPreviousItem: () => void;
@@ -42,20 +38,21 @@ export type TreeFeatureDef<T> = {
42
38
  getProps: () => Record<string, any>;
43
39
  getItemName: () => string;
44
40
  getItemData: () => T;
41
+ equals: (other?: ItemInstance<any> | null) => boolean;
45
42
  expand: () => void;
46
43
  collapse: () => void;
47
44
  isExpanded: () => boolean;
45
+ isDescendentOf: (parentId: string) => boolean;
48
46
  isFocused: () => boolean;
49
47
  isFolder: () => boolean;
50
48
  setFocused: () => void;
51
- getParent: () => ItemInstance<T>;
49
+ getParent: () => ItemInstance<T> | undefined;
52
50
  getChildren: () => ItemInstance<T>[];
53
51
  getIndexInParent: () => number;
54
52
  primaryAction: () => void;
55
53
  getTree: () => TreeInstance<T>;
56
- getItemAbove: () => ItemInstance<T> | null;
57
- getItemBelow: () => ItemInstance<T> | null;
58
- getMemoizedProp: <X>(name: string, create: () => X, deps?: any[]) => X;
54
+ getItemAbove: () => ItemInstance<T> | undefined;
55
+ getItemBelow: () => ItemInstance<T> | undefined;
59
56
  scrollTo: (scrollIntoViewArg?: boolean | ScrollIntoViewOptions) => Promise<void>;
60
57
  };
61
58
  hotkeys: "focusNextItem" | "focusPreviousItem" | "expandOrDown" | "collapseOrUp" | "focusFirstItem" | "focusLastItem";
@@ -1,7 +1,7 @@
1
1
  export * from "./types/core";
2
2
  export * from "./core/create-tree";
3
3
  export * from "./features/tree/types";
4
- export * from "./features/main/types";
4
+ export { MainFeatureDef, InstanceBuilder } from "./features/main/types";
5
5
  export * from "./features/drag-and-drop/types";
6
6
  export * from "./features/selection/types";
7
7
  export * from "./features/async-data-loader/types";
@@ -10,6 +10,7 @@ export * from "./features/hotkeys-core/types";
10
10
  export * from "./features/search/types";
11
11
  export * from "./features/renaming/types";
12
12
  export * from "./features/expand-all/types";
13
+ export * from "./features/prop-memoization/types";
13
14
  export * from "./features/selection/feature";
14
15
  export * from "./features/hotkeys-core/feature";
15
16
  export * from "./features/async-data-loader/feature";
@@ -18,6 +19,9 @@ export * from "./features/drag-and-drop/feature";
18
19
  export * from "./features/search/feature";
19
20
  export * from "./features/renaming/feature";
20
21
  export * from "./features/expand-all/feature";
22
+ export * from "./features/prop-memoization/feature";
21
23
  export * from "./utilities/create-on-drop-handler";
22
24
  export * from "./utilities/insert-items-at-target";
23
25
  export * from "./utilities/remove-items-from-parents";
26
+ export * from "./core/build-proxified-instance";
27
+ export * from "./core/build-static-instance";
package/lib/cjs/index.js CHANGED
@@ -17,7 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./types/core"), exports);
18
18
  __exportStar(require("./core/create-tree"), exports);
19
19
  __exportStar(require("./features/tree/types"), exports);
20
- __exportStar(require("./features/main/types"), exports);
21
20
  __exportStar(require("./features/drag-and-drop/types"), exports);
22
21
  __exportStar(require("./features/selection/types"), exports);
23
22
  __exportStar(require("./features/async-data-loader/types"), exports);
@@ -26,6 +25,7 @@ __exportStar(require("./features/hotkeys-core/types"), exports);
26
25
  __exportStar(require("./features/search/types"), exports);
27
26
  __exportStar(require("./features/renaming/types"), exports);
28
27
  __exportStar(require("./features/expand-all/types"), exports);
28
+ __exportStar(require("./features/prop-memoization/types"), exports);
29
29
  __exportStar(require("./features/selection/feature"), exports);
30
30
  __exportStar(require("./features/hotkeys-core/feature"), exports);
31
31
  __exportStar(require("./features/async-data-loader/feature"), exports);
@@ -34,6 +34,9 @@ __exportStar(require("./features/drag-and-drop/feature"), exports);
34
34
  __exportStar(require("./features/search/feature"), exports);
35
35
  __exportStar(require("./features/renaming/feature"), exports);
36
36
  __exportStar(require("./features/expand-all/feature"), exports);
37
+ __exportStar(require("./features/prop-memoization/feature"), exports);
37
38
  __exportStar(require("./utilities/create-on-drop-handler"), exports);
38
39
  __exportStar(require("./utilities/insert-items-at-target"), exports);
39
40
  __exportStar(require("./utilities/remove-items-from-parents"), exports);
41
+ __exportStar(require("./core/build-proxified-instance"), exports);
42
+ __exportStar(require("./core/build-static-instance"), exports);
@@ -8,6 +8,7 @@ import { SearchFeatureDef } from "./features/search/types";
8
8
  import { SelectionFeatureDef } from "./features/selection/types";
9
9
  import { SyncDataLoaderFeatureDef } from "./features/sync-data-loader/types";
10
10
  import { TreeFeatureDef } from "./features/tree/types";
11
+ import { PropMemoizationFeatureDef } from "./features/prop-memoization/types";
11
12
  export * from ".";
12
13
  /** @interface */
13
14
  export type AsyncDataLoaderFeatureConfig<T> = AsyncDataLoaderFeatureDef<T>["config"];
@@ -55,6 +56,15 @@ export type MainFeatureTreeInstance = MainFeatureDef["treeInstance"];
55
56
  export type MainFeatureItemInstance = MainFeatureDef["itemInstance"];
56
57
  export type MainFeatureHotkeys = MainFeatureDef["hotkeys"];
57
58
  /** @interface */
59
+ export type PropMemoizationConfig = PropMemoizationFeatureDef["config"];
60
+ /** @interface */
61
+ export type PropMemoizationState = PropMemoizationFeatureDef["state"];
62
+ /** @interface */
63
+ export type PropMemoizationTreeInstance = PropMemoizationFeatureDef["treeInstance"];
64
+ /** @interface */
65
+ export type PropMemoizationItemInstance = PropMemoizationFeatureDef["itemInstance"];
66
+ export type PropMemoizationHotkeys = PropMemoizationFeatureDef["hotkeys"];
67
+ /** @interface */
58
68
  export type RenamingFeatureConfig<T> = RenamingFeatureDef<T>["config"];
59
69
  /** @interface */
60
70
  export type RenamingFeatureState<T> = RenamingFeatureDef<T>["state"];
@@ -0,0 +1,23 @@
1
+ import { DragEvent } from "react";
2
+ import { TestTree } from "./test-tree";
3
+ import { HotkeyName } from "../types/core";
4
+ export declare class TestTreeDo<T> {
5
+ protected tree: TestTree<T>;
6
+ protected itemInstance(itemId: string): import("../types/core").ItemInstance<T>;
7
+ protected itemProps(itemId: string): Record<string, any>;
8
+ constructor(tree: TestTree<T>);
9
+ selectItem(id: string): void;
10
+ shiftSelectItem(id: string): void;
11
+ ctrlSelectItem(id: string): void;
12
+ ctrlShiftSelectItem(id: string): void;
13
+ selectMultiple(...ids: string[]): void;
14
+ hotkey(hotkey: HotkeyName, e?: Partial<KeyboardEvent>): void;
15
+ startDrag(itemId: string, event?: DragEvent): DragEvent<Element>;
16
+ dragOver(itemId: string, event?: DragEvent): DragEvent<Element>;
17
+ dragOverNotAllowed(itemId: string, event?: DragEvent): DragEvent<Element>;
18
+ dragLeave(itemId: string): void;
19
+ dragEnd(itemId: string, event?: DragEvent): DragEvent<Element>;
20
+ drop(itemId: string, event?: DragEvent): DragEvent<Element>;
21
+ dragOverAndDrop(itemId: string, event?: DragEvent): DragEvent<Element>;
22
+ private consistentCalls;
23
+ }