tree-element 0.1.0 → 0.2.0

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 (149) hide show
  1. package/README.md +49 -29
  2. package/lib/animation.js +5 -5
  3. package/lib/animation.js.map +1 -1
  4. package/lib/classNames.d.ts.map +1 -1
  5. package/lib/classNames.js +2 -2
  6. package/lib/classNames.js.map +1 -1
  7. package/lib/dataLoader.d.ts.map +1 -1
  8. package/lib/dataLoader.js +18 -21
  9. package/lib/dataLoader.js.map +1 -1
  10. package/lib/dragAndDropHandler/binarySearch.js +3 -3
  11. package/lib/dragAndDropHandler/binarySearch.js.map +1 -1
  12. package/lib/dragAndDropHandler/dragElement.d.ts.map +1 -1
  13. package/lib/dragAndDropHandler/dragElement.js +9 -12
  14. package/lib/dragAndDropHandler/dragElement.js.map +1 -1
  15. package/lib/dragAndDropHandler/generateHitAreas.d.ts.map +1 -1
  16. package/lib/dragAndDropHandler/generateHitAreas.js +25 -25
  17. package/lib/dragAndDropHandler/generateHitAreas.js.map +1 -1
  18. package/lib/dragAndDropHandler/index.d.ts.map +1 -1
  19. package/lib/dragAndDropHandler/index.js +90 -114
  20. package/lib/dragAndDropHandler/index.js.map +1 -1
  21. package/lib/dragAndDropHandler/iterateVisibleNodes.d.ts.map +1 -1
  22. package/lib/dragAndDropHandler/iterateVisibleNodes.js +10 -10
  23. package/lib/dragAndDropHandler/iterateVisibleNodes.js.map +1 -1
  24. package/lib/dragAndDropHandler/types.d.ts.map +1 -1
  25. package/lib/elementsRenderer.d.ts +15 -6
  26. package/lib/elementsRenderer.d.ts.map +1 -1
  27. package/lib/elementsRenderer.js +157 -121
  28. package/lib/elementsRenderer.js.map +1 -1
  29. package/lib/events.d.ts +11 -4
  30. package/lib/events.d.ts.map +1 -1
  31. package/lib/index.d.ts +5 -5
  32. package/lib/index.d.ts.map +1 -1
  33. package/lib/index.js +249 -252
  34. package/lib/index.js.map +1 -1
  35. package/lib/keyHandler.d.ts +2 -3
  36. package/lib/keyHandler.d.ts.map +1 -1
  37. package/lib/keyHandler.js +26 -25
  38. package/lib/keyHandler.js.map +1 -1
  39. package/lib/methodTypes.d.ts +1 -1
  40. package/lib/methodTypes.d.ts.map +1 -1
  41. package/lib/mouseHandler.d.ts.map +1 -1
  42. package/lib/mouseHandler.js +26 -42
  43. package/lib/mouseHandler.js.map +1 -1
  44. package/lib/mouseUtils.d.ts.map +1 -1
  45. package/lib/mouseUtils.js +2 -2
  46. package/lib/mouseUtils.js.map +1 -1
  47. package/lib/node.d.ts +2 -1
  48. package/lib/node.d.ts.map +1 -1
  49. package/lib/node.js +36 -35
  50. package/lib/node.js.map +1 -1
  51. package/lib/nodeElement/borderDropHint.d.ts.map +1 -1
  52. package/lib/nodeElement/borderDropHint.js +4 -5
  53. package/lib/nodeElement/borderDropHint.js.map +1 -1
  54. package/lib/nodeElement/folderElement.d.ts +7 -4
  55. package/lib/nodeElement/folderElement.d.ts.map +1 -1
  56. package/lib/nodeElement/folderElement.js +61 -42
  57. package/lib/nodeElement/folderElement.js.map +1 -1
  58. package/lib/nodeElement/ghostDropHint.d.ts.map +1 -1
  59. package/lib/nodeElement/ghostDropHint.js +5 -9
  60. package/lib/nodeElement/ghostDropHint.js.map +1 -1
  61. package/lib/nodeElement/index.d.ts +2 -1
  62. package/lib/nodeElement/index.d.ts.map +1 -1
  63. package/lib/nodeElement/index.js +34 -26
  64. package/lib/nodeElement/index.js.map +1 -1
  65. package/lib/nodeUtils.d.ts.map +1 -1
  66. package/lib/nodeUtils.js +1 -1
  67. package/lib/nodeUtils.js.map +1 -1
  68. package/lib/options.d.ts.map +1 -1
  69. package/lib/positionUtils.js +3 -3
  70. package/lib/positionUtils.js.map +1 -1
  71. package/lib/requestUrl.d.ts +1 -1
  72. package/lib/requestUrl.d.ts.map +1 -1
  73. package/lib/requestUrl.js +4 -6
  74. package/lib/requestUrl.js.map +1 -1
  75. package/lib/saveStateHandler.d.ts.map +1 -1
  76. package/lib/saveStateHandler.js +38 -48
  77. package/lib/saveStateHandler.js.map +1 -1
  78. package/lib/scrollHandler/containerScrollParent.d.ts.map +1 -1
  79. package/lib/scrollHandler/containerScrollParent.js +9 -11
  80. package/lib/scrollHandler/containerScrollParent.js.map +1 -1
  81. package/lib/scrollHandler/createScrollParent.d.ts.map +1 -1
  82. package/lib/scrollHandler/createScrollParent.js +10 -10
  83. package/lib/scrollHandler/createScrollParent.js.map +1 -1
  84. package/lib/scrollHandler/documentScrollParent.d.ts.map +1 -1
  85. package/lib/scrollHandler/documentScrollParent.js +16 -19
  86. package/lib/scrollHandler/documentScrollParent.js.map +1 -1
  87. package/lib/scrollHandler/scrollParent.d.ts.map +1 -1
  88. package/lib/scrollHandler/scrollParent.js +11 -17
  89. package/lib/scrollHandler/scrollParent.js.map +1 -1
  90. package/lib/scrollHandler.d.ts.map +1 -1
  91. package/lib/scrollHandler.js +11 -14
  92. package/lib/scrollHandler.js.map +1 -1
  93. package/lib/selectNodeHandler.d.ts +2 -2
  94. package/lib/selectNodeHandler.d.ts.map +1 -1
  95. package/lib/selectNodeHandler.js +45 -54
  96. package/lib/selectNodeHandler.js.map +1 -1
  97. package/lib/setDefaultOptions.d.ts.map +1 -1
  98. package/lib/setDefaultOptions.js +23 -28
  99. package/lib/setDefaultOptions.js.map +1 -1
  100. package/lib/triggerCustomEvent.d.ts.map +1 -1
  101. package/lib/triggerCustomEvent.js +2 -2
  102. package/lib/triggerCustomEvent.js.map +1 -1
  103. package/lib/util.d.ts.map +1 -1
  104. package/lib/util.js +2 -2
  105. package/lib/util.js.map +1 -1
  106. package/lib/version.d.ts +1 -1
  107. package/lib/version.js +1 -1
  108. package/lib/version.js.map +1 -1
  109. package/package.json +7 -3
  110. package/src/animation.ts +1 -1
  111. package/src/classNames.ts +52 -52
  112. package/src/dataLoader.ts +68 -70
  113. package/src/dragAndDropHandler/binarySearch.ts +17 -17
  114. package/src/dragAndDropHandler/dragElement.ts +50 -50
  115. package/src/dragAndDropHandler/generateHitAreas.ts +156 -161
  116. package/src/dragAndDropHandler/index.ts +342 -351
  117. package/src/dragAndDropHandler/iterateVisibleNodes.ts +59 -63
  118. package/src/dragAndDropHandler/types.ts +5 -5
  119. package/src/elementsRenderer.ts +351 -298
  120. package/src/events.ts +216 -209
  121. package/src/header.txt +1 -1
  122. package/src/index.ts +52 -82
  123. package/src/keyHandler.ts +125 -115
  124. package/src/methodTypes.ts +4 -7
  125. package/src/mouseHandler.ts +314 -317
  126. package/src/mouseUtils.ts +14 -14
  127. package/src/node.ts +761 -766
  128. package/src/nodeElement/borderDropHint.ts +25 -25
  129. package/src/nodeElement/folderElement.ts +135 -112
  130. package/src/nodeElement/ghostDropHint.ts +62 -62
  131. package/src/nodeElement/index.ts +88 -74
  132. package/src/nodeUtils.ts +5 -5
  133. package/src/options.ts +6 -2
  134. package/src/requestUrl.ts +3 -3
  135. package/src/saveStateHandler.ts +204 -206
  136. package/src/scrollHandler/containerScrollParent.ts +49 -52
  137. package/src/scrollHandler/createScrollParent.ts +27 -27
  138. package/src/scrollHandler/documentScrollParent.ts +70 -70
  139. package/src/scrollHandler/scrollParent.ts +98 -98
  140. package/src/scrollHandler.ts +45 -45
  141. package/src/selectNodeHandler.ts +176 -166
  142. package/src/setDefaultOptions.ts +25 -22
  143. package/src/triggerCustomEvent.ts +7 -3
  144. package/src/util.ts +2 -2
  145. package/src/version.ts +1 -1
  146. package/tree_element.debug.js +3770 -3799
  147. package/tree_element.debug.js.map +1 -1
  148. package/tree_element.js +2 -2
  149. package/tree_element.js.map +1 -1
