@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,18 +1,8 @@
1
1
  import { FeatureImplementation, ItemInstance } from "../../types/core";
2
- import { ItemMeta, TreeFeatureDef, TreeItemDataRef } from "./types";
3
- import { makeStateUpdater, memo, poll } from "../../utils";
4
- import { MainFeatureDef } from "../main/types";
5
- import { HotkeysCoreFeatureDef } from "../hotkeys-core/types";
6
- import { SyncDataLoaderFeatureDef } from "../sync-data-loader/types";
2
+ import { ItemMeta } from "./types";
3
+ import { makeStateUpdater, poll } from "../../utils";
7
4
 
8
- export const treeFeature: FeatureImplementation<
9
- any,
10
- TreeFeatureDef<any>,
11
- | MainFeatureDef
12
- | TreeFeatureDef<any>
13
- | HotkeysCoreFeatureDef<any>
14
- | SyncDataLoaderFeatureDef<any>
15
- > = {
5
+ export const treeFeature: FeatureImplementation<any> = {
16
6
  key: "tree",
17
7
 
18
8
  getInitialState: (initialState) => ({
@@ -32,24 +22,12 @@ export const treeFeature: FeatureImplementation<
32
22
  focusedItem: "setFocusedItem",
33
23
  },
34
24
 
35
- createTreeInstance: (prev, instance) => ({
36
- ...prev,
37
-
38
- retrieveItemData: () => {
39
- throw new Error("No data-loader registered");
40
- },
41
-
42
- retrieveChildrenIds: () => {
43
- throw new Error("No data-loader registered");
44
- },
45
-
46
- isItemExpanded: (itemId) =>
47
- instance.getState().expandedItems.includes(itemId),
48
-
49
- getItemsMeta: () => {
50
- const { rootItemId } = instance.getConfig();
51
- const { expandedItems } = instance.getState();
25
+ treeInstance: {
26
+ getItemsMeta: ({ tree }) => {
27
+ const { rootItemId } = tree.getConfig();
28
+ const { expandedItems } = tree.getState();
52
29
  const flatItems: ItemMeta[] = [];
30
+ const expandedItemsSet = new Set(expandedItems);
53
31
 
54
32
  const recursiveAdd = (
55
33
  itemId: string,
@@ -67,8 +45,9 @@ export const treeFeature: FeatureImplementation<
67
45
  posInSet,
68
46
  });
69
47
 
70
- if (expandedItems.includes(itemId)) {
71
- const children = instance.retrieveChildrenIds(itemId) ?? [];
48
+ if (expandedItemsSet.has(itemId)) {
49
+ // TODO THIS MADE A HUGE DIFFERENCE!
50
+ const children = tree.retrieveChildrenIds(itemId) ?? [];
72
51
  let i = 0;
73
52
  for (const childId of children) {
74
53
  recursiveAdd(childId, itemId, level + 1, children.length, i++);
@@ -76,7 +55,7 @@ export const treeFeature: FeatureImplementation<
76
55
  }
77
56
  };
78
57
 
79
- const children = instance.retrieveChildrenIds(rootItemId);
58
+ const children = tree.retrieveChildrenIds(rootItemId);
80
59
  let i = 0;
81
60
  for (const itemId of children) {
82
61
  recursiveAdd(itemId, rootItemId, 0, children.length, i++);
@@ -85,62 +64,31 @@ export const treeFeature: FeatureImplementation<
85
64
  return flatItems;
86
65
  },
87
66
 
88
- expandItem: (itemId) => {
89
- if (!instance.getItemInstance(itemId).isFolder()) {
90
- return;
91
- }
92
-
93
- if (instance.getState().loadingItems?.includes(itemId)) {
94
- return;
95
- }
96
-
97
- instance.applySubStateUpdate("expandedItems", (expandedItems) => [
98
- ...expandedItems,
99
- itemId,
100
- ]);
101
- instance.rebuildTree();
102
- },
103
-
104
- collapseItem: (itemId) => {
105
- if (!instance.getItemInstance(itemId).isFolder()) {
106
- return;
107
- }
108
-
109
- instance.applySubStateUpdate("expandedItems", (expandedItems) =>
110
- expandedItems.filter((id) => id !== itemId),
111
- );
112
- instance.rebuildTree();
113
- },
114
-
115
67
  // TODO memo
116
- getFocusedItem: () => {
68
+ getFocusedItem: ({ tree }) => {
117
69
  return (
118
- instance.getItemInstance(instance.getState().focusedItem ?? "") ??
119
- instance.getItems()[0]
70
+ tree.getItemInstance(tree.getState().focusedItem ?? "") ??
71
+ tree.getItems()[0]
120
72
  );
121
73
  },
122
74
 
123
- focusItem: (itemId) => {
124
- instance.applySubStateUpdate("focusedItem", itemId);
125
- },
126
-
127
- focusNextItem: () => {
128
- const { index } = instance.getFocusedItem().getItemMeta();
129
- const nextIndex = Math.min(index + 1, instance.getItems().length - 1);
130
- instance.focusItem(instance.getItems()[nextIndex].getId());
75
+ focusNextItem: ({ tree }) => {
76
+ const { index } = tree.getFocusedItem().getItemMeta();
77
+ const nextIndex = Math.min(index + 1, tree.getItems().length - 1);
78
+ tree.getItems()[nextIndex]?.setFocused();
131
79
  },
132
80
 
133
- focusPreviousItem: () => {
134
- const { index } = instance.getFocusedItem().getItemMeta();
81
+ focusPreviousItem: ({ tree }) => {
82
+ const { index } = tree.getFocusedItem().getItemMeta();
135
83
  const nextIndex = Math.max(index - 1, 0);
136
- instance.focusItem(instance.getItems()[nextIndex].getId());
84
+ tree.getItems()[nextIndex]?.setFocused();
137
85
  },
138
86
 
139
- updateDomFocus: () => {
87
+ updateDomFocus: ({ tree }) => {
140
88
  // Required because if the state is managed outside in react, the state only updated during next render
141
89
  setTimeout(async () => {
142
- const focusedItem = instance.getFocusedItem();
143
- instance.getConfig().scrollToItem?.(focusedItem);
90
+ const focusedItem = tree.getFocusedItem();
91
+ tree.getConfig().scrollToItem?.(focusedItem);
144
92
  await poll(() => focusedItem.getElement() !== null, 20);
145
93
  const focusedElement = focusedItem.getElement();
146
94
  if (!focusedElement) return;
@@ -148,29 +96,30 @@ export const treeFeature: FeatureImplementation<
148
96
  });
149
97
  },
150
98
 
151
- getContainerProps: () => ({
152
- ...prev.getContainerProps?.(),
99
+ // TODO add label parameter
100
+ getContainerProps: ({ prev, tree }) => ({
101
+ ...prev?.(),
153
102
  role: "tree",
154
- ariaLabel: "",
155
- ariaActivedescendant: "",
103
+ "aria-label": "",
104
+ ref: tree.registerElement, // TODO memo
156
105
  }),
157
- }),
158
106
 
159
- createItemInstance: (prev, item, tree) => ({
160
- ...prev,
161
- isLoading: () => {
162
- throw new Error("No data-loader registered");
163
- },
164
- scrollTo: async (scrollIntoViewArg) => {
107
+ // relevant for hotkeys of this feature
108
+ isSearchOpen: () => false,
109
+ },
110
+
111
+ itemInstance: {
112
+ scrollTo: async ({ tree, item }, scrollIntoViewArg) => {
165
113
  tree.getConfig().scrollToItem?.(item as any);
166
114
  await poll(() => item.getElement() !== null, 20);
167
- item.getElement()!.scrollIntoView(scrollIntoViewArg);
115
+ item.getElement()?.scrollIntoView(scrollIntoViewArg);
168
116
  },
169
- getId: () => item.getItemMeta().itemId,
170
- getProps: () => {
117
+ getId: ({ itemId }) => itemId,
118
+ getProps: ({ item, prev }) => {
171
119
  const itemMeta = item.getItemMeta();
172
120
  return {
173
- ...prev.getProps?.(),
121
+ ...prev?.(),
122
+ ref: item.registerElement, // TODO memo
174
123
  role: "treeitem",
175
124
  "aria-setsize": itemMeta.setSize,
176
125
  "aria-posinset": itemMeta.posInSet,
@@ -178,7 +127,7 @@ export const treeFeature: FeatureImplementation<
178
127
  "aria-label": item.getItemName(),
179
128
  "aria-level": itemMeta.level,
180
129
  tabIndex: item.isFocused() ? 0 : -1,
181
- onClick: item.getMemoizedProp("tree/onClick", () => (e) => {
130
+ onClick: (e: MouseEvent) => {
182
131
  item.setFocused();
183
132
  item.primaryAction();
184
133
 
@@ -195,66 +144,74 @@ export const treeFeature: FeatureImplementation<
195
144
  } else {
196
145
  item.expand();
197
146
  }
198
- }),
147
+ },
199
148
  };
200
149
  },
201
- expand: () => tree.expandItem(item.getItemMeta().itemId),
202
- collapse: () => tree.collapseItem(item.getItemMeta().itemId),
203
- getItemData: () => tree.retrieveItemData(item.getItemMeta().itemId),
204
- isExpanded: () =>
205
- tree.getState().expandedItems.includes(item.getItemMeta().itemId),
206
- isFocused: () =>
207
- tree.getState().focusedItem === item.getItemMeta().itemId ||
150
+ expand: ({ tree, item, itemId }) => {
151
+ if (!item.isFolder()) {
152
+ return;
153
+ }
154
+
155
+ if (tree.getState().loadingItems?.includes(itemId)) {
156
+ return;
157
+ }
158
+
159
+ tree.applySubStateUpdate("expandedItems", (expandedItems) => [
160
+ ...expandedItems,
161
+ itemId,
162
+ ]);
163
+ tree.rebuildTree();
164
+ },
165
+ collapse: ({ tree, item, itemId }) => {
166
+ if (!item.isFolder()) {
167
+ return;
168
+ }
169
+
170
+ tree.applySubStateUpdate("expandedItems", (expandedItems) =>
171
+ expandedItems.filter((id) => id !== itemId),
172
+ );
173
+ tree.rebuildTree();
174
+ },
175
+ getItemData: ({ tree, itemId }) => tree.retrieveItemData(itemId),
176
+ equals: ({ item }, other) => item.getId() === other?.getId(),
177
+ isExpanded: ({ tree, itemId }) =>
178
+ tree.getState().expandedItems.includes(itemId),
179
+ isDescendentOf: ({ item }, parentId) => {
180
+ const parent = item.getParent();
181
+ return Boolean(
182
+ parent?.getId() === parentId || parent?.isDescendentOf(parentId),
183
+ );
184
+ },
185
+ isFocused: ({ tree, item, itemId }) =>
186
+ tree.getState().focusedItem === itemId ||
208
187
  (tree.getState().focusedItem === null && item.getItemMeta().index === 0),
209
- isFolder: () =>
188
+ isFolder: ({ tree, item }) =>
210
189
  item.getItemMeta().level === -1 ||
211
190
  tree.getConfig().isItemFolder(item as ItemInstance<any>),
212
- getItemName: () => {
191
+ getItemName: ({ tree, item }) => {
213
192
  const config = tree.getConfig();
214
193
  return config.getItemName(item as ItemInstance<any>);
215
194
  },
216
- setFocused: () => tree.focusItem(item.getItemMeta().itemId),
217
- primaryAction: () =>
195
+ setFocused: ({ tree, itemId }) => {
196
+ tree.applySubStateUpdate("focusedItem", itemId);
197
+ },
198
+ primaryAction: ({ tree, item }) =>
218
199
  tree.getConfig().onPrimaryAction?.(item as ItemInstance<any>),
219
- getParent: memo(
220
- (itemMeta) => {
221
- for (let i = itemMeta.index - 1; i >= 0; i--) {
222
- const potentialParent = tree.getItems()[i];
223
- if (potentialParent.getItemMeta().level < itemMeta.level) {
224
- return potentialParent;
225
- }
226
- }
227
- return tree.getItemInstance(tree.getConfig().rootItemId);
228
- },
229
- () => [item.getItemMeta()],
230
- ),
231
- // TODO remove
232
- getIndexInParent: () => item.getItemMeta().posInSet,
233
- getChildren: () =>
200
+ getParent: ({ tree, item }) =>
201
+ item.getItemMeta().parentId
202
+ ? tree.getItemInstance(item.getItemMeta().parentId)
203
+ : undefined,
204
+ getIndexInParent: ({ item }) => item.getItemMeta().posInSet,
205
+ getChildren: ({ tree, item }) =>
234
206
  tree
235
207
  .retrieveChildrenIds(item.getItemMeta().itemId)
236
208
  .map((id) => tree.getItemInstance(id)),
237
- getTree: () => tree as any,
238
- getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1],
239
- getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1],
240
- getMemoizedProp: (name, create, deps) => {
241
- const data = item.getDataRef<TreeItemDataRef>();
242
- const memoizedValue = data.current.memoizedValues?.[name];
243
- if (
244
- memoizedValue &&
245
- (!deps ||
246
- data.current.memoizedDeps?.[name]?.every((d, i) => d === deps![i]))
247
- ) {
248
- return memoizedValue;
249
- }
250
- data.current.memoizedDeps ??= {};
251
- data.current.memoizedValues ??= {};
252
- const value = create();
253
- data.current.memoizedDeps[name] = deps;
254
- data.current.memoizedValues[name] = value;
255
- return value;
256
- },
257
- }),
209
+ getTree: ({ tree }) => tree as any,
210
+ getItemAbove: ({ tree, item }) =>
211
+ tree.getItems()[item.getItemMeta().index - 1],
212
+ getItemBelow: ({ tree, item }) =>
213
+ tree.getItems()[item.getItemMeta().index + 1],
214
+ },
258
215
 
259
216
  hotkeys: {
260
217
  focusNextItem: {
@@ -262,7 +219,7 @@ export const treeFeature: FeatureImplementation<
262
219
  canRepeat: true,
263
220
  preventDefault: true,
264
221
  isEnabled: (tree) =>
265
- !(tree.isSearchOpen?.() ?? false) && !tree.getState().dnd,
222
+ !(tree.isSearchOpen?.() ?? false) && !tree.getState().dnd, // TODO what happens when the feature doesnt exist? proxy method still claims to exist
266
223
  handler: (e, tree) => {
267
224
  tree.focusNextItem();
268
225
  tree.updateDomFocus();
@@ -311,14 +268,14 @@ export const treeFeature: FeatureImplementation<
311
268
  focusFirstItem: {
312
269
  hotkey: "Home",
313
270
  handler: (e, tree) => {
314
- tree.focusItem(tree.getItems()[0].getId());
271
+ tree.getItems()[0]?.setFocused();
315
272
  tree.updateDomFocus();
316
273
  },
317
274
  },
318
275
  focusLastItem: {
319
276
  hotkey: "End",
320
277
  handler: (e, tree) => {
321
- tree.focusItem(tree.getItems()[tree.getItems().length - 1].getId());
278
+ tree.getItems()[tree.getItems().length - 1]?.setFocused();
322
279
  tree.updateDomFocus();
323
280
  },
324
281
  },