@headless-tree/core 0.0.10 → 0.0.11

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 (114) hide show
  1. package/CHANGELOG.md +6 -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 +27 -0
  6. package/lib/cjs/core/create-tree.js +55 -36
  7. package/lib/cjs/features/async-data-loader/feature.js +37 -23
  8. package/lib/cjs/features/async-data-loader/types.d.ts +2 -1
  9. package/lib/cjs/features/drag-and-drop/feature.js +64 -32
  10. package/lib/cjs/features/drag-and-drop/types.d.ts +13 -4
  11. package/lib/cjs/features/drag-and-drop/utils.d.ts +1 -2
  12. package/lib/cjs/features/drag-and-drop/utils.js +140 -37
  13. package/lib/cjs/features/expand-all/feature.js +12 -6
  14. package/lib/cjs/features/main/types.d.ts +8 -2
  15. package/lib/cjs/features/renaming/feature.js +33 -18
  16. package/lib/cjs/features/renaming/types.d.ts +1 -1
  17. package/lib/cjs/features/search/feature.js +38 -24
  18. package/lib/cjs/features/search/types.d.ts +0 -1
  19. package/lib/cjs/features/selection/feature.js +23 -14
  20. package/lib/cjs/features/sync-data-loader/feature.js +7 -2
  21. package/lib/cjs/features/tree/feature.d.ts +2 -1
  22. package/lib/cjs/features/tree/feature.js +85 -63
  23. package/lib/cjs/features/tree/types.d.ts +5 -3
  24. package/lib/cjs/index.d.ts +3 -1
  25. package/lib/cjs/index.js +2 -1
  26. package/lib/cjs/test-utils/test-tree-do.d.ts +23 -0
  27. package/lib/cjs/test-utils/test-tree-do.js +99 -0
  28. package/lib/cjs/test-utils/test-tree-expect.d.ts +15 -0
  29. package/lib/cjs/test-utils/test-tree-expect.js +62 -0
  30. package/lib/cjs/test-utils/test-tree.d.ts +47 -0
  31. package/lib/cjs/test-utils/test-tree.js +195 -0
  32. package/lib/cjs/types/core.d.ts +31 -15
  33. package/lib/cjs/utilities/errors.d.ts +1 -0
  34. package/lib/cjs/utilities/errors.js +5 -0
  35. package/lib/cjs/utilities/insert-items-at-target.js +10 -3
  36. package/lib/cjs/utilities/remove-items-from-parents.js +14 -8
  37. package/lib/cjs/utils.d.ts +3 -3
  38. package/lib/cjs/utils.js +6 -6
  39. package/lib/esm/core/build-proxified-instance.d.ts +2 -0
  40. package/lib/esm/core/build-proxified-instance.js +54 -0
  41. package/lib/esm/core/build-static-instance.d.ts +2 -0
  42. package/lib/esm/core/build-static-instance.js +23 -0
  43. package/lib/esm/core/create-tree.js +55 -36
  44. package/lib/esm/features/async-data-loader/feature.js +37 -23
  45. package/lib/esm/features/async-data-loader/types.d.ts +2 -1
  46. package/lib/esm/features/drag-and-drop/feature.js +64 -32
  47. package/lib/esm/features/drag-and-drop/types.d.ts +13 -4
  48. package/lib/esm/features/drag-and-drop/utils.d.ts +1 -2
  49. package/lib/esm/features/drag-and-drop/utils.js +138 -34
  50. package/lib/esm/features/expand-all/feature.js +12 -6
  51. package/lib/esm/features/main/types.d.ts +8 -2
  52. package/lib/esm/features/renaming/feature.js +33 -18
  53. package/lib/esm/features/renaming/types.d.ts +1 -1
  54. package/lib/esm/features/search/feature.js +38 -24
  55. package/lib/esm/features/search/types.d.ts +0 -1
  56. package/lib/esm/features/selection/feature.js +23 -14
  57. package/lib/esm/features/sync-data-loader/feature.js +7 -2
  58. package/lib/esm/features/tree/feature.d.ts +2 -1
  59. package/lib/esm/features/tree/feature.js +86 -64
  60. package/lib/esm/features/tree/types.d.ts +5 -3
  61. package/lib/esm/index.d.ts +3 -1
  62. package/lib/esm/index.js +2 -1
  63. package/lib/esm/test-utils/test-tree-do.d.ts +23 -0
  64. package/lib/esm/test-utils/test-tree-do.js +95 -0
  65. package/lib/esm/test-utils/test-tree-expect.d.ts +15 -0
  66. package/lib/esm/test-utils/test-tree-expect.js +58 -0
  67. package/lib/esm/test-utils/test-tree.d.ts +47 -0
  68. package/lib/esm/test-utils/test-tree.js +191 -0
  69. package/lib/esm/types/core.d.ts +31 -15
  70. package/lib/esm/utilities/errors.d.ts +1 -0
  71. package/lib/esm/utilities/errors.js +1 -0
  72. package/lib/esm/utilities/insert-items-at-target.js +10 -3
  73. package/lib/esm/utilities/remove-items-from-parents.js +14 -8
  74. package/lib/esm/utils.d.ts +3 -3
  75. package/lib/esm/utils.js +3 -3
  76. package/package.json +7 -3
  77. package/src/core/build-proxified-instance.ts +115 -0
  78. package/src/core/build-static-instance.ts +28 -0
  79. package/src/core/create-tree.ts +60 -62
  80. package/src/features/async-data-loader/async-data-loader.spec.ts +143 -0
  81. package/src/features/async-data-loader/feature.ts +33 -31
  82. package/src/features/async-data-loader/types.ts +3 -1
  83. package/src/features/drag-and-drop/drag-and-drop.spec.ts +716 -0
  84. package/src/features/drag-and-drop/feature.ts +109 -85
  85. package/src/features/drag-and-drop/types.ts +21 -7
  86. package/src/features/drag-and-drop/utils.ts +196 -55
  87. package/src/features/expand-all/expand-all.spec.ts +52 -0
  88. package/src/features/expand-all/feature.ts +8 -12
  89. package/src/features/hotkeys-core/feature.ts +1 -1
  90. package/src/features/main/types.ts +14 -1
  91. package/src/features/renaming/feature.ts +30 -29
  92. package/src/features/renaming/renaming.spec.ts +125 -0
  93. package/src/features/renaming/types.ts +1 -1
  94. package/src/features/search/feature.ts +34 -38
  95. package/src/features/search/search.spec.ts +115 -0
  96. package/src/features/search/types.ts +0 -1
  97. package/src/features/selection/feature.ts +29 -30
  98. package/src/features/selection/selection.spec.ts +220 -0
  99. package/src/features/sync-data-loader/feature.ts +8 -11
  100. package/src/features/tree/feature.ts +82 -87
  101. package/src/features/tree/tree.spec.ts +515 -0
  102. package/src/features/tree/types.ts +5 -3
  103. package/src/index.ts +4 -1
  104. package/src/test-utils/test-tree-do.ts +136 -0
  105. package/src/test-utils/test-tree-expect.ts +86 -0
  106. package/src/test-utils/test-tree.ts +217 -0
  107. package/src/types/core.ts +92 -33
  108. package/src/utilities/errors.ts +2 -0
  109. package/src/utilities/insert-items-at-target.ts +10 -3
  110. package/src/utilities/remove-items-from-parents.ts +15 -10
  111. package/src/utils.spec.ts +89 -0
  112. package/src/utils.ts +6 -6
  113. package/tsconfig.json +1 -0
  114. package/vitest.config.ts +6 -0
