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