@headless-tree/core 0.0.0-20250322153940 → 0.0.0-20250330164609

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 (52) hide show
  1. package/CHANGELOG.md +2 -1
  2. package/lib/cjs/features/drag-and-drop/feature.js +11 -11
  3. package/lib/cjs/features/drag-and-drop/types.d.ts +11 -11
  4. package/lib/cjs/features/drag-and-drop/types.js +7 -7
  5. package/lib/cjs/features/drag-and-drop/utils.d.ts +18 -3
  6. package/lib/cjs/features/drag-and-drop/utils.js +42 -30
  7. package/lib/cjs/features/hotkeys-core/feature.js +1 -0
  8. package/lib/cjs/features/keyboard-drag-and-drop/feature.d.ts +2 -0
  9. package/lib/cjs/features/keyboard-drag-and-drop/feature.js +207 -0
  10. package/lib/cjs/features/keyboard-drag-and-drop/types.d.ts +27 -0
  11. package/lib/cjs/features/keyboard-drag-and-drop/types.js +11 -0
  12. package/lib/cjs/index.d.ts +2 -0
  13. package/lib/cjs/index.js +2 -0
  14. package/lib/cjs/mddocs-entry.d.ts +10 -0
  15. package/lib/cjs/test-utils/test-tree-expect.d.ts +5 -3
  16. package/lib/cjs/test-utils/test-tree-expect.js +3 -0
  17. package/lib/cjs/types/core.d.ts +2 -1
  18. package/lib/cjs/utilities/create-on-drop-handler.d.ts +2 -2
  19. package/lib/cjs/utilities/insert-items-at-target.d.ts +2 -2
  20. package/lib/esm/features/drag-and-drop/feature.js +12 -12
  21. package/lib/esm/features/drag-and-drop/types.d.ts +11 -11
  22. package/lib/esm/features/drag-and-drop/types.js +6 -6
  23. package/lib/esm/features/drag-and-drop/utils.d.ts +18 -3
  24. package/lib/esm/features/drag-and-drop/utils.js +37 -28
  25. package/lib/esm/features/hotkeys-core/feature.js +1 -0
  26. package/lib/esm/features/keyboard-drag-and-drop/feature.d.ts +2 -0
  27. package/lib/esm/features/keyboard-drag-and-drop/feature.js +204 -0
  28. package/lib/esm/features/keyboard-drag-and-drop/types.d.ts +27 -0
  29. package/lib/esm/features/keyboard-drag-and-drop/types.js +8 -0
  30. package/lib/esm/index.d.ts +2 -0
  31. package/lib/esm/index.js +2 -0
  32. package/lib/esm/mddocs-entry.d.ts +10 -0
  33. package/lib/esm/test-utils/test-tree-expect.d.ts +5 -3
  34. package/lib/esm/test-utils/test-tree-expect.js +3 -0
  35. package/lib/esm/types/core.d.ts +2 -1
  36. package/lib/esm/utilities/create-on-drop-handler.d.ts +2 -2
  37. package/lib/esm/utilities/insert-items-at-target.d.ts +2 -2
  38. package/package.json +1 -1
  39. package/src/features/drag-and-drop/drag-and-drop.spec.ts +6 -6
  40. package/src/features/drag-and-drop/feature.ts +12 -12
  41. package/src/features/drag-and-drop/types.ts +11 -11
  42. package/src/features/drag-and-drop/utils.ts +64 -39
  43. package/src/features/hotkeys-core/feature.ts +1 -0
  44. package/src/features/keyboard-drag-and-drop/feature.ts +255 -0
  45. package/src/features/keyboard-drag-and-drop/keyboard-drag-and-drop.spec.ts +401 -0
  46. package/src/features/keyboard-drag-and-drop/types.ts +30 -0
  47. package/src/index.ts +2 -0
  48. package/src/mddocs-entry.ts +16 -0
  49. package/src/test-utils/test-tree-expect.ts +7 -2
  50. package/src/types/core.ts +2 -0
  51. package/src/utilities/create-on-drop-handler.ts +2 -2
  52. package/src/utilities/insert-items-at-target.ts +2 -2
