@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,6 +1,7 @@
1
1
  import { ItemInstance, SetStateFn } from "../../types/core";
2
2
  export type DndDataRef = {
3
3
  lastDragCode?: string;
4
+ lastAllowDrop?: boolean;
4
5
  };
5
6
  export type DndState<T> = {
6
7
  draggedItems?: ItemInstance<T>[];
@@ -8,19 +9,23 @@ export type DndState<T> = {
8
9
  dragTarget?: DropTarget<T>;
9
10
  };
10
11
  export type DragLineData = {
11
- intend: number;
12
+ indent: number;
12
13
  top: number;
13
14
  left: number;
14
- right: number;
15
+ width: number;
15
16
  };
16
17
  export type DropTarget<T> = {
17
18
  item: ItemInstance<T>;
18
19
  childIndex: number;
19
20
  insertionIndex: number;
21
+ dragLineIndex: number;
22
+ dragLineLevel: number;
20
23
  } | {
21
24
  item: ItemInstance<T>;
22
25
  childIndex: null;
23
26
  insertionIndex: null;
27
+ dragLineIndex: null;
28
+ dragLineLevel: null;
24
29
  };
25
30
  export declare enum DropTargetPosition {
26
31
  Top = "top",
@@ -32,13 +37,16 @@ export type DragAndDropFeatureDef<T> = {
32
37
  dnd?: DndState<T> | null;
33
38
  };
34
39
  config: {
35
- setDndState?: SetStateFn<DndState<T> | null>;
36
- topLinePercentage?: number;
37
- bottomLinePercentage?: number;
38
- canDropInbetween?: boolean;
40
+ setDndState?: SetStateFn<DndState<T> | undefined | null>;
41
+ /** Defines the size of the area at the top and bottom of an item where, when an item is dropped, the item willö
42
+ * be placed above or below the item within the same parent, as opposed to being placed inside the item.
43
+ * If `canReorder` is `false`, this is ignored. */
44
+ reorderAreaPercentage?: number;
45
+ canReorder?: boolean;
39
46
  isItemDraggable?: (item: ItemInstance<T>) => boolean;
40
47
  canDrag?: (items: ItemInstance<T>[]) => boolean;
41
48
  canDrop?: (items: ItemInstance<T>[], target: DropTarget<T>) => boolean;
49
+ indent?: number;
42
50
  createForeignDragObject?: (items: ItemInstance<T>[]) => {
43
51
  format: string;
44
52
  data: any;
@@ -58,6 +66,7 @@ export type DragAndDropFeatureDef<T> = {
58
66
  treeInstance: {
59
67
  getDropTarget: () => DropTarget<T> | null;
60
68
  getDragLineData: () => DragLineData | null;
69
+ getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
61
70
  };
62
71
  itemInstance: {
63
72
  isDropTarget: () => boolean;
@@ -1,6 +1,5 @@
1
1
  import { ItemInstance, TreeInstance } from "../../types/core";
2
2
  import { DropTarget } from "./types";
3
- export declare const getDragCode: ({ item, childIndex }: DropTarget<any>) => string;
4
- export declare const getDropOffset: (e: any, item: ItemInstance<any>) => number;
5
3
  export declare const canDrop: (dataTransfer: DataTransfer | null, target: DropTarget<any>, tree: TreeInstance<any>) => boolean;
6
- export declare const getDropTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>, canDropInbetween?: boolean | undefined) => DropTarget<any>;
4
+ export declare const getDragCode: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>) => string;
5
+ export declare const getDropTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>, canReorder?: boolean | undefined) => DropTarget<any>;
@@ -1,10 +1,16 @@
1
- import { DropTargetPosition } from "./types";
2
- export const getDragCode = ({ item, childIndex }) => `${item.getId()}__${childIndex !== null && childIndex !== void 0 ? childIndex : "none"}`;
3
- export const getDropOffset = (e, item) => {
4
- var _a;
5
- const bb = (_a = item.getElement()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
6
- return bb ? (e.pageY - bb.top) / bb.height : 0.5;
7
- };
1
+ var ItemDropCategory;
2
+ (function (ItemDropCategory) {
3
+ ItemDropCategory[ItemDropCategory["Item"] = 0] = "Item";
4
+ ItemDropCategory[ItemDropCategory["ExpandedFolder"] = 1] = "ExpandedFolder";
5
+ ItemDropCategory[ItemDropCategory["LastInGroup"] = 2] = "LastInGroup";
6
+ })(ItemDropCategory || (ItemDropCategory = {}));
7
+ var PlacementType;
8
+ (function (PlacementType) {
9
+ PlacementType[PlacementType["ReorderAbove"] = 0] = "ReorderAbove";
10
+ PlacementType[PlacementType["ReorderBelow"] = 1] = "ReorderBelow";
11
+ PlacementType[PlacementType["MakeChild"] = 2] = "MakeChild";
12
+ PlacementType[PlacementType["Reparent"] = 3] = "Reparent";
13
+ })(PlacementType || (PlacementType = {}));
8
14
  export const canDrop = (dataTransfer, target, tree) => {
9
15
  var _a, _b, _c, _d;
10
16
  const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
@@ -12,6 +18,11 @@ export const canDrop = (dataTransfer, target, tree) => {
12
18
  if (draggedItems && !((_c = (_b = config.canDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target)) !== null && _c !== void 0 ? _c : true)) {
13
19
  return false;
14
20
  }
21
+ if (draggedItems &&
22
+ draggedItems.some((draggedItem) => target.item.getId() === draggedItem.getId() ||
23
+ target.item.isDescendentOf(draggedItem.getId()))) {
24
+ return false;
25
+ }
15
26
  if (!draggedItems &&
16
27
  dataTransfer &&
17
28
  !((_d = config.canDropForeignDragObject) === null || _d === void 0 ? void 0 : _d.call(config, dataTransfer, target))) {
@@ -19,52 +30,145 @@ export const canDrop = (dataTransfer, target, tree) => {
19
30
  }
20
31
  return true;
21
32
  };
22
- const getDropTargetPosition = (offset, topLinePercentage, bottomLinePercentage) => {
23
- if (offset < topLinePercentage) {
24
- return DropTargetPosition.Top;
33
+ const getItemDropCategory = (item) => {
34
+ if (item.isExpanded()) {
35
+ return ItemDropCategory.ExpandedFolder;
25
36
  }
26
- if (offset > bottomLinePercentage) {
27
- return DropTargetPosition.Bottom;
37
+ const parent = item.getParent();
38
+ if (parent && item.getIndexInParent() === parent.getItemMeta().setSize - 1) {
39
+ return ItemDropCategory.LastInGroup;
28
40
  }
29
- return DropTargetPosition.Item;
41
+ return ItemDropCategory.Item;
30
42
  };
31
- export const getDropTarget = (e, item, tree, canDropInbetween = tree.getConfig().canDropInbetween) => {
32
- var _a, _b, _c, _d;
43
+ const getTargetPlacement = (e, item, tree, canMakeChild) => {
44
+ var _a, _b, _c;
33
45
  const config = tree.getConfig();
46
+ if (!config.canReorder) {
47
+ return canMakeChild
48
+ ? { type: PlacementType.MakeChild }
49
+ : { type: PlacementType.ReorderBelow };
50
+ }
51
+ const bb = (_a = item.getElement()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
52
+ const topPercent = bb ? (e.pageY - bb.top) / bb.height : 0.5;
53
+ const leftPixels = bb ? e.pageX - bb.left : 0;
54
+ const targetDropCategory = getItemDropCategory(item);
55
+ const reorderAreaPercentage = !canMakeChild
56
+ ? 0.5
57
+ : (_b = config.reorderAreaPercentage) !== null && _b !== void 0 ? _b : 0.3;
58
+ const indent = (_c = config.indent) !== null && _c !== void 0 ? _c : 20;
59
+ const makeChildType = canMakeChild
60
+ ? PlacementType.MakeChild
61
+ : PlacementType.ReorderBelow;
62
+ if (targetDropCategory === ItemDropCategory.ExpandedFolder) {
63
+ if (topPercent < reorderAreaPercentage) {
64
+ return { type: PlacementType.ReorderAbove };
65
+ }
66
+ return { type: makeChildType };
67
+ }
68
+ if (targetDropCategory === ItemDropCategory.LastInGroup) {
69
+ if (leftPixels < item.getItemMeta().level * indent) {
70
+ if (topPercent < 0.5) {
71
+ return { type: PlacementType.ReorderAbove };
72
+ }
73
+ return {
74
+ type: PlacementType.Reparent,
75
+ reparentLevel: Math.floor(leftPixels / indent),
76
+ };
77
+ }
78
+ // if not at left of item area, treat as if it was a normal item
79
+ }
80
+ // targetDropCategory === ItemDropCategory.Item
81
+ if (topPercent < reorderAreaPercentage) {
82
+ return { type: PlacementType.ReorderAbove };
83
+ }
84
+ if (topPercent > 1 - reorderAreaPercentage) {
85
+ return { type: PlacementType.ReorderBelow };
86
+ }
87
+ return { type: makeChildType };
88
+ };
89
+ export const getDragCode = (e, item, tree) => {
90
+ const placement = getTargetPlacement(e, item, tree, true);
91
+ return [
92
+ item.getId(),
93
+ placement.type,
94
+ placement.type === PlacementType.Reparent ? placement.reparentLevel : 0,
95
+ ].join("__");
96
+ };
97
+ const getNthParent = (item, n) => {
98
+ if (n === item.getItemMeta().level) {
99
+ return item;
100
+ }
101
+ return getNthParent(item.getParent(), n);
102
+ };
103
+ export const getDropTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) => {
104
+ var _a, _b, _c;
34
105
  const draggedItems = (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) !== null && _b !== void 0 ? _b : [];
35
- const itemTarget = { item, childIndex: null, insertionIndex: null };
36
- const parentTarget = {
37
- item: item.getParent(),
106
+ const itemMeta = item.getItemMeta();
107
+ const parent = item.getParent();
108
+ const itemTarget = {
109
+ item,
38
110
  childIndex: null,
39
111
  insertionIndex: null,
112
+ dragLineIndex: null,
113
+ dragLineLevel: null,
40
114
  };
41
- if (!canDropInbetween) {
42
- if (!canDrop(e.dataTransfer, parentTarget, tree)) {
43
- return getDropTarget(e, item.getParent(), tree, false);
115
+ const parentTarget = parent
116
+ ? {
117
+ item: parent,
118
+ childIndex: null,
119
+ insertionIndex: null,
120
+ dragLineIndex: null,
121
+ dragLineLevel: null,
44
122
  }
123
+ : null;
124
+ const canBecomeSibling = parentTarget && canDrop(e.dataTransfer, parentTarget, tree);
125
+ const canMakeChild = canDrop(e.dataTransfer, itemTarget, tree);
126
+ const placement = getTargetPlacement(e, item, tree, canMakeChild);
127
+ if (!canReorder &&
128
+ parent &&
129
+ canBecomeSibling &&
130
+ placement.type !== PlacementType.MakeChild) {
131
+ return parentTarget;
132
+ }
133
+ if (!canReorder && parent && !canBecomeSibling) {
134
+ // TODO! this breaks in story DND/Can Drop. Maybe move this logic into a composable DropTargetStrategy[] ?
135
+ return getDropTarget(e, parent, tree, false);
136
+ }
137
+ if (!parent) {
138
+ // Shouldn't happen, but if dropped "next" to root item, just drop it inside
45
139
  return itemTarget;
46
140
  }
47
- const canDropInside = canDrop(e.dataTransfer, itemTarget, tree);
48
- const offset = getDropOffset(e, item);
49
- const pos = canDropInside
50
- ? getDropTargetPosition(offset, (_c = config.topLinePercentage) !== null && _c !== void 0 ? _c : 0.3, (_d = config.bottomLinePercentage) !== null && _d !== void 0 ? _d : 0.7)
51
- : getDropTargetPosition(offset, 0.5, 0.5);
52
- if (pos === DropTargetPosition.Item) {
141
+ if (placement.type === PlacementType.MakeChild) {
53
142
  return itemTarget;
54
143
  }
55
- if (!canDrop(e.dataTransfer, parentTarget, tree)) {
56
- return getDropTarget(e, item.getParent(), tree, false);
144
+ if (!canBecomeSibling) {
145
+ return getDropTarget(e, parent, tree, false);
146
+ }
147
+ if (placement.type === PlacementType.Reparent) {
148
+ const reparentedTarget = getNthParent(item, placement.reparentLevel - 1);
149
+ const targetItemAbove = getNthParent(item, placement.reparentLevel); // .getItemBelow()!;
150
+ const targetIndex = targetItemAbove.getIndexInParent() + 1;
151
+ // TODO possibly count items dragged out above the new target
152
+ return {
153
+ item: reparentedTarget,
154
+ childIndex: targetIndex,
155
+ insertionIndex: targetIndex,
156
+ dragLineIndex: itemMeta.index + 1,
157
+ dragLineLevel: placement.reparentLevel,
158
+ };
57
159
  }
58
- const childIndex = item.getIndexInParent() + (pos === DropTargetPosition.Top ? 0 : 1);
59
- const numberOfDragItemsBeforeTarget = item
60
- .getParent()
160
+ const maybeAddOneForBelow = placement.type === PlacementType.ReorderAbove ? 0 : 1;
161
+ const childIndex = item.getIndexInParent() + maybeAddOneForBelow;
162
+ const numberOfDragItemsBeforeTarget = (_c = parent
61
163
  .getChildren()
62
164
  .slice(0, childIndex)
63
165
  .reduce((counter, child) => child && (draggedItems === null || draggedItems === void 0 ? void 0 : draggedItems.some((i) => i.getId() === child.getId()))
64
166
  ? ++counter
65
- : counter, 0);
167
+ : counter, 0)) !== null && _c !== void 0 ? _c : 0;
66
168
  return {
67
- item: item.getParent(),
169
+ item: parent,
170
+ dragLineIndex: itemMeta.index + maybeAddOneForBelow,
171
+ dragLineLevel: itemMeta.level,
68
172
  childIndex,
69
173
  // TODO performance could be improved by computing this only when dragcode changed
70
174
  insertionIndex: childIndex - numberOfDragItemsBeforeTarget,
@@ -1,6 +1,2 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
- import { ExpandAllFeatureDef } from "./types";
3
- import { MainFeatureDef } from "../main/types";
4
- import { TreeFeatureDef } from "../tree/types";
5
- import { SyncDataLoaderFeatureDef } from "../sync-data-loader/types";
6
- export declare const expandAllFeature: FeatureImplementation<any, ExpandAllFeatureDef, MainFeatureDef | TreeFeatureDef<any> | SyncDataLoaderFeatureDef<any> | ExpandAllFeatureDef>;
2
+ export declare const expandAllFeature: FeatureImplementation;
@@ -10,13 +10,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { poll } from "../../utils";
11
11
  export const expandAllFeature = {
12
12
  key: "expand-all",
13
- createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { expandAll: (cancelToken) => __awaiter(void 0, void 0, void 0, function* () {
13
+ treeInstance: {
14
+ expandAll: (_a, cancelToken_1) => __awaiter(void 0, [_a, cancelToken_1], void 0, function* ({ tree }, cancelToken) {
14
15
  yield Promise.all(tree.getItems().map((item) => item.expandAll(cancelToken)));
15
- }), collapseAll: () => {
16
+ }),
17
+ collapseAll: ({ tree }) => {
16
18
  tree.applySubStateUpdate("expandedItems", []);
17
19
  tree.rebuildTree();
18
- } })),
19
- createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { expandAll: (cancelToken) => __awaiter(void 0, void 0, void 0, function* () {
20
+ },
21
+ },
22
+ itemInstance: {
23
+ expandAll: (_a, cancelToken_1) => __awaiter(void 0, [_a, cancelToken_1], void 0, function* ({ tree, item }, cancelToken) {
20
24
  if (cancelToken === null || cancelToken === void 0 ? void 0 : cancelToken.current) {
21
25
  return;
22
26
  }
@@ -29,10 +33,12 @@ export const expandAllFeature = {
29
33
  yield poll(() => !tree.getState().loadingItems.includes(child.getId()));
30
34
  yield (child === null || child === void 0 ? void 0 : child.expandAll(cancelToken));
31
35
  })));
32
- }), collapseAll: () => {
36
+ }),
37
+ collapseAll: ({ item }) => {
33
38
  for (const child of item.getChildren()) {
34
39
  child === null || child === void 0 ? void 0 : child.collapseAll();
35
40
  }
36
41
  item.collapse();
37
- } })),
42
+ },
43
+ },
38
44
  };
@@ -1,4 +1,2 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
- import { HotkeysCoreFeatureDef } from "./types";
3
- import { MainFeatureDef } from "../main/types";
4
- export declare const hotkeysCoreFeature: FeatureImplementation<any, HotkeysCoreFeatureDef<any>, MainFeatureDef | HotkeysCoreFeatureDef<any>>;
2
+ export declare const hotkeysCoreFeature: FeatureImplementation;
@@ -1,12 +1,18 @@
1
- import { FeatureImplementation, HotkeysConfig, ItemInstance, SetStateFn, TreeConfig, TreeState, Updater } from "../../types/core";
1
+ import { FeatureImplementation, HotkeysConfig, ItemInstance, SetStateFn, TreeConfig, TreeInstance, TreeState, Updater } from "../../types/core";
2
2
  import { ItemMeta } from "../tree/types";
3
+ export type InstanceTypeMap = {
4
+ itemInstance: ItemInstance<any>;
5
+ treeInstance: TreeInstance<any>;
6
+ };
7
+ export type InstanceBuilder = <T extends keyof InstanceTypeMap>(features: FeatureImplementation[], instanceType: T, buildOpts: (self: any) => any) => [instance: InstanceTypeMap[T], finalize: () => void];
3
8
  export type MainFeatureDef<T = any> = {
4
9
  state: {};
5
10
  config: {
6
11
  features?: FeatureImplementation<any>[];
7
12
  initialState?: Partial<TreeState<T>>;
8
13
  state?: Partial<TreeState<T>>;
9
- setState?: SetStateFn<TreeState<T>>;
14
+ setState?: SetStateFn<Partial<TreeState<T>>>;
15
+ instanceBuilder?: InstanceBuilder;
10
16
  };
11
17
  treeInstance: {
12
18
  /** @internal */
@@ -0,0 +1,2 @@
1
+ import { FeatureImplementation } from "../../types/core";
2
+ export declare const propMemoizationFeature: FeatureImplementation;
@@ -0,0 +1,45 @@
1
+ const memoize = (props, dataRef) => {
2
+ var _a;
3
+ (_a = dataRef.memoizedProps) !== null && _a !== void 0 ? _a : (dataRef.memoizedProps = {});
4
+ for (const key in props) {
5
+ if (typeof props[key] === "function") {
6
+ if (key in dataRef.memoizedProps) {
7
+ props[key] = dataRef.memoizedProps[key];
8
+ }
9
+ else {
10
+ dataRef.memoizedProps[key] = props[key];
11
+ }
12
+ }
13
+ }
14
+ return props;
15
+ };
16
+ export const propMemoizationFeature = {
17
+ key: "prop-memoization",
18
+ overwrites: [
19
+ "main",
20
+ "async-data-loader",
21
+ "sync-data-loader",
22
+ "drag-and-drop",
23
+ "expand-all",
24
+ "hotkeys-core",
25
+ "renaming",
26
+ "search",
27
+ "selection",
28
+ ],
29
+ treeInstance: {
30
+ getContainerProps: ({ tree, prev }) => {
31
+ var _a;
32
+ const dataRef = tree.getDataRef();
33
+ const props = (_a = prev === null || prev === void 0 ? void 0 : prev()) !== null && _a !== void 0 ? _a : {};
34
+ return memoize(props, dataRef.current);
35
+ },
36
+ },
37
+ itemInstance: {
38
+ getProps: ({ item, prev }) => {
39
+ var _a;
40
+ const dataRef = item.getDataRef();
41
+ const props = (_a = prev === null || prev === void 0 ? void 0 : prev()) !== null && _a !== void 0 ? _a : {};
42
+ return memoize(props, dataRef.current);
43
+ },
44
+ },
45
+ };
@@ -0,0 +1,10 @@
1
+ export type PropMemoizationDataRef = {
2
+ memoizedProps?: Record<string, any>;
3
+ };
4
+ export type PropMemoizationFeatureDef = {
5
+ state: {};
6
+ config: {};
7
+ treeInstance: {};
8
+ itemInstance: {};
9
+ hotkeys: never;
10
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,2 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
- import { RenamingFeatureDef } from "./types";
3
- import { MainFeatureDef } from "../main/types";
4
- import { TreeFeatureDef } from "../tree/types";
5
- export declare const renamingFeature: FeatureImplementation<any, RenamingFeatureDef<any>, MainFeatureDef | TreeFeatureDef<any> | RenamingFeatureDef<any>>;
2
+ export declare const renamingFeature: FeatureImplementation;
@@ -6,39 +6,53 @@ export const renamingFeature = {
6
6
  renamingItem: "setRenamingItem",
7
7
  renamingValue: "setRenamingValue",
8
8
  },
9
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { startRenamingItem: (itemId) => {
10
- const item = instance.getItemInstance(itemId);
11
- if (!item.canRename()) {
12
- return;
13
- }
14
- instance.applySubStateUpdate("renamingItem", itemId);
15
- instance.applySubStateUpdate("renamingValue", item.getItemName());
16
- }, getRenamingItem: () => {
17
- const itemId = instance.getState().renamingItem;
18
- return itemId ? instance.getItemInstance(itemId) : null;
19
- }, getRenamingValue: () => instance.getState().renamingValue || "", abortRenaming: () => {
20
- instance.applySubStateUpdate("renamingItem", null);
21
- }, completeRenaming: () => {
9
+ treeInstance: {
10
+ getRenamingItem: ({ tree }) => {
11
+ const itemId = tree.getState().renamingItem;
12
+ return itemId ? tree.getItemInstance(itemId) : null;
13
+ },
14
+ getRenamingValue: ({ tree }) => tree.getState().renamingValue || "",
15
+ abortRenaming: ({ tree }) => {
16
+ tree.applySubStateUpdate("renamingItem", null);
17
+ tree.updateDomFocus();
18
+ },
19
+ completeRenaming: ({ tree }) => {
22
20
  var _a;
23
- const config = instance.getConfig();
24
- const item = instance.getRenamingItem();
21
+ const config = tree.getConfig();
22
+ const item = tree.getRenamingItem();
25
23
  if (item) {
26
- (_a = config.onRename) === null || _a === void 0 ? void 0 : _a.call(config, item, instance.getState().renamingValue || "");
24
+ (_a = config.onRename) === null || _a === void 0 ? void 0 : _a.call(config, item, tree.getState().renamingValue || "");
25
+ }
26
+ tree.applySubStateUpdate("renamingItem", null);
27
+ tree.updateDomFocus();
28
+ },
29
+ isRenamingItem: ({ tree }) => !!tree.getState().renamingItem,
30
+ },
31
+ itemInstance: {
32
+ startRenaming: ({ tree, item, itemId }) => {
33
+ if (!item.canRename()) {
34
+ return;
27
35
  }
28
- instance.applySubStateUpdate("renamingItem", null);
29
- }, isRenamingItem: () => !!instance.getState().renamingItem })),
30
- createItemInstance: (prev, instance, tree) => (Object.assign(Object.assign({}, prev), { getRenameInputProps: () => ({
36
+ tree.applySubStateUpdate("renamingItem", itemId);
37
+ tree.applySubStateUpdate("renamingValue", item.getItemName());
38
+ },
39
+ getRenameInputProps: ({ tree }) => ({
31
40
  onBlur: () => tree.abortRenaming(),
32
41
  value: tree.getRenamingValue(),
33
42
  onChange: (e) => {
34
- tree.applySubStateUpdate("renamingValue", e.target.value);
43
+ var _a;
44
+ // TODO custom type with e.target.value
45
+ tree.applySubStateUpdate("renamingValue", (_a = e.target) === null || _a === void 0 ? void 0 : _a.value);
35
46
  },
36
- }), canRename: () => { var _a, _b, _c; return (_c = (_b = (_a = tree.getConfig()).canRename) === null || _b === void 0 ? void 0 : _b.call(_a, instance)) !== null && _c !== void 0 ? _c : true; }, isRenaming: () => instance.getId() === tree.getState().renamingItem })),
47
+ }),
48
+ canRename: ({ tree, item }) => { var _a, _b, _c; return (_c = (_b = (_a = tree.getConfig()).canRename) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true; },
49
+ isRenaming: ({ tree, item }) => item.getId() === tree.getState().renamingItem,
50
+ },
37
51
  hotkeys: {
38
52
  renameItem: {
39
53
  hotkey: "F2",
40
54
  handler: (e, tree) => {
41
- tree.startRenamingItem(tree.getFocusedItem().getId());
55
+ tree.getFocusedItem().startRenaming();
42
56
  },
43
57
  },
44
58
  abortRenaming: {
@@ -5,13 +5,12 @@ export type RenamingFeatureDef<T> = {
5
5
  renamingValue?: string;
6
6
  };
7
7
  config: {
8
- setRenamingItem?: SetStateFn<string | null>;
8
+ setRenamingItem?: SetStateFn<string | null | undefined>;
9
9
  setRenamingValue?: SetStateFn<string | undefined>;
10
10
  canRename?: (item: ItemInstance<T>) => boolean;
11
11
  onRename?: (item: ItemInstance<T>, value: string) => void;
12
12
  };
13
13
  treeInstance: {
14
- startRenamingItem: (itemId: string) => void;
15
14
  getRenamingItem: () => ItemInstance<T> | null;
16
15
  getRenamingValue: () => string;
17
16
  abortRenaming: () => void;
@@ -22,6 +21,7 @@ export type RenamingFeatureDef<T> = {
22
21
  getRenameInputProps: () => any;
23
22
  canRename: () => boolean;
24
23
  isRenaming: () => boolean;
24
+ startRenaming: () => void;
25
25
  };
26
26
  hotkeys: "renameItem" | "abortRenaming" | "completeRenaming";
27
27
  };
@@ -1,5 +1,2 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
- import { SearchFeatureDef } from "./types";
3
- import { MainFeatureDef } from "../main/types";
4
- import { TreeFeatureDef } from "../tree/types";
5
- export declare const searchFeature: FeatureImplementation<any, SearchFeatureDef<any>, MainFeatureDef | TreeFeatureDef<any> | SearchFeatureDef<any>>;
2
+ export declare const searchFeature: FeatureImplementation;
@@ -7,39 +7,53 @@ export const searchFeature = {
7
7
  stateHandlerNames: {
8
8
  search: "setSearch",
9
9
  },
10
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { setSearch: (search) => {
10
+ treeInstance: {
11
+ setSearch: ({ tree }, search) => {
11
12
  var _a;
12
- instance.applySubStateUpdate("search", search);
13
- (_a = instance
13
+ tree.applySubStateUpdate("search", search);
14
+ (_a = tree
14
15
  .getItems()
15
- .find((item) => {
16
- var _a, _b;
17
- return (_b = (_a = instance
18
- .getConfig()).isSearchMatchingItem) === null || _b === void 0 ? void 0 : _b.call(_a, instance.getSearchValue(), item);
19
- })) === null || _a === void 0 ? void 0 : _a.setFocused();
20
- }, openSearch: (initialValue = "") => {
21
- instance.setSearch(initialValue);
16
+ .find((item) => { var _a, _b; return (_b = (_a = tree.getConfig()).isSearchMatchingItem) === null || _b === void 0 ? void 0 : _b.call(_a, tree.getSearchValue(), item); })) === null || _a === void 0 ? void 0 : _a.setFocused();
17
+ },
18
+ openSearch: ({ tree }, initialValue = "") => {
19
+ var _a, _b;
20
+ tree.setSearch(initialValue);
21
+ (_b = (_a = tree.getConfig()).onOpenSearch) === null || _b === void 0 ? void 0 : _b.call(_a);
22
22
  setTimeout(() => {
23
23
  var _a;
24
- (_a = instance
25
- .getDataRef()
26
- .current.searchInput) === null || _a === void 0 ? void 0 : _a.focus();
24
+ (_a = tree.getDataRef().current.searchInput) === null || _a === void 0 ? void 0 : _a.focus();
27
25
  });
28
- }, closeSearch: () => {
29
- instance.setSearch(null);
30
- instance.updateDomFocus();
31
- }, isSearchOpen: () => instance.getState().search !== null, getSearchValue: () => instance.getState().search || "", registerSearchInputElement: (element) => {
32
- const dataRef = instance.getDataRef();
26
+ },
27
+ closeSearch: ({ tree }) => {
28
+ var _a, _b;
29
+ tree.setSearch(null);
30
+ (_b = (_a = tree.getConfig()).onCloseSearch) === null || _b === void 0 ? void 0 : _b.call(_a);
31
+ tree.updateDomFocus();
32
+ },
33
+ isSearchOpen: ({ tree }) => tree.getState().search !== null,
34
+ getSearchValue: ({ tree }) => tree.getState().search || "",
35
+ registerSearchInputElement: ({ tree }, element) => {
36
+ const dataRef = tree.getDataRef();
33
37
  dataRef.current.searchInput = element;
34
38
  if (element && dataRef.current.keydownHandler) {
35
39
  element.addEventListener("keydown", dataRef.current.keydownHandler);
36
40
  }
37
- }, getSearchInputElement: () => { var _a; return (_a = instance.getDataRef().current.searchInput) !== null && _a !== void 0 ? _a : null; }, getSearchInputElementProps: () => ({
38
- value: instance.getSearchValue(),
39
- onChange: (e) => instance.setSearch(e.target.value),
40
- onBlur: () => instance.closeSearch(),
41
- }), getSearchMatchingItems: memo((search, items) => items.filter((item) => { var _a, _b; return search && ((_b = (_a = instance.getConfig()).isSearchMatchingItem) === null || _b === void 0 ? void 0 : _b.call(_a, search, item)); }), () => [instance.getSearchValue(), instance.getItems()]) })),
42
- createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { isMatchingSearch: () => tree.getSearchMatchingItems().some((i) => i.getId() === item.getId()) })),
41
+ },
42
+ getSearchInputElement: ({ tree }) => { var _a; return (_a = tree.getDataRef().current.searchInput) !== null && _a !== void 0 ? _a : null; },
43
+ getSearchInputElementProps: ({ tree }) => ({
44
+ value: tree.getSearchValue(),
45
+ onChange: (e) => tree.setSearch(e.target.value),
46
+ onBlur: () => tree.closeSearch(),
47
+ }),
48
+ getSearchMatchingItems: memo(({ tree }) => [
49
+ tree.getSearchValue(),
50
+ tree.getItems(),
51
+ tree.getConfig().isSearchMatchingItem,
52
+ ], (search, items, isSearchMatchingItem) => items.filter((item) => search && (isSearchMatchingItem === null || isSearchMatchingItem === void 0 ? void 0 : isSearchMatchingItem(search, item)))),
53
+ },
54
+ itemInstance: {
55
+ isMatchingSearch: ({ tree, item }) => tree.getSearchMatchingItems().some((i) => i.getId() === item.getId()),
56
+ },
43
57
  hotkeys: {
44
58
  openSearch: {
45
59
  hotkey: "LetterOrNumber",
@@ -12,7 +12,6 @@ export type SearchFeatureDef<T> = {
12
12
  setSearch?: SetStateFn<string | null>;
13
13
  onOpenSearch?: () => void;
14
14
  onCloseSearch?: () => void;
15
- onSearchMatchesItems?: (search: string, items: ItemInstance<T>[]) => void;
16
15
  isSearchMatchingItem?: (search: string, item: ItemInstance<T>) => boolean;
17
16
  };
18
17
  treeInstance: {
@@ -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;