@@ -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.canDropInbetween) {
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, canDropInbetween = tree.getConfig().canDropInbetween) => {
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 (!canDropInbetween &&
133
+ parent &&
134
+ canBecomeSibling &&
135
+ placement.type !== PlacementType.MakeChild) {
136
+ return parentTarget;
137
+ }
138
+ if (!canDropInbetween && 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,
@@ -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,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 */
@@ -9,34 +9,49 @@ 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);
12
+ treeInstance: {
13
+ startRenamingItem: ({ tree }, itemId) => {
14
+ const item = tree.getItemInstance(itemId);
14
15
  if (!item.canRename()) {
15
16
  return;
16
17
  }
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: () => {
18
+ tree.applySubStateUpdate("renamingItem", itemId);
19
+ tree.applySubStateUpdate("renamingValue", item.getItemName());
20
+ },
21
+ getRenamingItem: ({ tree }) => {
22
+ const itemId = tree.getState().renamingItem;
23
+ return itemId ? tree.getItemInstance(itemId) : null;
24
+ },
25
+ getRenamingValue: ({ tree }) => tree.getState().renamingValue || "",
26
+ abortRenaming: ({ tree }) => {
27
+ tree.applySubStateUpdate("renamingItem", null);
28
+ tree.updateDomFocus();
29
+ },
30
+ completeRenaming: ({ tree }) => {
25
31
  var _a;
26
- const config = instance.getConfig();
27
- const item = instance.getRenamingItem();
32
+ const config = tree.getConfig();
33
+ const item = tree.getRenamingItem();
28
34
  if (item) {
29
- (_a = config.onRename) === null || _a === void 0 ? void 0 : _a.call(config, item, instance.getState().renamingValue || "");
35
+ (_a = config.onRename) === null || _a === void 0 ? void 0 : _a.call(config, item, tree.getState().renamingValue || "");
30
36
  }
31
- instance.applySubStateUpdate("renamingItem", null);
32
- }, isRenamingItem: () => !!instance.getState().renamingItem })),
33
- createItemInstance: (prev, instance, tree) => (Object.assign(Object.assign({}, prev), { getRenameInputProps: () => ({
37
+ tree.applySubStateUpdate("renamingItem", null);
38
+ tree.updateDomFocus();
39
+ },
40
+ isRenamingItem: ({ tree }) => !!tree.getState().renamingItem,
41
+ },
42
+ itemInstance: {
43
+ getRenameInputProps: ({ tree }) => ({
34
44
  onBlur: () => tree.abortRenaming(),
35
45
  value: tree.getRenamingValue(),
36
46
  onChange: (e) => {
37
- tree.applySubStateUpdate("renamingValue", e.target.value);
47
+ var _a;
48
+ // TODO custom type with e.target.value
49
+ tree.applySubStateUpdate("renamingValue", (_a = e.target) === null || _a === void 0 ? void 0 : _a.value);
38
50
  },
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 })),
51
+ }),
52
+ 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; },
53
+ isRenaming: ({ tree, item }) => item.getId() === tree.getState().renamingItem,
54
+ },
40
55
  hotkeys: {
41
56
  renameItem: {
42
57
  hotkey: "F2",
@@ -5,7 +5,7 @@ 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;
@@ -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: {
@@ -9,25 +9,31 @@ exports.selectionFeature = {
9
9
  stateHandlerNames: {
10
10
  selectedItems: "setSelectedItems",
11
11
  },
12
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { setSelectedItems: (selectedItems) => {
13
- instance.applySubStateUpdate("selectedItems", selectedItems);
14
- },
12
+ treeInstance: {
13
+ setSelectedItems: ({ tree }, selectedItems) => {
14
+ tree.applySubStateUpdate("selectedItems", selectedItems);
15
+ },
15
16
  // TODO memo
16
- getSelectedItems: () => {
17
- return instance.getState().selectedItems.map(instance.getItemInstance);
18
- } })),
19
- createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { select: () => {
17
+ getSelectedItems: ({ tree }) => {
18
+ return tree.getState().selectedItems.map(tree.getItemInstance);
19
+ },
20
+ },
21
+ itemInstance: {
22
+ select: ({ tree, item }) => {
20
23
  const { selectedItems } = tree.getState();
21
24
  tree.setSelectedItems(selectedItems.includes(item.getItemMeta().itemId)
22
25
  ? selectedItems
23
26
  : [...selectedItems, item.getItemMeta().itemId]);
24
- }, deselect: () => {
27
+ },
28
+ deselect: ({ tree, item }) => {
25
29
  const { selectedItems } = tree.getState();
26
30
  tree.setSelectedItems(selectedItems.filter((id) => id !== item.getItemMeta().itemId));
27
- }, isSelected: () => {
31
+ },
32
+ isSelected: ({ tree, item }) => {
28
33
  const { selectedItems } = tree.getState();
29
34
  return selectedItems.includes(item.getItemMeta().itemId);
30
- }, selectUpTo: (ctrl) => {
35
+ },
36
+ selectUpTo: ({ tree, item }, ctrl) => {
31
37
  const indexA = item.getItemMeta().index;
32
38
  // TODO dont use focused item as anchor, but last primary-clicked item
33
39
  const indexB = tree.getFocusedItem().getItemMeta().index;
@@ -45,14 +51,16 @@ exports.selectionFeature = {
45
51
  ...new Set([...selectedItems, ...newSelectedItems]),
46
52
  ];
47
53
  tree.setSelectedItems(uniqueSelectedItems);
48
- }, toggleSelect: () => {
54
+ },
55
+ toggleSelect: ({ item }) => {
49
56
  if (item.isSelected()) {
50
57
  item.deselect();
51
58
  }
52
59
  else {
53
60
  item.select();
54
61
  }
55
- }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { "aria-selected": item.isSelected() ? "true" : "false", onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
62
+ },
63
+ getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { "aria-selected": item.isSelected() ? "true" : "false", onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
56
64
  var _a, _b;
57
65
  if (e.shiftKey) {
58
66
  item.selectUpTo(e.ctrlKey || e.metaKey);
@@ -63,8 +71,9 @@ exports.selectionFeature = {
63
71
  else {
64
72
  tree.setSelectedItems([item.getItemMeta().itemId]);
65
73
  }
66
- (_b = (_a = prev.getProps()).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
67
- }) })) })),
74
+ (_b = (_a = prev === null || prev === void 0 ? void 0 : prev()) === null || _a === void 0 ? void 0 : _a.onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
75
+ }) })),
76
+ },
68
77
  hotkeys: {
69
78
  // setSelectedItem: {
70
79
  // hotkey: "space",
@@ -9,6 +9,11 @@ exports.syncDataLoaderFeature = {
9
9
  stateHandlerNames: {
10
10
  loadingItems: "setLoadingItems",
11
11
  },
12
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: (itemId) => instance.getConfig().dataLoader.getItem(itemId), retrieveChildrenIds: (itemId) => instance.getConfig().dataLoader.getChildren(itemId) })),
13
- createItemInstance: (prev) => (Object.assign(Object.assign({}, prev), { isLoading: () => false })),
12
+ treeInstance: {
13
+ retrieveItemData: ({ tree }, itemId) => tree.getConfig().dataLoader.getItem(itemId),
14
+ retrieveChildrenIds: ({ tree }, itemId) => tree.getConfig().dataLoader.getChildren(itemId),
15
+ },
16
+ itemInstance: {
17
+ isLoading: () => false,
18
+ },
14
19
  };
@@ -3,4 +3,5 @@ import { TreeFeatureDef } from "./types";
3
3
  import { MainFeatureDef } from "../main/types";
4
4
  import { HotkeysCoreFeatureDef } from "../hotkeys-core/types";
5
5
  import { SyncDataLoaderFeatureDef } from "../sync-data-loader/types";
6
- export declare const treeFeature: FeatureImplementation<any, TreeFeatureDef<any>, MainFeatureDef | TreeFeatureDef<any> | HotkeysCoreFeatureDef<any> | SyncDataLoaderFeatureDef<any>>;
6
+ import { SearchFeatureDef } from "../search/types";
7
+ export declare const treeFeature: FeatureImplementation<any, TreeFeatureDef<any>, MainFeatureDef | TreeFeatureDef<any> | HotkeysCoreFeatureDef<any> | SyncDataLoaderFeatureDef<any> | SearchFeatureDef<any>>;