package/lib/esm/index.js CHANGED
@@ -2,6 +2,7 @@ export * from "./types/core";
2
2
  export * from "./core/create-tree";
3
3
  export * from "./features/tree/types";
4
4
  export * from "./features/drag-and-drop/types";
5
+ export * from "./features/keyboard-drag-and-drop/types";
5
6
  export * from "./features/selection/types";
6
7
  export * from "./features/async-data-loader/types";
7
8
  export * from "./features/sync-data-loader/types";
@@ -15,6 +16,7 @@ export * from "./features/hotkeys-core/feature";
15
16
  export * from "./features/async-data-loader/feature";
16
17
  export * from "./features/sync-data-loader/feature";
17
18
  export * from "./features/drag-and-drop/feature";
19
+ export * from "./features/keyboard-drag-and-drop/feature";
18
20
  export * from "./features/search/feature";
19
21
  export * from "./features/renaming/feature";
20
22
  export * from "./features/expand-all/feature";
@@ -9,6 +9,7 @@ import { SelectionFeatureDef } from "./features/selection/types";
9
9
  import { SyncDataLoaderFeatureDef } from "./features/sync-data-loader/types";
10
10
  import { TreeFeatureDef } from "./features/tree/types";
11
11
  import { PropMemoizationFeatureDef } from "./features/prop-memoization/types";
12
+ import { KeyboardDragAndDropFeatureDef } from "./features/keyboard-drag-and-drop/types";
12
13
  export * from ".";
13
14
  /** @interface */
14
15
  export type AsyncDataLoaderFeatureConfig<T> = AsyncDataLoaderFeatureDef<T>["config"];
