tree-element 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +14 -6
  2. package/lib/animation.d.ts +2 -2
  3. package/lib/animation.d.ts.map +1 -1
  4. package/lib/animation.js +13 -9
  5. package/lib/animation.js.map +1 -1
  6. package/lib/dataLoader.d.ts +1 -0
  7. package/lib/dataLoader.d.ts.map +1 -1
  8. package/lib/dataLoader.js +8 -0
  9. package/lib/dataLoader.js.map +1 -1
  10. package/lib/dragAndDropHandler/dragElement.d.ts.map +1 -1
  11. package/lib/dragAndDropHandler/dragElement.js +2 -1
  12. package/lib/dragAndDropHandler/dragElement.js.map +1 -1
  13. package/lib/dragAndDropHandler/index.d.ts.map +1 -1
  14. package/lib/dragAndDropHandler/index.js +56 -65
  15. package/lib/dragAndDropHandler/index.js.map +1 -1
  16. package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts.map +1 -1
  17. package/lib/dragAndDropHandler/iterateVisibleNodes.js +16 -15
  18. package/lib/dragAndDropHandler/iterateVisibleNodes.js.map +1 -1
  19. package/lib/elementsRenderer.d.ts +5 -1
  20. package/lib/elementsRenderer.d.ts.map +1 -1
  21. package/lib/elementsRenderer.js +62 -39
  22. package/lib/elementsRenderer.js.map +1 -1
  23. package/lib/events.d.ts +44 -11
  24. package/lib/events.d.ts.map +1 -1
  25. package/lib/index.d.ts +31 -8
  26. package/lib/index.d.ts.map +1 -1
  27. package/lib/index.js +162 -122
  28. package/lib/index.js.map +1 -1
  29. package/lib/keyHandler.d.ts +11 -5
  30. package/lib/keyHandler.d.ts.map +1 -1
  31. package/lib/keyHandler.js +87 -33
  32. package/lib/keyHandler.js.map +1 -1
  33. package/lib/methodTypes.d.ts +2 -2
  34. package/lib/methodTypes.d.ts.map +1 -1
  35. package/lib/mouseHandler.d.ts +1 -1
  36. package/lib/mouseHandler.d.ts.map +1 -1
  37. package/lib/mouseHandler.js +10 -7
  38. package/lib/mouseHandler.js.map +1 -1
  39. package/lib/node.d.ts +45 -15
  40. package/lib/node.d.ts.map +1 -1
  41. package/lib/node.js +136 -139
  42. package/lib/node.js.map +1 -1
  43. package/lib/nodeElement/folderElement.d.ts +1 -1
  44. package/lib/nodeElement/folderElement.d.ts.map +1 -1
  45. package/lib/nodeElement/folderElement.js +46 -57
  46. package/lib/nodeElement/folderElement.js.map +1 -1
  47. package/lib/nodeElement/ghostDropHint.d.ts.map +1 -1
  48. package/lib/nodeElement/ghostDropHint.js +8 -4
  49. package/lib/nodeElement/ghostDropHint.js.map +1 -1
  50. package/lib/nodeElement/index.d.ts.map +1 -1
  51. package/lib/nodeElement/index.js +6 -6
  52. package/lib/nodeElement/index.js.map +1 -1
  53. package/lib/nodeUtils.d.ts.map +1 -1
  54. package/lib/nodeUtils.js +1 -1
  55. package/lib/nodeUtils.js.map +1 -1
  56. package/lib/options.d.ts +23 -6
  57. package/lib/options.d.ts.map +1 -1
  58. package/lib/requestUrl.d.ts +0 -1
  59. package/lib/requestUrl.d.ts.map +1 -1
  60. package/lib/requestUrl.js +4 -22
  61. package/lib/requestUrl.js.map +1 -1
  62. package/lib/saveStateHandler.d.ts.map +1 -1
  63. package/lib/saveStateHandler.js +21 -41
  64. package/lib/saveStateHandler.js.map +1 -1
  65. package/lib/scrollHandler/containerScrollParent.d.ts.map +1 -1
  66. package/lib/scrollHandler/containerScrollParent.js +3 -8
  67. package/lib/scrollHandler/containerScrollParent.js.map +1 -1
  68. package/lib/scrollHandler/createScrollParent.d.ts.map +1 -1
  69. package/lib/scrollHandler/createScrollParent.js +4 -5
  70. package/lib/scrollHandler/createScrollParent.js.map +1 -1
  71. package/lib/scrollHandler/documentScrollParent.d.ts.map +1 -1
  72. package/lib/scrollHandler/documentScrollParent.js +3 -9
  73. package/lib/scrollHandler/documentScrollParent.js.map +1 -1
  74. package/lib/scrollHandler/scrollParent.d.ts.map +1 -1
  75. package/lib/scrollHandler/scrollParent.js +19 -17
  76. package/lib/scrollHandler/scrollParent.js.map +1 -1
  77. package/lib/selectNodeHandler.d.ts +3 -1
  78. package/lib/selectNodeHandler.d.ts.map +1 -1
  79. package/lib/selectNodeHandler.js +27 -37
  80. package/lib/selectNodeHandler.js.map +1 -1
  81. package/lib/setDefaultOptions.d.ts +3 -0
  82. package/lib/setDefaultOptions.d.ts.map +1 -1
  83. package/lib/setDefaultOptions.js +21 -20
  84. package/lib/setDefaultOptions.js.map +1 -1
  85. package/lib/util.d.ts.map +1 -1
  86. package/lib/util.js +1 -1
  87. package/lib/util.js.map +1 -1
  88. package/lib/version.d.ts +1 -1
  89. package/lib/version.js +1 -1
  90. package/lib/version.js.map +1 -1
  91. package/package.json +44 -35
  92. package/src/animation.ts +13 -11
  93. package/src/dataLoader.ts +11 -0
  94. package/src/dragAndDropHandler/dragElement.ts +2 -1
  95. package/src/dragAndDropHandler/index.ts +70 -75
  96. package/src/dragAndDropHandler/iterateVisibleNodes.ts +18 -16
  97. package/src/elementsRenderer.ts +76 -46
  98. package/src/events.ts +44 -11
  99. package/src/index.ts +210 -150
  100. package/src/keyHandler.ts +95 -41
  101. package/src/methodTypes.ts +3 -3
  102. package/src/mouseHandler.ts +10 -7
  103. package/src/node.ts +155 -148
  104. package/src/nodeElement/folderElement.ts +54 -63
  105. package/src/nodeElement/ghostDropHint.ts +4 -2
  106. package/src/nodeElement/index.ts +9 -15
  107. package/src/nodeUtils.ts +1 -1
  108. package/src/options.ts +23 -6
  109. package/src/requestUrl.ts +4 -25
  110. package/src/saveStateHandler.ts +29 -43
  111. package/src/scrollHandler/containerScrollParent.ts +3 -9
  112. package/src/scrollHandler/createScrollParent.ts +1 -2
  113. package/src/scrollHandler/documentScrollParent.ts +5 -11
  114. package/src/scrollHandler/scrollParent.ts +29 -25
  115. package/src/selectNodeHandler.ts +34 -38
  116. package/src/setDefaultOptions.ts +31 -19
  117. package/src/util.ts +1 -2
  118. package/src/version.ts +1 -1
  119. package/tree_element.css +87 -69
  120. package/tree_element.debug.js +717 -659
  121. package/tree_element.debug.js.map +1 -1
  122. package/tree_element.js +2 -2
  123. package/tree_element.js.map +1 -1