package/src/index.ts CHANGED
@@ -54,13 +54,10 @@ interface TreeElementParams extends Partial<TreeElementOptions> {
54
54
  /** Replaces how events are dispatched. It must return whether the event
55
55
  * was not cancelled. This exists for tests and for integrating with
56
56
  * another event system. */
57
- overrideTriggerEventProvider?: TriggerEventProvider,
57
+ overrideTriggerEventProvider?: TriggerEventProvider;
58
58
  }
59
59
 
60
60
  export default class TreeElement {
61
- /** @hidden */
62
- public tree: Node;
63
-
64
61
  private classNames: ClassNames;
65
62
  private dataLoader: DataLoader;
66
63
  private dndHandler: DragAndDropHandler;
@@ -74,14 +71,20 @@ export default class TreeElement {
74
71
  private saveStateHandler: SaveStateHandler;
75
72
  private scrollHandler: ScrollHandler;
76
73
  private selectNodeHandler: SelectNodeHandler;
74
+ private tree: Node;
77
75
  private triggerEventProvider: TriggerEventProvider;
78
76
 
79
77
  /** @hidden */
80
- constructor({ htmlElement, overrideTriggerEventProvider, ...options }: TreeElementParams) {
78
+ constructor({
79
+ htmlElement,
80
+ overrideTriggerEventProvider,
81
+ ...options
82
+ }: TreeElementParams) {
81
83
  this.htmlElement = htmlElement;
82
84
  this.options = setDefaultOptions(htmlElement, options);
83
85
  this.classNames = createClassNames(this.options);
84
- this.triggerEventProvider = overrideTriggerEventProvider ?? triggerCustomEvent;
86
+ this.triggerEventProvider =
87
+ overrideTriggerEventProvider ?? triggerCustomEvent;
85
88
 
86
89
  this.isInitialized = false;
87
90
  this.tree = new Node({}, true);
@@ -130,7 +133,7 @@ export default class TreeElement {
130
133
 
131
134
  const saveState = () => {
132
135
  saveStateHandler.saveState();
133
- }
136
+ };
134
137
 
135
138
  const selectNodeHandler = new SelectNodeHandler({
136
139
  getNodeById,
@@ -139,7 +142,7 @@ export default class TreeElement {
139
142
  getSelectable: () => this.options.selectable,
140
143
  openParents,
141
144
  saveState,
142
- triggerEvent
145
+ triggerEvent,
143
146
  });
144
147
 
145
148
  const addToSelection =
@@ -150,7 +153,8 @@ export default class TreeElement {
150
153
  selectNodeHandler.isNodeSelected.bind(selectNodeHandler);
151
154
  const removeFromSelection =
152
155
  selectNodeHandler.removeFromSelection.bind(selectNodeHandler);
153
- const selectNode = selectNodeHandler.selectSingleNode.bind(selectNodeHandler);
156
+ const selectNode =
157
+ selectNodeHandler.selectSingleNode.bind(selectNodeHandler);
154
158
 
155
159
  const getMouseDelay = () => this.options.startDndDelay ?? 0;
156
160
 
@@ -267,10 +271,7 @@ export default class TreeElement {
267
271
  * @returns The new node, or `null` when the node has no parent.
268
272
  * @group Changing the tree
269
273
  */
270
- public addNodeAfter(
271
- nodeData: NodeData,
272
- existingNode: Node,
273
- ): Node | null {
274
+ public addNodeAfter(nodeData: NodeData, existingNode: Node): Node | null {
274
275
  const newNode = existingNode.addAfter(nodeData);
275
276
 
276
277
  if (newNode) {
@@ -286,10 +287,7 @@ export default class TreeElement {
286
287
  * @returns The new node, or `null` when the node has no parent.
287
288
  * @group Changing the tree
288
289
  */
289
- public addNodeBefore(
290
- nodeData: NodeData,
291
- existingNode: Node,
292
- ): Node | null {
290
+ public addNodeBefore(nodeData: NodeData, existingNode: Node): Node | null {
293
291
  const newNode = existingNode.addBefore(nodeData);
294
292
 
295
293
  if (newNode) {
@@ -306,10 +304,7 @@ export default class TreeElement {
306
304
  * @returns The new node, or `null` when the node has no parent.
307
305
  * @group Changing the tree
308
306
  */
309
- public addParentNode(
310
- nodeData: NodeData,
311
- existingNode: Node,
312
- ): Node | null {
307
+ public addParentNode(nodeData: NodeData, existingNode: Node): Node | null {
313
308
  const newNode = existingNode.addParent(nodeData);
314
309
 
315
310
  if (newNode) {
@@ -377,7 +372,7 @@ export default class TreeElement {
377
372
  * @group Other
378
373
  */
379
374
  public deinit(): void {
380
- this.htmlElement.textContent = '';
375
+ this.htmlElement.textContent = "";
381
376
 
382
377
  this.dataLoader.deinit();
383
378
  this.keyHandler.deinit();
@@ -465,11 +460,11 @@ export default class TreeElement {
465
460
  }
466
461
 
467
462
  /**
468
- * Returns the selected node, or `false` when nothing is selected.
463
+ * Returns the selected node, or `null` when nothing is selected.
469
464
  *
470
465
  * @group Selection
471
466
  */
472
- public getSelectedNode(): false | Node {
467
+ public getSelectedNode(): Node | null {
473
468
  return this.selectNodeHandler.getSelectedNode();
474
469
  }
475
470
 
@@ -571,11 +566,10 @@ export default class TreeElement {
571
566
  * @param url - Defaults to the `dataUrl` option.
572
567
  * @group Loading data
573
568
  */
574
- public async loadDataFromUrl(
575
- url?: string,
576
- parentNode?: Node
577
- ): Promise<void> {
578
- const requestUrl = url ? new RequestUrl(url) : this.createRequestUrl(parentNode);
569
+ public async loadDataFromUrl(url?: string, parentNode?: Node): Promise<void> {
570
+ const requestUrl = url
571
+ ? new RequestUrl(url)
572
+ : this.createRequestUrl(parentNode);
579
573
 
580
574
  if (requestUrl) {
581
575
  await this.dataLoader.loadFromUrl(requestUrl, parentNode);
@@ -588,10 +582,7 @@ export default class TreeElement {
588
582
  * @group Selection
589
583
  */
590
584
  public moveDown() {
591
- const selectedNode = this.getSelectedNode();
592
- if (selectedNode) {
593
- this.keyHandler.moveDown(selectedNode);
594
- }
585
+ this.keyHandler.moveDown();
595
586
  }
596
587
 
597
588
  /**
@@ -605,11 +596,7 @@ export default class TreeElement {
605
596
  * @param position - `"before"`, `"after"` or `"inside"`.
606
597
  * @group Changing the tree
607
598
  */
608
- public moveNode(
609
- node: Node,
610
- targetNode: Node,
611
- position: Position,
612
- ): void {
599
+ public moveNode(node: Node, targetNode: Node, position: Position): void {
613
600
  this.tree.moveNode(node, targetNode, position);
614
601
  this.refreshElements(null);
615
602
  }
@@ -620,10 +607,7 @@ export default class TreeElement {
620
607
  * @group Selection
621
608
  */
622
609
  public moveUp() {
623
- const selectedNode = this.getSelectedNode();
624
- if (selectedNode) {
625
- this.keyHandler.moveUp(selectedNode);
626
- }
610
+ this.keyHandler.moveUp();
627
611
  }
628
612
 
629
613
  /**
@@ -640,15 +624,12 @@ export default class TreeElement {
640
624
  * @param slide - Override the `slide` option for this call.
641
625
  * @group Opening and closing
642
626
  */
643
- public async openNode(
644
- node: Node,
645
- slide?: boolean
646
- ): Promise<void> {
627
+ public async openNode(node: Node, slide?: boolean): Promise<void> {
647
628
  const mustSlide = slide ?? this.options.slide;
648
629
 
649
630
  const doOpenNode = async (
650
631
  openedNode: Node,
651
- slideOption: boolean
632
+ slideOption: boolean,
652
633
  ): Promise<void> => {
653
634
  if (!node.children.length) {
654
635
  return;
@@ -656,10 +637,7 @@ export default class TreeElement {
656
637
 
657
638
  const folderElement = this.createFolderElement(openedNode);
658
639
 
659
- await folderElement.open(
660
- slideOption,
661
- this.options.animationSpeed,
662
- );
640
+ await folderElement.open(slideOption, this.options.animationSpeed);
663
641
  };
664
642
 
665
643
  if (node.isFolder() || node.isEmptyFolder) {
@@ -752,9 +730,7 @@ export default class TreeElement {
752
730
  return;
753
731
  }
754
732
 
755
- const top =
756
- getOffsetTop(node.element) -
757
- getOffsetTop(this.htmlElement);
733
+ const top = getOffsetTop(node.element) - getOffsetTop(this.htmlElement);
758
734
 
759
735
  this.scrollHandler.scrollToY(top);
760
736
  }
@@ -768,10 +744,7 @@ export default class TreeElement {
768
744
  * `false`.
769
745
  * @group Selection
770
746
  */
771
- public selectNode(
772
- node: Node | null,
773
- options?: SelectNodeOptions,
774
- ): void {
747
+ public selectNode(node: Node | null, options?: SelectNodeOptions): void {
775
748
  if (!node) {
776
749
  // Called with empty node -> deselect current node
777
750
  this.deselectCurrentNode();
@@ -793,13 +766,15 @@ export default class TreeElement {
793
766
  }
794
767
 
795
768
  /**
796
- * Applies a state to the tree.
769
+ * Applies a state to the tree, and saves it to storage when `saveState` is
770
+ * enabled.
797
771
  *
798
772
  * @group State
799
773
  */
800
774
  public setState(state: SavedState) {
801
775
  this.saveStateHandler.setInitialState(state);
802
776
  this.refreshElements(null);
777
+ this.saveState();
803
778
  }
804
779
 
805
780
  /**
@@ -879,6 +854,7 @@ export default class TreeElement {
879
854
  this.scrollHandler,
880
855
  );
881
856
  const openedIconElement = this.renderer.openedIconElement;
857
+ const renderChildren = this.renderer.renderChildren.bind(this.renderer);
882
858
  const tabIndex = this.options.tabIndex;
883
859
  const treeElement = this.htmlElement;
884
860
  const triggerEvent = this.triggerEvent.bind(this);
@@ -889,6 +865,7 @@ export default class TreeElement {
889
865
  getScrollLeft,
890
866
  node,
891
867
  openedIconElement,
868
+ renderChildren,
892
869
  tabIndex,
893
870
  treeElement,
894
871
  triggerEvent,
@@ -913,9 +890,9 @@ export default class TreeElement {
913
890
  }
914
891
 
915
892
  /* Create a RequestUrl based on the url in the options.
916
- * Add a 'node' query parameter for loading on demand
917
- * Add a 'selected_node' query parameter if a node is selected.
918
- */
893
+ * Add a 'node' query parameter for loading on demand
894
+ * Add a 'selected_node' query parameter if a node is selected.
895
+ */
919
896
  private createRequestUrl(node?: Node): null | RequestUrl {
920
897
  const dataUrl = this.options.dataUrl;
921
898
 
@@ -935,12 +912,12 @@ export default class TreeElement {
935
912
 
936
913
  if (node?.id) {
937
914
  // Load on demand of a subtree; add node parameter
938
- requestUrl.setSearchParam('node', node.id.toString());
915
+ requestUrl.setSearchParam("node", node.id.toString());
939
916
  } else {
940
917
  // Add selected_node parameter
941
918
  const selectedNodeId = this.getNodeIdToBeSelected();
942
919
  if (selectedNodeId) {
943
- requestUrl.setSearchParam('selected_node', selectedNodeId.toString());
920
+ requestUrl.setSearchParam("selected_node", selectedNodeId.toString());
944
921
  }
945
922
  }
946
923
 
@@ -1020,11 +997,7 @@ export default class TreeElement {
1020
997
  }
1021
998
  };
1022
999
 
1023
- this.tree = new this.options.nodeClass(
1024
- null,
1025
- true,
1026
- this.options.nodeClass,
1027
- );
1000
+ this.tree = new this.options.nodeClass(null, true, this.options.nodeClass);
1028
1001
 
1029
1002
  this.selectNodeHandler.clear();
1030
1003
 
@@ -1071,10 +1044,7 @@ export default class TreeElement {
1071
1044
  }
1072
1045
  }
1073
1046
 
1074
- private async loadFolderOnDemand(
1075
- node: Node,
1076
- slide: boolean,
1077
- ): Promise<void> {
1047
+ private async loadFolderOnDemand(node: Node, slide: boolean): Promise<void> {
1078
1048
  node.is_loading = true;
1079
1049
 
1080
1050
  await this.loadDataFromUrl(undefined, node);
@@ -1178,8 +1148,7 @@ export default class TreeElement {
1178
1148
  if (!state) {
1179
1149
  return [false, false];
1180
1150
  } else {
1181
- const mustLoadOnDemand =
1182
- this.saveStateHandler.setInitialState(state);
1151
+ const mustLoadOnDemand = this.saveStateHandler.setInitialState(state);
1183
1152
 
1184
1153
  // return true: the state is restored
1185
1154
  return [true, mustLoadOnDemand];
@@ -1221,16 +1190,14 @@ export default class TreeElement {
1221
1190
 
1222
1191
  // Set the initial state for nodes that are loaded on demand
1223
1192
  private async setInitialStateOnDemand(): Promise<void> {
1224
- return new Promise(resolve => {
1193
+ return new Promise((resolve) => {
1225
1194
  const restoreState = (): boolean => {
1226
1195
  const state = this.saveStateHandler.getStateFromStorage();
1227
1196
 
1228
1197
  if (!state) {
1229
1198
  return false;
1230
1199
  } else {
1231
- void this.saveStateHandler.setInitialStateOnDemand(
1232
- state,
1233
- ).then(() => {
1200
+ void this.saveStateHandler.setInitialStateOnDemand(state).then(() => {
1234
1201
  resolve();
1235
1202
  });
1236
1203
 
@@ -1284,7 +1251,10 @@ export default class TreeElement {
1284
1251
  this.nodeMap.set(element, node);
1285
1252
  }
1286
1253
 
1287
- private triggerEvent<Name extends TreeEventName>(eventName: Name, values?: TreeEvents[Name]): boolean {
1288
- return this.triggerEventProvider(this.htmlElement, eventName, values)
1254
+ private triggerEvent<Name extends TreeEventName>(
1255
+ eventName: Name,
1256
+ values?: TreeEvents[Name],
1257
+ ): boolean {
1258
+ return this.triggerEventProvider(this.htmlElement, eventName, values);
1289
1259
  }
1290
- }
1260
+ }
package/src/keyHandler.ts CHANGED
@@ -1,139 +1,149 @@
1
1
  import type {
2
- CloseNode,
3
- GetSelectedNode,
4
- IsFocusOnTree,
5
- OpenNode,
6
- SelectNode,
2
+ CloseNode,
3
+ GetSelectedNode,
4
+ IsFocusOnTree,
5
+ OpenNode,
6
+ SelectNode,
7
7
  } from "./methodTypes";
8
8
  import type { Node } from "./node";
9
9
 
10
10
  interface KeyHandlerParams {
11
- closeNode: CloseNode;
12
- getSelectedNode: GetSelectedNode;
13
- isFocusOnTree: IsFocusOnTree;
14
- keyboardSupport: boolean;
15
- openNode: OpenNode;
16
- selectNode: SelectNode;
11
+ closeNode: CloseNode;
12
+ getSelectedNode: GetSelectedNode;
13
+ isFocusOnTree: IsFocusOnTree;
14
+ keyboardSupport: boolean;
15
+ openNode: OpenNode;
16
+ selectNode: SelectNode;
17
17
  }
18
18
 
19
19
  export default class KeyHandler {
20
- private closeNode: CloseNode;
21
- private getSelectedNode: GetSelectedNode;
22
-
23
- private isFocusOnTree: IsFocusOnTree;
24
-
25
- private keyboardSupport: boolean;
26
- private openNode: OpenNode;
27
- private originalSelectNode: SelectNode;
28
- constructor({
29
- closeNode,
30
- getSelectedNode,
31
- isFocusOnTree,
32
- keyboardSupport,
33
- openNode,
34
- selectNode,
35
- }: KeyHandlerParams) {
36
- this.closeNode = closeNode;
37
- this.getSelectedNode = getSelectedNode;
38
- this.isFocusOnTree = isFocusOnTree;
39
- this.keyboardSupport = keyboardSupport;
40
- this.openNode = openNode;
41
- this.originalSelectNode = selectNode;
42
-
43
- if (keyboardSupport) {
44
- document.addEventListener("keydown", this.handleKeyDown);
45
- }
20
+ private closeNode: CloseNode;
21
+ private getSelectedNode: GetSelectedNode;
22
+
23
+ private isFocusOnTree: IsFocusOnTree;
24
+
25
+ private keyboardSupport: boolean;
26
+ private openNode: OpenNode;
27
+ private originalSelectNode: SelectNode;
28
+
29
+ constructor({
30
+ closeNode,
31
+ getSelectedNode,
32
+ isFocusOnTree,
33
+ keyboardSupport,
34
+ openNode,
35
+ selectNode,
36
+ }: KeyHandlerParams) {
37
+ this.closeNode = closeNode;
38
+ this.getSelectedNode = getSelectedNode;
39
+ this.isFocusOnTree = isFocusOnTree;
40
+ this.keyboardSupport = keyboardSupport;
41
+ this.openNode = openNode;
42
+ this.originalSelectNode = selectNode;
43
+
44
+ if (keyboardSupport) {
45
+ document.addEventListener("keydown", this.handleKeyDown);
46
46
  }
47
+ }
47
48
 
48
- public deinit(): void {
49
- if (this.keyboardSupport) {
50
- document.removeEventListener("keydown", this.handleKeyDown);
51
- }
49
+ public deinit(): void {
50
+ if (this.keyboardSupport) {
51
+ document.removeEventListener("keydown", this.handleKeyDown);
52
52
  }
53
+ }
53
54
 
54
- public moveDown(selectedNode: Node): boolean {
55
- return this.selectNode(selectedNode.getNextVisibleNode());
55
+ public moveDown(): boolean {
56
+ return this.selectNode(this.getSelectedNode()?.getNextVisibleNode());
57
+ }
58
+
59
+ public moveUp(): boolean {
60
+ return this.selectNode(this.getSelectedNode()?.getPreviousVisibleNode());
61
+ }
62
+
63
+ private canHandleKeyboard(): boolean {
64
+ return this.keyboardSupport && this.isFocusOnTree();
65
+ }
66
+
67
+ private handleKeyDown = (e: KeyboardEvent): void => {
68
+ if (!this.canHandleKeyboard()) {
69
+ return;
56
70
  }
57
71
 
58
- public moveUp(selectedNode: Node): boolean {
59
- return this.selectNode(selectedNode.getPreviousVisibleNode());
72
+ let isKeyHandled = false;
73
+
74
+ const selectedNode = this.getSelectedNode();
75
+ if (selectedNode) {
76
+ switch (e.key) {
77
+ case "ArrowDown":
78
+ isKeyHandled = this.moveDown();
79
+ break;
80
+
81
+ case "ArrowLeft":
82
+ isKeyHandled = this.moveLeft();
83
+ break;
84
+
85
+ case "ArrowRight":
86
+ isKeyHandled = this.moveRight();
87
+ break;
88
+
89
+ case "ArrowUp":
90
+ isKeyHandled = this.moveUp();
91
+ break;
92
+ }
60
93
  }
61
94
 
62
- private canHandleKeyboard(): boolean {
63
- return this.keyboardSupport && this.isFocusOnTree();
95
+ if (isKeyHandled) {
96
+ e.preventDefault();
64
97
  }
98
+ };
99
+
100
+ private moveLeft(): boolean {
101
+ const selectedNode = this.getSelectedNode();
65
102
 
66
- private handleKeyDown = (e: KeyboardEvent): void => {
67
- if (!this.canHandleKeyboard()) {
68
- return;
69
- }
70
-
71
- let isKeyHandled = false;
72
-
73
- const selectedNode = this.getSelectedNode();
74
- if (selectedNode) {
75
- switch (e.key) {
76
- case "ArrowDown":
77
- isKeyHandled = this.moveDown(selectedNode);
78
- break;
79
-
80
- case "ArrowLeft":
81
- isKeyHandled = this.moveLeft(selectedNode);
82
- break;
83
-
84
- case "ArrowRight":
85
- isKeyHandled = this.moveRight(selectedNode);
86
- break;
87
-
88
- case "ArrowUp":
89
- isKeyHandled = this.moveUp(selectedNode);
90
- break;
91
- }
92
- }
93
-
94
- if (isKeyHandled) {
95
- e.preventDefault();
96
- }
97
- };
98
-
99
- private moveLeft(selectedNode: Node): boolean {
100
- if (selectedNode.isFolder() && selectedNode.is_open) {
101
- // Left on an open node closes the node
102
- this.closeNode(selectedNode);
103
- return true;
104
- } else {
105
- // Left on a closed or end node moves focus to the node's parent
106
- return this.selectNode(selectedNode.getParent());
107
- }
103
+ /* istanbul ignore if */
104
+ if (!selectedNode) {
105
+ return false;
108
106
  }
109
107
 
110
- private moveRight(selectedNode: Node): boolean {
111
- if (!selectedNode.isFolder()) {
112
- return false;
113
- } else {
114
- // folder node
115
- if (selectedNode.is_open) {
116
- // Right moves to the first child of an open node
117
- return this.selectNode(selectedNode.getNextVisibleNode());
118
- } else {
119
- // Right expands a closed node
120
- void this.openNode(selectedNode);
121
- return true;
122
- }
123
- }
108
+ if (selectedNode.isFolder() && selectedNode.is_open) {
109
+ // Left on an open node closes the node
110
+ this.closeNode(selectedNode);
111
+ return true;
112
+ } else {
113
+ // Left on a closed or end node moves focus to the node's parent
114
+ return this.selectNode(selectedNode.getParent());
124
115
  }
116
+ }
125
117
 
126
- /* Select the node.
127
- * Don't do anything if the node is null.
128
- * Result: a different node was selected.
129
- */
130
- private selectNode(node: Node | null): boolean {
131
- if (!node) {
132
- return false;
133
- } else {
134
- this.originalSelectNode(node);
135
-
136
- return true;
137
- }
118
+ private moveRight(): boolean {
119
+ const selectedNode = this.getSelectedNode();
120
+
121
+ if (!selectedNode?.isFolder()) {
122
+ return false;
123
+ } else {
124
+ // folder node
125
+ if (selectedNode.is_open) {
126
+ // Right moves to the first child of an open node
127
+ return this.selectNode(selectedNode.getNextVisibleNode());
128
+ } else {
129
+ // Right expands a closed node
130
+ void this.openNode(selectedNode);
131
+ return true;
132
+ }
133
+ }
134
+ }
135
+
136
+ /* Select the node.
137
+ * Don't do anything if the node is null.
138
+ * Result: a different node was selected.
139
+ */
140
+ private selectNode(node?: Node | null): boolean {
141
+ if (!node) {
142
+ return false;
143
+ } else {
144
+ this.originalSelectNode(node);
145
+
146
+ return true;
138
147
  }
148
+ }
139
149
  }
@@ -12,7 +12,7 @@ export type GetNodeElementForNode = (node: Node) => NodeElement;
12
12
 
13
13
  export type GetScrollLeft = () => number;
14
14
 
15
- export type GetSelectedNode = () => false | Node;
15
+ export type GetSelectedNode = () => Node | null;
16
16
 
17
17
  export type GetSelectedNodes = () => Node[];
18
18
 
@@ -24,10 +24,7 @@ export type IsNodeSelected = (node: Node) => boolean;
24
24
 
25
25
  export type LoadData = (data: NodeData[], parentNode?: Node) => void;
26
26
 
27
- export type OpenNode = (
28
- node: Node,
29
- slide?: boolean,
30
- ) => Promise<void>;
27
+ export type OpenNode = (node: Node, slide?: boolean) => Promise<void>;
31
28
 
32
29
  export type OpenParents = (node: Node) => void;
33
30
 
@@ -39,6 +36,6 @@ export type SelectNode = (node: Node) => void;
39
36
 
40
37
  // Trigger an event. Return if the event is processed (true) or cancelled (false).
41
38
  export type TriggerEvent = <Name extends TreeEventName>(
42
- eventName: Name,
43
- values?: TreeEvents[Name],
39
+ eventName: Name,
40
+ values?: TreeEvents[Name],
44
41
  ) => boolean;