@@ -29,6 +30,15 @@ export type DragAndDropFeatureTreeInstance<T> = DragAndDropFeatureDef<T>["treeIn
29
30
  export type DragAndDropFeatureItemInstance<T> = DragAndDropFeatureDef<T>["itemInstance"];
30
31
  export type DragAndDropFeatureHotkeys<T> = DragAndDropFeatureDef<T>["hotkeys"];
31
32
  /** @interface */
33
+ export type KeyboardDragAndDropFeatureConfig<T> = KeyboardDragAndDropFeatureDef<T>["config"];
34
+ /** @interface */
35
+ export type KeyboardDragAndDropFeatureState<T> = KeyboardDragAndDropFeatureDef<T>["state"];
36
+ /** @interface */
37
+ export type KeyboardDragAndDropFeatureTreeInstance<T> = KeyboardDragAndDropFeatureDef<T>["treeInstance"];
38
+ /** @interface */
39
+ export type KeyboardDragAndDropFeatureItemInstance<T> = KeyboardDragAndDropFeatureDef<T>["itemInstance"];
40
+ export type KeyboardDragAndDropFeatureHotkeys<T> = KeyboardDragAndDropFeatureDef<T>["hotkeys"];
41
+ /** @interface */
32
42
  export type ExpandAllFeatureConfig = ExpandAllFeatureDef["config"];
33
43
  /** @interface */
34
44
  export type ExpandAllFeatureState = ExpandAllFeatureDef["state"];
@@ -1,15 +1,17 @@
1
1
  import { DragEvent } from "react";
2
2
  import { TestTree } from "./test-tree";
3
- import { DropTarget } from "../features/drag-and-drop/types";
3
+ import { DragTarget } from "../features/drag-and-drop/types";
4
+ import { TreeState } from "../types/core";
4
5
  export declare class TestTreeExpect<T> {
5
6
  private tree;
6
- protected itemInstance(itemId: string): import("..").ItemInstance<T>;
7
+ protected itemInstance(itemId: string): import("../types/core").ItemInstance<T>;
7
8
  protected itemProps(itemId: string): Record<string, any>;
8
9
  constructor(tree: TestTree<T>);
9
10
  foldersExpanded(...itemIds: string[]): void;
10
11
  foldersCollapsed(...itemIds: string[]): void;
11
12
  hasChildren(itemId: string, children: string[]): void;
12
- dropped(draggedItems: string[], target: DropTarget<any>): void;
13
+ substate<K extends keyof TreeState<T>>(key: K, value: TreeState<T>[K]): void;
14
+ dropped(draggedItems: string[], target: DragTarget<any>): void;
13
15
  dragOverNotAllowed(itemId: string, event?: DragEvent): DragEvent<Element>;
14
16
  defaultDragLineProps(indent?: number): void;
15
17
  }
@@ -26,6 +26,9 @@ export class TestTreeExpect {
26
26
  const itemChildren = item.getChildren().map((child) => child.getId());
27
27
  expect(itemChildren).toEqual(children);
28
28
  }
29
+ substate(key, value) {
30
+ expect(this.tree.instance.getState()[key]).toEqual(value);
31
+ }
29
32
  dropped(draggedItems, target) {
30
33
  expect(this.tree.instance.getConfig().onDrop).toBeCalledWith(draggedItems.map((id) => this.tree.item(id)), target);
31
34
  }
@@ -9,6 +9,7 @@ import { SearchFeatureDef } from "../features/search/types";
9
9
  import { RenamingFeatureDef } from "../features/renaming/types";
10
10
  import { ExpandAllFeatureDef } from "../features/expand-all/types";
11
11
  import { PropMemoizationFeatureDef } from "../features/prop-memoization/types";
12
+ import { KeyboardDragAndDropFeatureDef } from "../features/keyboard-drag-and-drop/types";
12
13
  export type Updater<T> = T | ((old: T) => T);
13
14
  export type SetStateFn<T> = (updaterOrValue: Updater<T>) => void;
14
15
  export type FeatureDef = {
@@ -33,7 +34,7 @@ type MergedFeatures<F extends FeatureDef> = {
33
34
  itemInstance: UnionToIntersection<F["itemInstance"]>;
34
35
  hotkeys: F["hotkeys"];
35
36
  };
36
- export type RegisteredFeatures<T> = MainFeatureDef<T> | TreeFeatureDef<T> | SelectionFeatureDef<T> | DragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef | PropMemoizationFeatureDef;
37
+ export type RegisteredFeatures<T> = MainFeatureDef<T> | TreeFeatureDef<T> | SelectionFeatureDef<T> | DragAndDropFeatureDef<T> | KeyboardDragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef | PropMemoizationFeatureDef;
37
38
  type TreeStateType<T> = MergedFeatures<RegisteredFeatures<T>>["state"];
38
39
  export interface TreeState<T> extends TreeStateType<T> {
39
40
  }
@@ -1,3 +1,3 @@
1
1
  import { ItemInstance } from "../types/core";
2
- import { DropTarget } from "../features/drag-and-drop/types";
3
- export declare const createOnDropHandler: <T>(onChangeChildren: (item: ItemInstance<T>, newChildren: string[]) => void) => (items: ItemInstance<T>[], target: DropTarget<T>) => Promise<void>;
2
+ import { DragTarget } from "../features/drag-and-drop/types";
3
+ export declare const createOnDropHandler: <T>(onChangeChildren: (item: ItemInstance<T>, newChildren: string[]) => void) => (items: ItemInstance<T>[], target: DragTarget<T>) => Promise<void>;
@@ -1,3 +1,3 @@
1
1
  import { ItemInstance } from "../types/core";
2
- import { DropTarget } from "../features/drag-and-drop/types";
3
- export declare const insertItemsAtTarget: <T>(itemIds: string[], target: DropTarget<T>, onChangeChildren: (item: ItemInstance<T>, newChildrenIds: string[]) => Promise<void> | void) => Promise<void>;
2
+ import { DragTarget } from "../features/drag-and-drop/types";
3
+ export declare const insertItemsAtTarget: <T>(itemIds: string[], target: DragTarget<T>, onChangeChildren: (item: ItemInstance<T>, newChildrenIds: string[]) => Promise<void> | void) => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@headless-tree/core",
3
- "version": "0.0.0-20250322153940",
3
+ "version": "0.0.0-20250330164609",
4
4
  "type": "module",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/esm/index.js",
@@ -648,20 +648,20 @@ describe("core-feature/drag-and-drop", () => {
648
648
  });
649
649
 
650
650
  describe("item instance methods", () => {
651
- it("returns isDropTarget() correct for folders", () => {
651
+ it("returns isDragTarget() correct for folders", () => {
652
652
  tree.do.startDrag("x111");
653
653
  tree.do.dragOver("x21");
654
- expect(tree.instance.getItemInstance("x21").isDropTarget()).toBe(true);
655
- expect(tree.instance.getItemInstance("x211").isDropTarget()).toBe(
654
+ expect(tree.instance.getItemInstance("x21").isDragTarget()).toBe(true);
655
+ expect(tree.instance.getItemInstance("x211").isDragTarget()).toBe(
656
656
  false,
657
657
  );
658
658
  });
659
659
 
660
- it("returns isDropTarget() correct for items", () => {
660
+ it("returns isDragTarget() correct for items", () => {
661
661
  tree.do.startDrag("x111");
662
662
  tree.do.dragOver("x211");
663
- expect(tree.instance.getItemInstance("x21").isDropTarget()).toBe(true);
664
- expect(tree.instance.getItemInstance("x211").isDropTarget()).toBe(
663
+ expect(tree.instance.getItemInstance("x21").isDragTarget()).toBe(true);
664
+ expect(tree.instance.getItemInstance("x211").isDragTarget()).toBe(
665
665
  false,
666
666
  );
667
667
  });
@@ -1,6 +1,6 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
2
  import { DndDataRef, DragLineData } from "./types";
3
- import { canDrop, getDragCode, getDropTarget } from "./utils";
3
+ import { canDrop, getDragCode, getDragTarget } from "./utils";
4
4
  import { makeStateUpdater } from "../../utils";
5
5
 
6
6
  export const dragAndDropFeature: FeatureImplementation = {
@@ -20,12 +20,12 @@ export const dragAndDropFeature: FeatureImplementation = {
20
20
  },
21
21
 
22
22
  treeInstance: {
23
- getDropTarget: ({ tree }) => {
23
+ getDragTarget: ({ tree }) => {
24
24
  return tree.getState().dnd?.dragTarget ?? null;
25
25
  },
26
26
 
27
27
  getDragLineData: ({ tree }): DragLineData | null => {
28
- const target = tree.getDropTarget();
28
+ const target = tree.getDragTarget();
29
29
  const indent = (target?.item.getItemMeta().level ?? 0) + 1;
30
30
 
31
31
  const treeBb = tree.getElement()?.getBoundingClientRect();
@@ -44,7 +44,7 @@ export const dragAndDropFeature: FeatureImplementation = {
44
44
  if (bb) {
45
45
  return {
46
46
  indent,
47
- top: bb.bottom - treeBb.bottom,
47
+ top: bb.bottom - treeBb.top,
48
48
  left: bb.left + leftOffset - treeBb.left,
49
49
  width: bb.width - leftOffset,
50
50
  };
@@ -131,7 +131,7 @@ export const dragAndDropFeature: FeatureImplementation = {
131
131
  }
132
132
  dataRef.current.lastDragCode = nextDragCode;
133
133
 
134
- const target = getDropTarget(e, item, tree);
134
+ const target = getDragTarget(e, item, tree);
135
135
 
136
136
  if (
137
137
  !tree.getState().dnd?.draggedItems &&
@@ -181,7 +181,7 @@ export const dragAndDropFeature: FeatureImplementation = {
181
181
 
182
182
  onDrop: async (e: DragEvent) => {
183
183
  const dataRef = tree.getDataRef<DndDataRef>();
184
- const target = getDropTarget(e, item, tree);
184
+ const target = getDragTarget(e, item, tree);
185
185
 
186
186
  if (!canDrop(e.dataTransfer, target, tree)) {
187
187
  return;
@@ -202,13 +202,13 @@ export const dragAndDropFeature: FeatureImplementation = {
202
202
  },
203
203
  }),
204
204
 
205
- isDropTarget: ({ tree, item }) => {
206
- const target = tree.getDropTarget();
205
+ isDragTarget: ({ tree, item }) => {
206
+ const target = tree.getDragTarget();
207
207
  return target ? target.item.getId() === item.getId() : false;
208
208
  },
209
209
 
210
- isDropTargetAbove: ({ tree, item }) => {
211
- const target = tree.getDropTarget();
210
+ isDragTargetAbove: ({ tree, item }) => {
211
+ const target = tree.getDragTarget();
212
212
 
213
213
  if (
214
214
  !target ||
@@ -219,8 +219,8 @@ export const dragAndDropFeature: FeatureImplementation = {
219
219
  return target.childIndex === item.getItemMeta().posInSet;
220
220
  },
221
221
 
222
- isDropTargetBelow: ({ tree, item }) => {
223
- const target = tree.getDropTarget();
222
+ isDragTargetBelow: ({ tree, item }) => {
223
+ const target = tree.getDragTarget();
224
224
 
225
225
  if (
226
226
  !target ||
@@ -8,7 +8,7 @@ export interface DndDataRef {
8
8
  export interface DndState<T> {
9
9
  draggedItems?: ItemInstance<T>[];
10
10
  draggingOverItem?: ItemInstance<T>;
11
- dragTarget?: DropTarget<T>;
11
+ dragTarget?: DragTarget<T>;
12
12
  }
13
13
 
14
14
  export interface DragLineData {
@@ -18,7 +18,7 @@ export interface DragLineData {
18
18
  width: number;
19
19
  }
20
20
 
21
- export type DropTarget<T> =
21
+ export type DragTarget<T> =
22
22
  | {
23
23
  item: ItemInstance<T>;
24
24
  childIndex: number;
@@ -30,7 +30,7 @@ export type DropTarget<T> =
30
30
  item: ItemInstance<T>;
31
31
  };
32
32
 
33
- export enum DropTargetPosition {
33
+ export enum DragTargetPosition {
34
34
  Top = "top",
35
35
  Bottom = "bottom",
36
36
  Item = "item",
@@ -50,7 +50,7 @@ export type DragAndDropFeatureDef<T> = {
50
50
  canReorder?: boolean;
51
51
 
52
52
  canDrag?: (items: ItemInstance<T>[]) => boolean;
53
- canDrop?: (items: ItemInstance<T>[], target: DropTarget<T>) => boolean;
53
+ canDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => boolean;
54
54
 
55
55
  indent?: number;
56
56
 
@@ -60,20 +60,20 @@ export type DragAndDropFeatureDef<T> = {
60
60
  };
61
61
  canDropForeignDragObject?: (
62
62
  dataTransfer: DataTransfer,
63
- target: DropTarget<T>,
63
+ target: DragTarget<T>,
64
64
  ) => boolean;
65
65
  onDrop?: (
66
66
  items: ItemInstance<T>[],
67
- target: DropTarget<T>,
67
+ target: DragTarget<T>,
68
68
  ) => void | Promise<void>;
69
69
  onDropForeignDragObject?: (
70
70
  dataTransfer: DataTransfer,
71
- target: DropTarget<T>,
71
+ target: DragTarget<T>,
72
72
  ) => void | Promise<void>;
73
73
  onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
74
74
  };
75
75
  treeInstance: {
76
- getDropTarget: () => DropTarget<T> | null;
76
+ getDragTarget: () => DragTarget<T> | null;
77
77
  getDragLineData: () => DragLineData | null;
78
78
 
79
79
  getDragLineStyle: (
@@ -82,9 +82,9 @@ export type DragAndDropFeatureDef<T> = {
82
82
  ) => Record<string, any>;
83
83
  };
84
84
  itemInstance: {
85
- isDropTarget: () => boolean;
86
- isDropTargetAbove: () => boolean;
87
- isDropTargetBelow: () => boolean;
85
+ isDragTarget: () => boolean;
86
+ isDragTargetAbove: () => boolean;
87
+ isDragTargetBelow: () => boolean;
88
88
  isDraggingOver: () => boolean;
89
89
  };
90
90
  hotkeys: never;
@@ -1,7 +1,7 @@
1
1
  import { ItemInstance, TreeInstance } from "../../types/core";
2
- import { DropTarget } from "./types";
2
+ import { DragTarget } from "./types";
3
3
 
4
- enum ItemDropCategory {
4
+ export enum ItemDropCategory {
5
5
  Item,
6
6
  ExpandedFolder,
7
7
  LastInGroup,
@@ -28,7 +28,7 @@ type TargetPlacement =
28
28
 
29
29
  export const canDrop = (
30
30
  dataTransfer: DataTransfer | null,
31
- target: DropTarget<any>,
31
+ target: DragTarget<any>,
32
32
  tree: TreeInstance<any>,
33
33
  ) => {
34
34
  const draggedItems = tree.getState().dnd?.draggedItems;
@@ -52,7 +52,8 @@ export const canDrop = (
52
52
  if (
53
53
  !draggedItems &&
54
54
  dataTransfer &&
55
- !config.canDropForeignDragObject?.(dataTransfer, target)
55
+ config.canDropForeignDragObject &&
56
+ !config.canDropForeignDragObject(dataTransfer, target)
56
57
  ) {
57
58
  return false;
58
59
  }
@@ -60,7 +61,7 @@ export const canDrop = (
60
61
  return true;
61
62
  };
62
63
 
63
- const getItemDropCategory = (item: ItemInstance<any>) => {
64
+ export const getItemDropCategory = (item: ItemInstance<any>) => {
64
65
  if (item.isExpanded()) {
65
66
  return ItemDropCategory.ExpandedFolder;
66
67
  }
@@ -73,6 +74,24 @@ const getItemDropCategory = (item: ItemInstance<any>) => {
73
74
  return ItemDropCategory.Item;
74
75
  };
75
76
 
77
+ export const getInsertionIndex = <T>(
78
+ children: ItemInstance<T>[],
79
+ childIndex: number,
80
+ draggedItems: ItemInstance<T>[] | undefined,
81
+ ) => {
82
+ const numberOfDragItemsBeforeTarget =
83
+ children
84
+ .slice(0, childIndex)
85
+ .reduce(
86
+ (counter, child) =>
87
+ child && draggedItems?.some((i) => i.getId() === child.getId())
88
+ ? ++counter
89
+ : counter,
90
+ 0,
91
+ ) ?? 0;
92
+ return childIndex - numberOfDragItemsBeforeTarget;
93
+ };
94
+
76
95
  const getTargetPlacement = (
77
96
  e: any,
78
97
  item: ItemInstance<any>,
@@ -153,17 +172,43 @@ const getNthParent = (
153
172
  return getNthParent(item.getParent()!, n);
154
173
  };
155
174
 
156
- export const getDropTarget = (
175
+ /** @param item refers to the bottom-most item of the container, at which bottom is being reparented on (e.g. root-1-2-6) */
176
+ export const getReparentTarget = <T>(
177
+ item: ItemInstance<T>,
178
+ reparentLevel: number,
179
+ draggedItems: ItemInstance<T>[] | undefined,
180
+ ) => {
181
+ const itemMeta = item.getItemMeta();
182
+ const reparentedTarget = getNthParent(item, reparentLevel - 1);
183
+ const targetItemAbove = getNthParent(item, reparentLevel); // .getItemBelow()!;
184
+ const targetIndex = targetItemAbove.getIndexInParent() + 1;
185
+
186
+ // TODO possibly count items dragged out above the new target
187
+
188
+ return {
189
+ item: reparentedTarget,
190
+ childIndex: targetIndex,
191
+ insertionIndex: getInsertionIndex(
192
+ reparentedTarget.getChildren(),
193
+ targetIndex,
194
+ draggedItems,
195
+ ),
196
+ dragLineIndex: itemMeta.index + 1,
197
+ dragLineLevel: reparentLevel,
198
+ };
199
+ };
200
+
201
+ export const getDragTarget = (
157
202
  e: any,
158
203
  item: ItemInstance<any>,
159
204
  tree: TreeInstance<any>,
160
205
  canReorder = tree.getConfig().canReorder,
161
- ): DropTarget<any> => {
162
- const draggedItems = tree.getState().dnd?.draggedItems ?? [];
206
+ ): DragTarget<any> => {
207
+ const draggedItems = tree.getState().dnd?.draggedItems;
163
208
  const itemMeta = item.getItemMeta();
164
209
  const parent = item.getParent();
165
- const itemTarget: DropTarget<any> = { item };
166
- const parentTarget: DropTarget<any> | null = parent ? { item: parent } : null;
210
+ const itemTarget: DragTarget<any> = { item };
211
+ const parentTarget: DragTarget<any> | null = parent ? { item: parent } : null;
167
212
  const canBecomeSibling =
168
213
  parentTarget && canDrop(e.dataTransfer, parentTarget, tree);
169
214
 
@@ -180,8 +225,8 @@ export const getDropTarget = (
180
225
  }
181
226
 
182
227
  if (!canReorder && parent && !canBecomeSibling) {
183
- // TODO! this breaks in story DND/Can Drop. Maybe move this logic into a composable DropTargetStrategy[] ?
184
- return getDropTarget(e, parent, tree, false);
228
+ // TODO! this breaks in story DND/Can Drop. Maybe move this logic into a composable DragTargetStrategy[] ?
229
+ return getDragTarget(e, parent, tree, false);
185
230
  }
186
231
 
187
232
  if (!parent) {
@@ -194,47 +239,27 @@ export const getDropTarget = (
194
239
  }
195
240
 
196
241
  if (!canBecomeSibling) {
197
- return getDropTarget(e, parent, tree, false);
242
+ return getDragTarget(e, parent, tree, false);
198
243
  }
199
244
 
200
245
  if (placement.type === PlacementType.Reparent) {
201
- const reparentedTarget = getNthParent(item, placement.reparentLevel - 1);
202
- const targetItemAbove = getNthParent(item, placement.reparentLevel); // .getItemBelow()!;
203
- const targetIndex = targetItemAbove.getIndexInParent() + 1;
204
-
205
- // TODO possibly count items dragged out above the new target
206
-
207
- return {
208
- item: reparentedTarget,
209
- childIndex: targetIndex,
210
- insertionIndex: targetIndex,
211
- dragLineIndex: itemMeta.index + 1,
212
- dragLineLevel: placement.reparentLevel,
213
- };
246
+ return getReparentTarget(item, placement.reparentLevel, draggedItems);
214
247
  }
215
248
 
216
249
  const maybeAddOneForBelow =
217
250
  placement.type === PlacementType.ReorderAbove ? 0 : 1;
218
251
  const childIndex = item.getIndexInParent() + maybeAddOneForBelow;
219
252
 
220
- const numberOfDragItemsBeforeTarget =
221
- parent
222
- .getChildren()
223
- .slice(0, childIndex)
224
- .reduce(
225
- (counter, child) =>
226
- child && draggedItems?.some((i) => i.getId() === child.getId())
227
- ? ++counter
228
- : counter,
229
- 0,
230
- ) ?? 0;
231
-
232
253
  return {
233
254
  item: parent,
234
255
  dragLineIndex: itemMeta.index + maybeAddOneForBelow,
235
256
  dragLineLevel: itemMeta.level,
236
257
  childIndex,
237
258
  // TODO performance could be improved by computing this only when dragcode changed
238
- insertionIndex: childIndex - numberOfDragItemsBeforeTarget,
259
+ insertionIndex: getInsertionIndex(
260
+ parent.getChildren(),
261
+ childIndex,
262
+ draggedItems,
263
+ ),
239
264
  };
240
265
  };
@@ -48,6 +48,7 @@ export const hotkeysCoreFeature: FeatureImplementation = {
48
48
  data.current.pressedKeys ??= new Set();
49
49
  const newMatch = !data.current.pressedKeys.has(e.key);
50
50
  data.current.pressedKeys.add(e.key);
51
+ console.log("HOTKEYS", data.current.pressedKeys);
51
52
 
52
53
  const hotkeyName = findHotkeyMatch(
53
54
  data.current.pressedKeys,