@@ -20,13 +20,15 @@ class GhostDropHint implements DropHint {
20
20
  this.ghost = this.createGhostElement();
21
21
 
22
22
  switch (position) {
23
- case "after":
23
+ case "after": {
24
24
  this.moveAfter();
25
25
  break;
26
+ }
26
27
 
27
- case "before":
28
+ case "before": {
28
29
  this.moveBefore();
29
30
  break;
31
+ }
30
32
 
31
33
  case "inside": {
32
34
  if (node.isFolder() && node.is_open) {
@@ -40,20 +40,9 @@ class NodeElement {
40
40
  }
41
41
 
42
42
  public addDropHint(position: Position): DropHint {
43
- if (this.mustShowBorderDropHint(position)) {
44
- return new BorderDropHint(
45
- this.element,
46
- this.getScrollLeft(),
47
- this.classNames,
48
- );
49
- } else {
50
- return new GhostDropHint(
51
- this.node,
52
- this.element,
53
- position,
54
- this.classNames,
55
- );
56
- }
43
+ return this.mustShowBorderDropHint(position)
44
+ ? new BorderDropHint(this.element, this.getScrollLeft(), this.classNames)
45
+ : new GhostDropHint(this.node, this.element, position, this.classNames);
57
46
  }
58
47
 
59
48
  public deselect(): void {
@@ -64,7 +53,12 @@ class NodeElement {
64
53
  this.element.classList.remove(this.classNames.selected);
65
54
 
66
55
  const titleSpan = this.getTitleSpan();
67
- titleSpan.removeAttribute("tabindex");
56
+
57
+ // Check for null or undefined
58
+ if (this.tabIndex != null) {
59
+ titleSpan.setAttribute("tabindex", "-1");
60
+ }
61
+
68
62
  titleSpan.setAttribute("aria-selected", "false");
69
63
 
70
64
  titleSpan.blur();
package/src/nodeUtils.ts CHANGED
@@ -9,4 +9,4 @@ export const isNodeRecordWithChildren = (
9
9
  ): data is NodeRecordWithChildren =>
10
10
  typeof data === "object" &&
11
11
  "children" in data &&
12
- data.children instanceof Array;
12
+ Array.isArray(data.children);
package/src/options.ts CHANGED
@@ -36,10 +36,25 @@ export interface TreeElementOptions {
36
36
  * The duration of the slide animation: `"fast"` is 200ms, `"slow"` is
37
37
  * 600ms, a number is milliseconds.
38
38
  *
39
- * @defaultValue `"fast"`
39
+ * @defaultValue `"fast"`, or `0` when the user prefers reduced motion
40
+ * (`prefers-reduced-motion: reduce`).
40
41
  * @group Appearance
41
42
  */
42
43
  animationSpeed: AnimationSpeed;
44
+ /**
45
+ * The accessible name of the tree, set as `aria-label` on the root `ul`.
46
+ * Use `ariaLabelledBy` instead when the name is visible on the page.
47
+ *
48
+ * @group Appearance
49
+ */
50
+ ariaLabel?: string;
51
+ /**
52
+ * The id of the element that names the tree, set as `aria-labelledby` on
53
+ * the root `ul`.
54
+ *
55
+ * @group Appearance
56
+ */
57
+ ariaLabelledBy?: string;
43
58
  /**
44
59
  * Escape node names. With `false`, names are inserted as html — only do
45
60
  * that for data you control.
@@ -82,8 +97,8 @@ export interface TreeElementOptions {
82
97
  *
83
98
  * Type: `HTMLElement | string`
84
99
  *
85
- * @defaultValue `"►"` (`►`), or `"◀"` (`◀`) when `rtl` is
86
- * true.
100
+ * @defaultValue An svg triangle pointing right, or left when `rtl` is
101
+ * true. It is sized in em and filled with `currentColor`.
87
102
  * @group Appearance
88
103
  */
89
104
  closedIcon?: IconElement;
@@ -129,7 +144,7 @@ export interface TreeElementOptions {
129
144
  */
130
145
  dragAndDrop: boolean;
131
146
  /**
132
- * Handle the arrow keys when the focus is on the tree. See
147
+ * Handle the keyboard when the focus is on the tree. See
133
148
  * [Selection](/guide/selection#keyboard-navigation).
134
149
  *
135
150
  * @defaultValue `true`
@@ -243,7 +258,8 @@ export interface TreeElementOptions {
243
258
  *
244
259
  * Type: `HTMLElement | string`
245
260
  *
246
- * @defaultValue `"▼"` (`▼`)
261
+ * @defaultValue An svg triangle pointing down, sized in em and filled with
262
+ * `currentColor`.
247
263
  * @group Appearance
248
264
  */
249
265
  openedIcon?: IconElement;
@@ -302,7 +318,8 @@ export interface TreeElementOptions {
302
318
  startDndDelay?: number;
303
319
  /**
304
320
  * The `tabindex` of the selected node's title, which is what makes the
305
- * tree focusable.
321
+ * tree focusable. When no node is selected, the first node gets it. The
322
+ * other nodes get `-1`.
306
323
  *
307
324
  * @defaultValue `0`
308
325
  * @group Selection
package/src/requestUrl.ts CHANGED
@@ -1,28 +1,11 @@
1
- // Url class for absolute and relative urls.
2
-
3
- const isAbsoluteUrl = (inputUrl: string) => {
4
- try {
5
- new URL(inputUrl);
6
- return true;
7
- } catch {
8
- return false;
9
- }
10
- };
11
-
12
- const LOCALHOST = "http://localhost";
1
+ // Url of a request. A relative url is resolved against the page, like a link
2
+ // or `fetch` would, so it also works when the page is in a subdirectory.
13
3
 
14
4
  class RequestUrl {
15
- private isAbsolute: boolean;
16
5
  private url: URL;
17
6
 
18
7
  constructor(inputUrl: string) {
19
- if (isAbsoluteUrl(inputUrl)) {
20
- this.url = new URL(inputUrl);
21
- this.isAbsolute = true;
22
- } else {
23
- this.url = new URL(inputUrl, LOCALHOST);
24
- this.isAbsolute = false;
25
- }
8
+ this.url = new URL(inputUrl, document.baseURI);
26
9
  }
27
10
 
28
11
  setSearchParam(key: string, value: string) {
@@ -30,11 +13,7 @@ class RequestUrl {
30
13
  }
31
14
 
32
15
  value() {
33
- if (this.isAbsolute) {
34
- return this.url.href;
35
- } else {
36
- return this.url.href.slice(LOCALHOST.length);
37
- }
16
+ return this.url.href;
38
17
  }
39
18
  }
40
19
 
@@ -73,11 +73,7 @@ export default class SaveStateHandler {
73
73
 
74
74
  const state = this.getStateFromStorage();
75
75
 
76
- if (state?.selected_node) {
77
- return state.selected_node[0] ?? null;
78
- } else {
79
- return null;
80
- }
76
+ return state?.selected_node ? (state.selected_node[0] ?? null) : null;
81
77
  }
82
78
 
83
79
  public getState(): SavedState {
@@ -97,11 +93,11 @@ export default class SaveStateHandler {
97
93
  const getSelectedNodeIds = (): NodeId[] => {
98
94
  const selectedNodeIds: NodeId[] = [];
99
95
 
100
- this.getSelectedNodes().forEach((node) => {
96
+ for (const node of this.getSelectedNodes()) {
101
97
  if (node.id != null) {
102
98
  selectedNodeIds.push(node.id);
103
99
  }
104
- });
100
+ }
105
101
 
106
102
  return selectedNodeIds;
107
103
  };
@@ -119,11 +115,7 @@ export default class SaveStateHandler {
119
115
 
120
116
  const jsonData = this.loadFromStorage();
121
117
 
122
- if (jsonData) {
123
- return this.parseState(jsonData);
124
- } else {
125
- return null;
126
- }
118
+ return jsonData ? this.parseState(jsonData) : null;
127
119
  }
128
120
 
129
121
  public saveState(): void {
@@ -147,11 +139,9 @@ export default class SaveStateHandler {
147
139
  result: must load on demand (boolean)
148
140
  */
149
141
  public setInitialState(state: SavedState): boolean {
150
- let mustLoadOnDemand = false;
151
-
152
- if (state.open_nodes) {
153
- mustLoadOnDemand = this.openInitialNodes(state.open_nodes);
154
- }
142
+ const mustLoadOnDemand = state.open_nodes
143
+ ? this.openInitialNodes(state.open_nodes)
144
+ : false;
155
145
 
156
146
  this.resetSelection();
157
147
 
@@ -175,9 +165,7 @@ export default class SaveStateHandler {
175
165
  for (const nodeId of nodeIds) {
176
166
  const node = this.getNodeById(nodeId);
177
167
 
178
- if (!node) {
179
- newNodesIds.push(nodeId);
180
- } else {
168
+ if (node) {
181
169
  if (!node.is_loading) {
182
170
  if (node.load_on_demand) {
183
171
  await loadAndOpenNode(node);
@@ -185,15 +173,15 @@ export default class SaveStateHandler {
185
173
  await this.openNode(node, false);
186
174
  }
187
175
  }
176
+ } else {
177
+ newNodesIds.push(nodeId);
188
178
  }
189
179
  }
190
180
 
191
181
  nodeIds = newNodesIds;
192
182
 
193
- if (state.selected_node) {
194
- if (this.selectInitialNodes(state.selected_node)) {
195
- this.refreshElements(null);
196
- }
183
+ if (state.selected_node && this.selectInitialNodes(state.selected_node)) {
184
+ this.refreshElements(null);
197
185
  }
198
186
  };
199
187
 
@@ -206,19 +194,15 @@ export default class SaveStateHandler {
206
194
  }
207
195
 
208
196
  private getKeyName(): string {
209
- if (typeof this.saveStateOption === "string") {
210
- return this.saveStateOption;
211
- } else {
212
- return "tree";
213
- }
197
+ return typeof this.saveStateOption === "string"
198
+ ? this.saveStateOption
199
+ : "tree";
214
200
  }
215
201
 
216
202
  private loadFromStorage(): null | string {
217
- if (this.onGetStateFromStorage) {
218
- return this.onGetStateFromStorage();
219
- } else {
220
- return localStorage.getItem(this.getKeyName());
221
- }
203
+ return this.onGetStateFromStorage
204
+ ? this.onGetStateFromStorage()
205
+ : localStorage.getItem(this.getKeyName());
222
206
  }
223
207
 
224
208
  private openInitialNodes(nodeIds: NodeId[]): boolean {
@@ -228,10 +212,10 @@ export default class SaveStateHandler {
228
212
  const node = this.getNodeById(nodeId);
229
213
 
230
214
  if (node) {
231
- if (!node.load_on_demand) {
232
- node.is_open = true;
233
- } else {
215
+ if (node.load_on_demand) {
234
216
  mustLoadOnDemand = true;
217
+ } else {
218
+ node.is_open = true;
235
219
  }
236
220
  }
237
221
  }
@@ -254,9 +238,9 @@ export default class SaveStateHandler {
254
238
  private resetSelection(): void {
255
239
  const selectedNodes = this.getSelectedNodes();
256
240
 
257
- selectedNodes.forEach((node) => {
241
+ for (const node of selectedNodes) {
258
242
  this.removeFromSelection(node);
259
- });
243
+ }
260
244
  }
261
245
 
262
246
  private selectInitialNodes(nodeIds: NodeId[]): boolean {
@@ -265,11 +249,13 @@ export default class SaveStateHandler {
265
249
  for (const nodeId of nodeIds) {
266
250
  const node = this.getNodeById(nodeId);
267
251
 
268
- if (node) {
269
- selectCount += 1;
270
-
271
- this.addToSelection(node);
252
+ if (!node) {
253
+ continue;
272
254
  }
255
+
256
+ selectCount += 1;
257
+
258
+ this.addToSelection(node);
273
259
  }
274
260
 
275
261
  return selectCount !== 0;
@@ -26,15 +26,13 @@ export default class ContainerScrollParent extends ScrollParent {
26
26
  const rightEdge = scrollParentOffset.left + containerWidth;
27
27
  const leftEdge = scrollParentOffset.left;
28
28
  const isNearRightEdge = pageX > rightEdge - 20;
29
- const isNearLeftEdge = pageX < leftEdge + 20;
30
29
 
31
30
  if (isNearRightEdge) {
32
31
  return "right";
33
- } else if (isNearLeftEdge) {
34
- return "left";
35
32
  }
36
33
 
37
- return undefined;
34
+ const isNearLeftEdge = pageX < leftEdge + 20;
35
+ return isNearLeftEdge ? "left" : undefined;
38
36
  }
39
37
 
40
38
  protected getNewVerticalScrollDirection(
@@ -44,11 +42,7 @@ export default class ContainerScrollParent extends ScrollParent {
44
42
  return "top";
45
43
  }
46
44
 
47
- if (pageY > this.getScrollParentBottom()) {
48
- return "bottom";
49
- }
50
-
51
- return undefined;
45
+ return pageY > this.getScrollParentBottom() ? "bottom" : undefined;
52
46
  }
53
47
 
54
48
  private getScrollParentBottom() {
@@ -43,9 +43,8 @@ const createScrollParent = (
43
43
  container,
44
44
  refreshHitAreas,
45
45
  });
46
- } else {
47
- return new DocumentScrollParent({ refreshHitAreas, treeElement });
48
46
  }
47
+ return new DocumentScrollParent({ refreshHitAreas, treeElement });
49
48
  };
50
49
 
51
50
  export default createScrollParent;
@@ -42,17 +42,13 @@ export default class DocumentScrollParent extends ScrollParent {
42
42
  const windowWidth = window.innerWidth;
43
43
 
44
44
  const isNearRightEdge = pageX > windowWidth - 20;
45
- const isNearLeftEdge = pageX - scrollLeft < 20;
46
45
 
47
46
  if (isNearRightEdge && this.canScrollRight()) {
48
47
  return "right";
49
48
  }
50
49
 
51
- if (isNearLeftEdge) {
52
- return "left";
53
- }
54
-
55
- return undefined;
50
+ const isNearLeftEdge = pageX - scrollLeft < 20;
51
+ return isNearLeftEdge ? "left" : undefined;
56
52
  }
57
53
 
58
54
  protected getNewVerticalScrollDirection(
@@ -67,11 +63,9 @@ export default class DocumentScrollParent extends ScrollParent {
67
63
 
68
64
  const windowHeight = window.innerHeight;
69
65
 
70
- if (windowHeight - (pageY - scrollTop) < 20 && this.canScrollDown()) {
71
- return "bottom";
72
- }
73
-
74
- return undefined;
66
+ return windowHeight - (pageY - scrollTop) < 20 && this.canScrollDown()
67
+ ? "bottom"
68
+ : undefined;
75
69
  }
76
70
 
77
71
  private canScrollDown() {
@@ -24,19 +24,21 @@ export abstract class ScrollParent {
24
24
  const newHorizontalScrollDirection =
25
25
  this.getNewHorizontalScrollDirection(pageX);
26
26
 
27
- if (this.horizontalScrollDirection !== newHorizontalScrollDirection) {
28
- this.horizontalScrollDirection = newHorizontalScrollDirection;
29
-
30
- if (this.horizontalScrollTimeout != null) {
31
- window.clearTimeout(this.horizontalScrollTimeout);
32
- }
33
-
34
- if (newHorizontalScrollDirection) {
35
- this.horizontalScrollTimeout = window.setTimeout(
36
- this.scrollHorizontally.bind(this),
37
- 40,
38
- );
39
- }
27
+ if (this.horizontalScrollDirection === newHorizontalScrollDirection) {
28
+ return;
29
+ }
30
+
31
+ this.horizontalScrollDirection = newHorizontalScrollDirection;
32
+
33
+ if (this.horizontalScrollTimeout != null) {
34
+ window.clearTimeout(this.horizontalScrollTimeout);
35
+ }
36
+
37
+ if (newHorizontalScrollDirection) {
38
+ this.horizontalScrollTimeout = window.setTimeout(
39
+ this.scrollHorizontally.bind(this),
40
+ 40,
41
+ );
40
42
  }
41
43
  }
42
44
 
@@ -44,20 +46,22 @@ export abstract class ScrollParent {
44
46
  const newVerticalScrollDirection =
45
47
  this.getNewVerticalScrollDirection(pageY);
46
48
 
47
- if (this.verticalScrollDirection !== newVerticalScrollDirection) {
48
- this.verticalScrollDirection = newVerticalScrollDirection;
49
+ if (this.verticalScrollDirection === newVerticalScrollDirection) {
50
+ return;
51
+ }
49
52
 
50
- if (this.verticalScrollTimeout != null) {
51
- window.clearTimeout(this.verticalScrollTimeout);
52
- this.verticalScrollTimeout = undefined;
53
- }
53
+ this.verticalScrollDirection = newVerticalScrollDirection;
54
+
55
+ if (this.verticalScrollTimeout != null) {
56
+ window.clearTimeout(this.verticalScrollTimeout);
57
+ this.verticalScrollTimeout = undefined;
58
+ }
54
59
 
55
- if (newVerticalScrollDirection) {
56
- this.verticalScrollTimeout = window.setTimeout(
57
- this.scrollVertically.bind(this),
58
- 40,
59
- );
60
- }
60
+ if (newVerticalScrollDirection) {
61
+ this.verticalScrollTimeout = window.setTimeout(
62
+ this.scrollVertically.bind(this),
63
+ 40,
64
+ );
61
65
  }
62
66
  }
63
67
 
@@ -20,6 +20,7 @@ interface SelectNodeHandlerParameters {
20
20
  openParents: OpenParents;
21
21
  saveState: () => void;
22
22
  triggerEvent: TriggerEvent;
23
+ updateTabStop: () => void;
23
24
  }
24
25
 
25
26
  export default class SelectNodeHandler {
@@ -32,6 +33,7 @@ export default class SelectNodeHandler {
32
33
  private selectedNodes: Set<NodeId>;
33
34
  private selectedSingleNode: Node | null;
34
35
  private triggerEvent: TriggerEvent;
36
+ private updateTabStop: () => void;
35
37
 
36
38
  constructor({
37
39
  getNodeById,
@@ -41,6 +43,7 @@ export default class SelectNodeHandler {
41
43
  openParents,
42
44
  saveState,
43
45
  triggerEvent,
46
+ updateTabStop,
44
47
  }: SelectNodeHandlerParameters) {
45
48
  this.getNodeById = getNodeById;
46
49
  this.getNodeElementForNode = getNodeElementForNode;
@@ -51,13 +54,14 @@ export default class SelectNodeHandler {
51
54
  this.selectedNodes = new Set<NodeId>();
52
55
  this.selectedSingleNode = null;
53
56
  this.triggerEvent = triggerEvent;
57
+ this.updateTabStop = updateTabStop;
54
58
  }
55
59
 
56
60
  public addToSelection(node: Node): void {
57
- if (node.id != null) {
58
- this.selectedNodes.add(node.id);
59
- } else {
61
+ if (node.id == null) {
60
62
  this.selectedSingleNode = node;
63
+ } else {
64
+ this.selectedNodes.add(node.id);
61
65
  }
62
66
  }
63
67
 
@@ -69,59 +73,50 @@ export default class SelectNodeHandler {
69
73
  public getSelectedNode(): Node | null {
70
74
  const selectedNodes = this.getSelectedNodes();
71
75
 
72
- if (selectedNodes.length) {
73
- return selectedNodes[0] ?? null;
74
- } else {
75
- return null;
76
- }
76
+ return selectedNodes.length ? (selectedNodes[0] ?? null) : null;
77
77
  }
78
78
 
79
79
  public getSelectedNodes(): Node[] {
80
80
  if (this.selectedSingleNode) {
81
81
  return [this.selectedSingleNode];
82
- } else {
83
- const selectedNodes: Node[] = [];
82
+ }
84
83
 
85
- this.selectedNodes.forEach((id) => {
86
- const node = this.getNodeById(id);
87
- if (node) {
88
- selectedNodes.push(node);
89
- }
90
- });
84
+ const selectedNodes: Node[] = [];
91
85
 
92
- return selectedNodes;
93
- }
86
+ this.selectedNodes.forEach((id) => {
87
+ const node = this.getNodeById(id);
88
+ if (node) {
89
+ selectedNodes.push(node);
90
+ }
91
+ });
92
+
93
+ return selectedNodes;
94
94
  }
95
95
 
96
96
  public getSelectedNodesUnder(parent: Node): Node[] {
97
97
  if (this.selectedSingleNode) {
98
- if (parent.isParentOf(this.selectedSingleNode)) {
99
- return [this.selectedSingleNode];
100
- } else {
101
- return [];
102
- }
103
- } else {
104
- const selectedNodes: Node[] = [];
98
+ return parent.isParentOf(this.selectedSingleNode)
99
+ ? [this.selectedSingleNode]
100
+ : [];
101
+ }
105
102
 
106
- this.selectedNodes.forEach((id) => {
107
- const node = this.getNodeById(id);
108
- if (node && parent.isParentOf(node)) {
109
- selectedNodes.push(node);
110
- }
111
- });
103
+ const selectedNodes: Node[] = [];
112
104
 
113
- return selectedNodes;
114
- }
105
+ this.selectedNodes.forEach((id) => {
106
+ const node = this.getNodeById(id);
107
+ if (node && parent.isParentOf(node)) {
108
+ selectedNodes.push(node);
109
+ }
110
+ });
111
+
112
+ return selectedNodes;
115
113
  }
116
114
 
117
115
  public isNodeSelected(node: Node): boolean {
118
116
  if (node.id != null) {
119
117
  return this.selectedNodes.has(node.id);
120
- } else if (this.selectedSingleNode) {
121
- return this.selectedSingleNode === node;
122
- } else {
123
- return false;
124
118
  }
119
+ return this.selectedSingleNode ? this.selectedSingleNode === node : false;
125
120
  }
126
121
 
127
122
  public removeFromSelection(node: Node, includeChildren = false): void {
@@ -155,7 +150,7 @@ export default class SelectNodeHandler {
155
150
  */
156
151
  public selectSingleNode(node: Node, optionsParam?: SelectNodeOptions) {
157
152
  const defaultOptions = { mustSetFocus: true, mustToggle: true };
158
- const selectOptions = { ...defaultOptions, ...(optionsParam ?? {}) };
153
+ const selectOptions = { ...defaultOptions, ...optionsParam };
159
154
 
160
155
  const canSelect = (): boolean => {
161
156
  if (!this.getSelectable()) {
@@ -197,6 +192,7 @@ export default class SelectNodeHandler {
197
192
  });
198
193
  }
199
194
 
195
+ this.updateTabStop();
200
196
  this.saveState();
201
197
  }
202
198
  }