@headless-tree/core 0.0.0-20250322153940 → 0.0.0-20250330232313
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.
- package/CHANGELOG.md +2 -1
- package/lib/cjs/features/drag-and-drop/feature.js +11 -11
- package/lib/cjs/features/drag-and-drop/types.d.ts +11 -11
- package/lib/cjs/features/drag-and-drop/types.js +7 -7
- package/lib/cjs/features/drag-and-drop/utils.d.ts +18 -3
- package/lib/cjs/features/drag-and-drop/utils.js +42 -30
- package/lib/cjs/features/hotkeys-core/feature.js +1 -0
- package/lib/cjs/features/keyboard-drag-and-drop/feature.d.ts +2 -0
- package/lib/cjs/features/keyboard-drag-and-drop/feature.js +207 -0
- package/lib/cjs/features/keyboard-drag-and-drop/types.d.ts +27 -0
- package/lib/cjs/features/keyboard-drag-and-drop/types.js +11 -0
- package/lib/cjs/index.d.ts +2 -0
- package/lib/cjs/index.js +2 -0
- package/lib/cjs/mddocs-entry.d.ts +10 -0
- package/lib/cjs/test-utils/test-tree-expect.d.ts +5 -3
- package/lib/cjs/test-utils/test-tree-expect.js +3 -0
- package/lib/cjs/types/core.d.ts +2 -1
- package/lib/cjs/utilities/create-on-drop-handler.d.ts +2 -2
- package/lib/cjs/utilities/insert-items-at-target.d.ts +2 -2
- package/lib/esm/features/drag-and-drop/feature.js +12 -12
- package/lib/esm/features/drag-and-drop/types.d.ts +11 -11
- package/lib/esm/features/drag-and-drop/types.js +6 -6
- package/lib/esm/features/drag-and-drop/utils.d.ts +18 -3
- package/lib/esm/features/drag-and-drop/utils.js +37 -28
- package/lib/esm/features/hotkeys-core/feature.js +1 -0
- package/lib/esm/features/keyboard-drag-and-drop/feature.d.ts +2 -0
- package/lib/esm/features/keyboard-drag-and-drop/feature.js +204 -0
- package/lib/esm/features/keyboard-drag-and-drop/types.d.ts +27 -0
- package/lib/esm/features/keyboard-drag-and-drop/types.js +8 -0
- package/lib/esm/index.d.ts +2 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/mddocs-entry.d.ts +10 -0
- package/lib/esm/test-utils/test-tree-expect.d.ts +5 -3
- package/lib/esm/test-utils/test-tree-expect.js +3 -0
- package/lib/esm/types/core.d.ts +2 -1
- package/lib/esm/utilities/create-on-drop-handler.d.ts +2 -2
- package/lib/esm/utilities/insert-items-at-target.d.ts +2 -2
- package/package.json +1 -1
- package/src/features/drag-and-drop/drag-and-drop.spec.ts +6 -6
- package/src/features/drag-and-drop/feature.ts +12 -12
- package/src/features/drag-and-drop/types.ts +11 -11
- package/src/features/drag-and-drop/utils.ts +64 -39
- package/src/features/hotkeys-core/feature.ts +1 -0
- package/src/features/keyboard-drag-and-drop/feature.ts +255 -0
- package/src/features/keyboard-drag-and-drop/keyboard-drag-and-drop.spec.ts +401 -0
- package/src/features/keyboard-drag-and-drop/types.ts +30 -0
- package/src/index.ts +2 -0
- package/src/mddocs-entry.ts +16 -0
- package/src/test-utils/test-tree-expect.ts +7 -2
- package/src/types/core.ts +2 -0
- package/src/utilities/create-on-drop-handler.ts +2 -2
- package/src/utilities/insert-items-at-target.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20250330232313
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
7
|
- 2af5668: Bug fix: Mutations to expanded tree items from outside will now trigger a rebuild of the tree structure (#65)
|
|
8
|
+
- 617faea: Support for keyboard-controlled drag-and-drop events
|
|
8
9
|
|
|
9
10
|
## 0.0.14
|
|
10
11
|
|
|
@@ -20,13 +20,13 @@ exports.dragAndDropFeature = {
|
|
|
20
20
|
dnd: "setDndState",
|
|
21
21
|
},
|
|
22
22
|
treeInstance: {
|
|
23
|
-
|
|
23
|
+
getDragTarget: ({ tree }) => {
|
|
24
24
|
var _a, _b;
|
|
25
25
|
return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
|
|
26
26
|
},
|
|
27
27
|
getDragLineData: ({ tree }) => {
|
|
28
28
|
var _a, _b, _c, _d, _e, _f;
|
|
29
|
-
const target = tree.
|
|
29
|
+
const target = tree.getDragTarget();
|
|
30
30
|
const indent = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
31
31
|
const treeBb = (_b = tree.getElement()) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect();
|
|
32
32
|
if (!target || !treeBb || !("childIndex" in target))
|
|
@@ -39,7 +39,7 @@ exports.dragAndDropFeature = {
|
|
|
39
39
|
if (bb) {
|
|
40
40
|
return {
|
|
41
41
|
indent,
|
|
42
|
-
top: bb.bottom - treeBb.
|
|
42
|
+
top: bb.bottom - treeBb.top,
|
|
43
43
|
left: bb.left + leftOffset - treeBb.left,
|
|
44
44
|
width: bb.width - leftOffset,
|
|
45
45
|
};
|
|
@@ -104,7 +104,7 @@ exports.dragAndDropFeature = {
|
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
dataRef.current.lastDragCode = nextDragCode;
|
|
107
|
-
const target = (0, utils_1.
|
|
107
|
+
const target = (0, utils_1.getDragTarget)(e, item, tree);
|
|
108
108
|
if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
|
|
109
109
|
(!e.dataTransfer ||
|
|
110
110
|
!((_c = (_b = tree
|
|
@@ -134,7 +134,7 @@ exports.dragAndDropFeature = {
|
|
|
134
134
|
}, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
135
135
|
var _a, _b, _c;
|
|
136
136
|
const dataRef = tree.getDataRef();
|
|
137
|
-
const target = (0, utils_1.
|
|
137
|
+
const target = (0, utils_1.getDragTarget)(e, item, tree);
|
|
138
138
|
if (!(0, utils_1.canDrop)(e.dataTransfer, target, tree)) {
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
@@ -150,20 +150,20 @@ exports.dragAndDropFeature = {
|
|
|
150
150
|
yield ((_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target));
|
|
151
151
|
}
|
|
152
152
|
}) })),
|
|
153
|
-
|
|
154
|
-
const target = tree.
|
|
153
|
+
isDragTarget: ({ tree, item }) => {
|
|
154
|
+
const target = tree.getDragTarget();
|
|
155
155
|
return target ? target.item.getId() === item.getId() : false;
|
|
156
156
|
},
|
|
157
|
-
|
|
158
|
-
const target = tree.
|
|
157
|
+
isDragTargetAbove: ({ tree, item }) => {
|
|
158
|
+
const target = tree.getDragTarget();
|
|
159
159
|
if (!target ||
|
|
160
160
|
!("childIndex" in target) ||
|
|
161
161
|
target.item !== item.getParent())
|
|
162
162
|
return false;
|
|
163
163
|
return target.childIndex === item.getItemMeta().posInSet;
|
|
164
164
|
},
|
|
165
|
-
|
|
166
|
-
const target = tree.
|
|
165
|
+
isDragTargetBelow: ({ tree, item }) => {
|
|
166
|
+
const target = tree.getDragTarget();
|
|
167
167
|
if (!target ||
|
|
168
168
|
!("childIndex" in target) ||
|
|
169
169
|
target.item !== item.getParent())
|
|
@@ -6,7 +6,7 @@ export interface DndDataRef {
|
|
|
6
6
|
export interface DndState<T> {
|
|
7
7
|
draggedItems?: ItemInstance<T>[];
|
|
8
8
|
draggingOverItem?: ItemInstance<T>;
|
|
9
|
-
dragTarget?:
|
|
9
|
+
dragTarget?: DragTarget<T>;
|
|
10
10
|
}
|
|
11
11
|
export interface DragLineData {
|
|
12
12
|
indent: number;
|
|
@@ -14,7 +14,7 @@ export interface DragLineData {
|
|
|
14
14
|
left: number;
|
|
15
15
|
width: number;
|
|
16
16
|
}
|
|
17
|
-
export type
|
|
17
|
+
export type DragTarget<T> = {
|
|
18
18
|
item: ItemInstance<T>;
|
|
19
19
|
childIndex: number;
|
|
20
20
|
insertionIndex: number;
|
|
@@ -23,7 +23,7 @@ export type DropTarget<T> = {
|
|
|
23
23
|
} | {
|
|
24
24
|
item: ItemInstance<T>;
|
|
25
25
|
};
|
|
26
|
-
export declare enum
|
|
26
|
+
export declare enum DragTargetPosition {
|
|
27
27
|
Top = "top",
|
|
28
28
|
Bottom = "bottom",
|
|
29
29
|
Item = "item"
|
|
@@ -40,26 +40,26 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
40
40
|
reorderAreaPercentage?: number;
|
|
41
41
|
canReorder?: boolean;
|
|
42
42
|
canDrag?: (items: ItemInstance<T>[]) => boolean;
|
|
43
|
-
canDrop?: (items: ItemInstance<T>[], target:
|
|
43
|
+
canDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => boolean;
|
|
44
44
|
indent?: number;
|
|
45
45
|
createForeignDragObject?: (items: ItemInstance<T>[]) => {
|
|
46
46
|
format: string;
|
|
47
47
|
data: any;
|
|
48
48
|
};
|
|
49
|
-
canDropForeignDragObject?: (dataTransfer: DataTransfer, target:
|
|
50
|
-
onDrop?: (items: ItemInstance<T>[], target:
|
|
51
|
-
onDropForeignDragObject?: (dataTransfer: DataTransfer, target:
|
|
49
|
+
canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
|
|
50
|
+
onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
|
|
51
|
+
onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
|
|
52
52
|
onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
|
|
53
53
|
};
|
|
54
54
|
treeInstance: {
|
|
55
|
-
|
|
55
|
+
getDragTarget: () => DragTarget<T> | null;
|
|
56
56
|
getDragLineData: () => DragLineData | null;
|
|
57
57
|
getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
|
|
58
58
|
};
|
|
59
59
|
itemInstance: {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
isDragTarget: () => boolean;
|
|
61
|
+
isDragTargetAbove: () => boolean;
|
|
62
|
+
isDragTargetBelow: () => boolean;
|
|
63
63
|
isDraggingOver: () => boolean;
|
|
64
64
|
};
|
|
65
65
|
hotkeys: never;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
var
|
|
5
|
-
(function (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
})(
|
|
3
|
+
exports.DragTargetPosition = void 0;
|
|
4
|
+
var DragTargetPosition;
|
|
5
|
+
(function (DragTargetPosition) {
|
|
6
|
+
DragTargetPosition["Top"] = "top";
|
|
7
|
+
DragTargetPosition["Bottom"] = "bottom";
|
|
8
|
+
DragTargetPosition["Item"] = "item";
|
|
9
|
+
})(DragTargetPosition || (exports.DragTargetPosition = DragTargetPosition = {}));
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { ItemInstance, TreeInstance } from "../../types/core";
|
|
2
|
-
import {
|
|
3
|
-
export declare
|
|
2
|
+
import { DragTarget } from "./types";
|
|
3
|
+
export declare enum ItemDropCategory {
|
|
4
|
+
Item = 0,
|
|
5
|
+
ExpandedFolder = 1,
|
|
6
|
+
LastInGroup = 2
|
|
7
|
+
}
|
|
8
|
+
export declare const canDrop: (dataTransfer: DataTransfer | null, target: DragTarget<any>, tree: TreeInstance<any>) => boolean;
|
|
9
|
+
export declare const getItemDropCategory: (item: ItemInstance<any>) => ItemDropCategory;
|
|
10
|
+
export declare const getInsertionIndex: <T>(children: ItemInstance<T>[], childIndex: number, draggedItems: ItemInstance<T>[] | undefined) => number;
|
|
4
11
|
export declare const getDragCode: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>) => string;
|
|
5
|
-
|
|
12
|
+
/** @param item refers to the bottom-most item of the container, at which bottom is being reparented on (e.g. root-1-2-6) */
|
|
13
|
+
export declare const getReparentTarget: <T>(item: ItemInstance<T>, reparentLevel: number, draggedItems: ItemInstance<T>[] | undefined) => {
|
|
14
|
+
item: ItemInstance<any>;
|
|
15
|
+
childIndex: number;
|
|
16
|
+
insertionIndex: number;
|
|
17
|
+
dragLineIndex: number;
|
|
18
|
+
dragLineLevel: number;
|
|
19
|
+
};
|
|
20
|
+
export declare const getDragTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>, canReorder?: boolean | undefined) => DragTarget<any>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getDragTarget = exports.getReparentTarget = exports.getDragCode = exports.getInsertionIndex = exports.getItemDropCategory = exports.canDrop = exports.ItemDropCategory = void 0;
|
|
4
4
|
var ItemDropCategory;
|
|
5
5
|
(function (ItemDropCategory) {
|
|
6
6
|
ItemDropCategory[ItemDropCategory["Item"] = 0] = "Item";
|
|
7
7
|
ItemDropCategory[ItemDropCategory["ExpandedFolder"] = 1] = "ExpandedFolder";
|
|
8
8
|
ItemDropCategory[ItemDropCategory["LastInGroup"] = 2] = "LastInGroup";
|
|
9
|
-
})(ItemDropCategory || (ItemDropCategory = {}));
|
|
9
|
+
})(ItemDropCategory || (exports.ItemDropCategory = ItemDropCategory = {}));
|
|
10
10
|
var PlacementType;
|
|
11
11
|
(function (PlacementType) {
|
|
12
12
|
PlacementType[PlacementType["ReorderAbove"] = 0] = "ReorderAbove";
|
|
@@ -15,7 +15,7 @@ var PlacementType;
|
|
|
15
15
|
PlacementType[PlacementType["Reparent"] = 3] = "Reparent";
|
|
16
16
|
})(PlacementType || (PlacementType = {}));
|
|
17
17
|
const canDrop = (dataTransfer, target, tree) => {
|
|
18
|
-
var _a, _b, _c
|
|
18
|
+
var _a, _b, _c;
|
|
19
19
|
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
20
20
|
const config = tree.getConfig();
|
|
21
21
|
if (draggedItems && !((_c = (_b = config.canDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target)) !== null && _c !== void 0 ? _c : true)) {
|
|
@@ -28,7 +28,8 @@ const canDrop = (dataTransfer, target, tree) => {
|
|
|
28
28
|
}
|
|
29
29
|
if (!draggedItems &&
|
|
30
30
|
dataTransfer &&
|
|
31
|
-
|
|
31
|
+
config.canDropForeignDragObject &&
|
|
32
|
+
!config.canDropForeignDragObject(dataTransfer, target)) {
|
|
32
33
|
return false;
|
|
33
34
|
}
|
|
34
35
|
return true;
|
|
@@ -44,6 +45,17 @@ const getItemDropCategory = (item) => {
|
|
|
44
45
|
}
|
|
45
46
|
return ItemDropCategory.Item;
|
|
46
47
|
};
|
|
48
|
+
exports.getItemDropCategory = getItemDropCategory;
|
|
49
|
+
const getInsertionIndex = (children, childIndex, draggedItems) => {
|
|
50
|
+
var _a;
|
|
51
|
+
const numberOfDragItemsBeforeTarget = (_a = children
|
|
52
|
+
.slice(0, childIndex)
|
|
53
|
+
.reduce((counter, child) => child && (draggedItems === null || draggedItems === void 0 ? void 0 : draggedItems.some((i) => i.getId() === child.getId()))
|
|
54
|
+
? ++counter
|
|
55
|
+
: counter, 0)) !== null && _a !== void 0 ? _a : 0;
|
|
56
|
+
return childIndex - numberOfDragItemsBeforeTarget;
|
|
57
|
+
};
|
|
58
|
+
exports.getInsertionIndex = getInsertionIndex;
|
|
47
59
|
const getTargetPlacement = (e, item, tree, canMakeChild) => {
|
|
48
60
|
var _a, _b, _c, _d, _e;
|
|
49
61
|
const config = tree.getConfig();
|
|
@@ -55,7 +67,7 @@ const getTargetPlacement = (e, item, tree, canMakeChild) => {
|
|
|
55
67
|
const bb = (_a = item.getElement()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
56
68
|
const topPercent = bb ? (e.clientY - bb.top) / bb.height : 0.5;
|
|
57
69
|
const leftPixels = bb ? e.clientX - bb.left : 0;
|
|
58
|
-
const targetDropCategory = getItemDropCategory(item);
|
|
70
|
+
const targetDropCategory = (0, exports.getItemDropCategory)(item);
|
|
59
71
|
const reorderAreaPercentage = !canMakeChild
|
|
60
72
|
? 0.5
|
|
61
73
|
: (_b = config.reorderAreaPercentage) !== null && _b !== void 0 ? _b : 0.3;
|
|
@@ -106,9 +118,25 @@ const getNthParent = (item, n) => {
|
|
|
106
118
|
}
|
|
107
119
|
return getNthParent(item.getParent(), n);
|
|
108
120
|
};
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
121
|
+
/** @param item refers to the bottom-most item of the container, at which bottom is being reparented on (e.g. root-1-2-6) */
|
|
122
|
+
const getReparentTarget = (item, reparentLevel, draggedItems) => {
|
|
123
|
+
const itemMeta = item.getItemMeta();
|
|
124
|
+
const reparentedTarget = getNthParent(item, reparentLevel - 1);
|
|
125
|
+
const targetItemAbove = getNthParent(item, reparentLevel); // .getItemBelow()!;
|
|
126
|
+
const targetIndex = targetItemAbove.getIndexInParent() + 1;
|
|
127
|
+
// TODO possibly count items dragged out above the new target
|
|
128
|
+
return {
|
|
129
|
+
item: reparentedTarget,
|
|
130
|
+
childIndex: targetIndex,
|
|
131
|
+
insertionIndex: (0, exports.getInsertionIndex)(reparentedTarget.getChildren(), targetIndex, draggedItems),
|
|
132
|
+
dragLineIndex: itemMeta.index + 1,
|
|
133
|
+
dragLineLevel: reparentLevel,
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
exports.getReparentTarget = getReparentTarget;
|
|
137
|
+
const getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) => {
|
|
138
|
+
var _a;
|
|
139
|
+
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
112
140
|
const itemMeta = item.getItemMeta();
|
|
113
141
|
const parent = item.getParent();
|
|
114
142
|
const itemTarget = { item };
|
|
@@ -123,8 +151,8 @@ const getDropTarget = (e, item, tree, canReorder = tree.getConfig().canReorder)
|
|
|
123
151
|
return parentTarget;
|
|
124
152
|
}
|
|
125
153
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
126
|
-
// TODO! this breaks in story DND/Can Drop. Maybe move this logic into a composable
|
|
127
|
-
return (0, exports.
|
|
154
|
+
// TODO! this breaks in story DND/Can Drop. Maybe move this logic into a composable DragTargetStrategy[] ?
|
|
155
|
+
return (0, exports.getDragTarget)(e, parent, tree, false);
|
|
128
156
|
}
|
|
129
157
|
if (!parent) {
|
|
130
158
|
// Shouldn't happen, but if dropped "next" to root item, just drop it inside
|
|
@@ -134,36 +162,20 @@ const getDropTarget = (e, item, tree, canReorder = tree.getConfig().canReorder)
|
|
|
134
162
|
return itemTarget;
|
|
135
163
|
}
|
|
136
164
|
if (!canBecomeSibling) {
|
|
137
|
-
return (0, exports.
|
|
165
|
+
return (0, exports.getDragTarget)(e, parent, tree, false);
|
|
138
166
|
}
|
|
139
167
|
if (placement.type === PlacementType.Reparent) {
|
|
140
|
-
|
|
141
|
-
const targetItemAbove = getNthParent(item, placement.reparentLevel); // .getItemBelow()!;
|
|
142
|
-
const targetIndex = targetItemAbove.getIndexInParent() + 1;
|
|
143
|
-
// TODO possibly count items dragged out above the new target
|
|
144
|
-
return {
|
|
145
|
-
item: reparentedTarget,
|
|
146
|
-
childIndex: targetIndex,
|
|
147
|
-
insertionIndex: targetIndex,
|
|
148
|
-
dragLineIndex: itemMeta.index + 1,
|
|
149
|
-
dragLineLevel: placement.reparentLevel,
|
|
150
|
-
};
|
|
168
|
+
return (0, exports.getReparentTarget)(item, placement.reparentLevel, draggedItems);
|
|
151
169
|
}
|
|
152
170
|
const maybeAddOneForBelow = placement.type === PlacementType.ReorderAbove ? 0 : 1;
|
|
153
171
|
const childIndex = item.getIndexInParent() + maybeAddOneForBelow;
|
|
154
|
-
const numberOfDragItemsBeforeTarget = (_c = parent
|
|
155
|
-
.getChildren()
|
|
156
|
-
.slice(0, childIndex)
|
|
157
|
-
.reduce((counter, child) => child && (draggedItems === null || draggedItems === void 0 ? void 0 : draggedItems.some((i) => i.getId() === child.getId()))
|
|
158
|
-
? ++counter
|
|
159
|
-
: counter, 0)) !== null && _c !== void 0 ? _c : 0;
|
|
160
172
|
return {
|
|
161
173
|
item: parent,
|
|
162
174
|
dragLineIndex: itemMeta.index + maybeAddOneForBelow,
|
|
163
175
|
dragLineLevel: itemMeta.level,
|
|
164
176
|
childIndex,
|
|
165
177
|
// TODO performance could be improved by computing this only when dragcode changed
|
|
166
|
-
insertionIndex:
|
|
178
|
+
insertionIndex: (0, exports.getInsertionIndex)(parent.getChildren(), childIndex, draggedItems),
|
|
167
179
|
};
|
|
168
180
|
};
|
|
169
|
-
exports.
|
|
181
|
+
exports.getDragTarget = getDragTarget;
|
|
@@ -30,6 +30,7 @@ exports.hotkeysCoreFeature = {
|
|
|
30
30
|
(_a = (_e = data.current).pressedKeys) !== null && _a !== void 0 ? _a : (_e.pressedKeys = new Set());
|
|
31
31
|
const newMatch = !data.current.pressedKeys.has(e.key);
|
|
32
32
|
data.current.pressedKeys.add(e.key);
|
|
33
|
+
console.log("HOTKEYS", data.current.pressedKeys);
|
|
33
34
|
const hotkeyName = findHotkeyMatch(data.current.pressedKeys, tree, tree.getHotkeyPresets(), tree.getConfig().hotkeys);
|
|
34
35
|
if (!hotkeyName)
|
|
35
36
|
return;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.keyboardDragAndDropFeature = void 0;
|
|
13
|
+
const utils_1 = require("../drag-and-drop/utils");
|
|
14
|
+
const utils_2 = require("../../utils");
|
|
15
|
+
const types_1 = require("./types");
|
|
16
|
+
const getNextDragTarget = (tree, isUp, dragTarget) => {
|
|
17
|
+
var _a, _b, _c, _d;
|
|
18
|
+
const direction = isUp ? 0 : 1;
|
|
19
|
+
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
|
|
20
|
+
// currently hovering between items
|
|
21
|
+
if ("childIndex" in dragTarget) {
|
|
22
|
+
// TODO move check in reusable function
|
|
23
|
+
const parent = dragTarget.item.getParent();
|
|
24
|
+
const targetedItem = tree.getItems()[dragTarget.dragLineIndex - 1]; // item above dragline
|
|
25
|
+
const targetCategory = targetedItem
|
|
26
|
+
? (0, utils_1.getItemDropCategory)(targetedItem)
|
|
27
|
+
: utils_1.ItemDropCategory.Item;
|
|
28
|
+
const maxLevel = (_b = targetedItem === null || targetedItem === void 0 ? void 0 : targetedItem.getItemMeta().level) !== null && _b !== void 0 ? _b : 0;
|
|
29
|
+
const minLevel = (_d = (_c = targetedItem === null || targetedItem === void 0 ? void 0 : targetedItem.getItemBelow()) === null || _c === void 0 ? void 0 : _c.getItemMeta().level) !== null && _d !== void 0 ? _d : 0;
|
|
30
|
+
// reparenting
|
|
31
|
+
if (targetCategory === utils_1.ItemDropCategory.LastInGroup) {
|
|
32
|
+
if (isUp && dragTarget.dragLineLevel < maxLevel) {
|
|
33
|
+
return (0, utils_1.getReparentTarget)(targetedItem, dragTarget.dragLineLevel + 1, draggedItems);
|
|
34
|
+
}
|
|
35
|
+
if (!isUp && dragTarget.dragLineLevel > minLevel && parent) {
|
|
36
|
+
return (0, utils_1.getReparentTarget)(targetedItem, dragTarget.dragLineLevel - 1, draggedItems);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const newIndex = dragTarget.dragLineIndex - 1 + direction;
|
|
40
|
+
const item = tree.getItems()[newIndex];
|
|
41
|
+
return item ? { item } : undefined;
|
|
42
|
+
}
|
|
43
|
+
// moving upwards outside of an open folder
|
|
44
|
+
const targetingExpandedFolder = (0, utils_1.getItemDropCategory)(dragTarget.item) === utils_1.ItemDropCategory.ExpandedFolder;
|
|
45
|
+
if (targetingExpandedFolder && !isUp) {
|
|
46
|
+
return {
|
|
47
|
+
item: dragTarget.item,
|
|
48
|
+
childIndex: 0,
|
|
49
|
+
insertionIndex: (0, utils_1.getInsertionIndex)(dragTarget.item.getChildren(), 0, draggedItems),
|
|
50
|
+
dragLineIndex: dragTarget.item.getItemMeta().index + direction,
|
|
51
|
+
dragLineLevel: dragTarget.item.getItemMeta().level + 1,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// currently hovering over item
|
|
55
|
+
const childIndex = dragTarget.item.getIndexInParent() + direction;
|
|
56
|
+
return {
|
|
57
|
+
item: dragTarget.item.getParent(),
|
|
58
|
+
childIndex,
|
|
59
|
+
insertionIndex: (0, utils_1.getInsertionIndex)(dragTarget.item.getParent().getChildren(), childIndex, draggedItems),
|
|
60
|
+
dragLineIndex: dragTarget.item.getItemMeta().index + direction,
|
|
61
|
+
dragLineLevel: dragTarget.item.getItemMeta().level,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
const getNextValidDragTarget = (tree, isUp, previousTarget) => {
|
|
65
|
+
var _a, _b;
|
|
66
|
+
if (previousTarget === void 0) { previousTarget = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget; }
|
|
67
|
+
if (!previousTarget)
|
|
68
|
+
return undefined;
|
|
69
|
+
const nextTarget = getNextDragTarget(tree, isUp, previousTarget);
|
|
70
|
+
const dataTransfer = (_b = tree.getDataRef().current.kDndDataTransfer) !== null && _b !== void 0 ? _b : null;
|
|
71
|
+
if (!nextTarget)
|
|
72
|
+
return undefined;
|
|
73
|
+
if ((0, utils_1.canDrop)(dataTransfer, nextTarget, tree)) {
|
|
74
|
+
return nextTarget;
|
|
75
|
+
}
|
|
76
|
+
return getNextValidDragTarget(tree, isUp, nextTarget);
|
|
77
|
+
};
|
|
78
|
+
const updateScroll = (tree) => {
|
|
79
|
+
const state = tree.getState().dnd;
|
|
80
|
+
if (!(state === null || state === void 0 ? void 0 : state.dragTarget) || "childIndex" in state.dragTarget)
|
|
81
|
+
return;
|
|
82
|
+
state.dragTarget.item.scrollTo({ block: "nearest", inline: "nearest" });
|
|
83
|
+
};
|
|
84
|
+
const initiateDrag = (tree, draggedItems, dataTransfer) => {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
const focusedItem = tree.getFocusedItem();
|
|
87
|
+
const { canDrag } = tree.getConfig();
|
|
88
|
+
if (draggedItems && canDrag && !canDrag(draggedItems)) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (draggedItems) {
|
|
92
|
+
tree.applySubStateUpdate("dnd", { draggedItems });
|
|
93
|
+
// getNextValidDragTarget->canDrop needs the draggedItems in state
|
|
94
|
+
(_b = (_a = tree.getConfig()).onStartKeyboardDrag) === null || _b === void 0 ? void 0 : _b.call(_a, draggedItems);
|
|
95
|
+
}
|
|
96
|
+
else if (dataTransfer) {
|
|
97
|
+
tree.getDataRef().current.kDndDataTransfer = dataTransfer;
|
|
98
|
+
}
|
|
99
|
+
const dragTarget = getNextValidDragTarget(tree, false, {
|
|
100
|
+
item: focusedItem,
|
|
101
|
+
});
|
|
102
|
+
if (!dragTarget)
|
|
103
|
+
return;
|
|
104
|
+
tree.applySubStateUpdate("dnd", {
|
|
105
|
+
draggedItems,
|
|
106
|
+
dragTarget,
|
|
107
|
+
});
|
|
108
|
+
tree.applySubStateUpdate("assistiveDndState", types_1.AssistiveDndState.Started);
|
|
109
|
+
updateScroll(tree);
|
|
110
|
+
};
|
|
111
|
+
const moveDragPosition = (tree, isUp) => {
|
|
112
|
+
var _a;
|
|
113
|
+
const dragTarget = getNextValidDragTarget(tree, isUp);
|
|
114
|
+
if (!dragTarget)
|
|
115
|
+
return;
|
|
116
|
+
tree.applySubStateUpdate("dnd", {
|
|
117
|
+
draggedItems: (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems,
|
|
118
|
+
dragTarget,
|
|
119
|
+
});
|
|
120
|
+
tree.applySubStateUpdate("assistiveDndState", types_1.AssistiveDndState.Dragging);
|
|
121
|
+
if (!("childIndex" in dragTarget)) {
|
|
122
|
+
dragTarget.item.setFocused();
|
|
123
|
+
}
|
|
124
|
+
updateScroll(tree);
|
|
125
|
+
};
|
|
126
|
+
exports.keyboardDragAndDropFeature = {
|
|
127
|
+
key: "keyboard-drag-and-drop",
|
|
128
|
+
deps: ["drag-and-drop"],
|
|
129
|
+
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setAssistiveDndState: (0, utils_2.makeStateUpdater)("assistiveDndState", tree) }, defaultConfig)),
|
|
130
|
+
stateHandlerNames: {
|
|
131
|
+
assistiveDndState: "setAssistiveDndState",
|
|
132
|
+
},
|
|
133
|
+
treeInstance: {
|
|
134
|
+
startKeyboardDrag: ({ tree }, draggedItems) => {
|
|
135
|
+
initiateDrag(tree, draggedItems, undefined);
|
|
136
|
+
},
|
|
137
|
+
startKeyboardDragOnForeignObject: ({ tree }, dataTransfer) => {
|
|
138
|
+
initiateDrag(tree, undefined, dataTransfer);
|
|
139
|
+
},
|
|
140
|
+
stopKeyboardDrag: ({ tree }) => {
|
|
141
|
+
tree.getDataRef().current.kDndDataTransfer = undefined;
|
|
142
|
+
tree.applySubStateUpdate("dnd", null);
|
|
143
|
+
tree.applySubStateUpdate("assistiveDndState", types_1.AssistiveDndState.None);
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
hotkeys: {
|
|
147
|
+
startDrag: {
|
|
148
|
+
hotkey: "Control+Shift+D",
|
|
149
|
+
preventDefault: true,
|
|
150
|
+
isEnabled: (tree) => !tree.getState().dnd,
|
|
151
|
+
handler: (_, tree) => {
|
|
152
|
+
tree.startKeyboardDrag(tree.getSelectedItems());
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
dragUp: {
|
|
156
|
+
hotkey: "ArrowUp",
|
|
157
|
+
preventDefault: true,
|
|
158
|
+
isEnabled: (tree) => !!tree.getState().dnd,
|
|
159
|
+
handler: (_, tree) => {
|
|
160
|
+
moveDragPosition(tree, true);
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
dragDown: {
|
|
164
|
+
hotkey: "ArrowDown",
|
|
165
|
+
preventDefault: true,
|
|
166
|
+
isEnabled: (tree) => !!tree.getState().dnd,
|
|
167
|
+
handler: (_, tree) => {
|
|
168
|
+
moveDragPosition(tree, false);
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
cancelDrag: {
|
|
172
|
+
hotkey: "Escape",
|
|
173
|
+
isEnabled: (tree) => !!tree.getState().dnd,
|
|
174
|
+
handler: (_, tree) => {
|
|
175
|
+
tree.stopKeyboardDrag();
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
completeDrag: {
|
|
179
|
+
hotkey: "Enter",
|
|
180
|
+
preventDefault: true,
|
|
181
|
+
isEnabled: (tree) => !!tree.getState().dnd,
|
|
182
|
+
handler: (e, tree) => __awaiter(void 0, void 0, void 0, function* () {
|
|
183
|
+
var _a, _b, _c, _d;
|
|
184
|
+
e.stopPropagation();
|
|
185
|
+
// TODO copied from keyboard onDrop, unify them
|
|
186
|
+
const dataRef = tree.getDataRef();
|
|
187
|
+
const target = tree.getDragTarget();
|
|
188
|
+
const dataTransfer = (_a = dataRef.current.kDndDataTransfer) !== null && _a !== void 0 ? _a : null;
|
|
189
|
+
if (!target || !(0, utils_1.canDrop)(dataTransfer, target, tree)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const config = tree.getConfig();
|
|
193
|
+
const draggedItems = (_b = tree.getState().dnd) === null || _b === void 0 ? void 0 : _b.draggedItems;
|
|
194
|
+
dataRef.current.lastDragCode = undefined;
|
|
195
|
+
tree.applySubStateUpdate("dnd", null);
|
|
196
|
+
if (draggedItems) {
|
|
197
|
+
yield ((_c = config.onDrop) === null || _c === void 0 ? void 0 : _c.call(config, draggedItems, target));
|
|
198
|
+
tree.getItemInstance(draggedItems[0].getId()).setFocused();
|
|
199
|
+
}
|
|
200
|
+
else if (dataTransfer) {
|
|
201
|
+
yield ((_d = config.onDropForeignDragObject) === null || _d === void 0 ? void 0 : _d.call(config, dataTransfer, target));
|
|
202
|
+
}
|
|
203
|
+
tree.applySubStateUpdate("assistiveDndState", types_1.AssistiveDndState.Completed);
|
|
204
|
+
}),
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ItemInstance, SetStateFn } from "../../types/core";
|
|
2
|
+
export interface KDndDataRef {
|
|
3
|
+
kDndDataTransfer: DataTransfer | undefined;
|
|
4
|
+
}
|
|
5
|
+
export declare enum AssistiveDndState {
|
|
6
|
+
None = 0,
|
|
7
|
+
Started = 1,
|
|
8
|
+
Dragging = 2,
|
|
9
|
+
Completed = 3,
|
|
10
|
+
Aborted = 4
|
|
11
|
+
}
|
|
12
|
+
export type KeyboardDragAndDropFeatureDef<T> = {
|
|
13
|
+
state: {
|
|
14
|
+
assistiveDndState?: AssistiveDndState | null;
|
|
15
|
+
};
|
|
16
|
+
config: {
|
|
17
|
+
setAssistiveDndState?: SetStateFn<AssistiveDndState | undefined | null>;
|
|
18
|
+
onStartKeyboardDrag?: (items: ItemInstance<T>[]) => void;
|
|
19
|
+
};
|
|
20
|
+
treeInstance: {
|
|
21
|
+
startKeyboardDrag: (items: ItemInstance<T>[]) => void;
|
|
22
|
+
startKeyboardDragOnForeignObject: (dataTransfer: DataTransfer) => void;
|
|
23
|
+
stopKeyboardDrag: () => void;
|
|
24
|
+
};
|
|
25
|
+
itemInstance: {};
|
|
26
|
+
hotkeys: "startDrag" | "cancelDrag" | "completeDrag" | "dragUp" | "dragDown";
|
|
27
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AssistiveDndState = void 0;
|
|
4
|
+
var AssistiveDndState;
|
|
5
|
+
(function (AssistiveDndState) {
|
|
6
|
+
AssistiveDndState[AssistiveDndState["None"] = 0] = "None";
|
|
7
|
+
AssistiveDndState[AssistiveDndState["Started"] = 1] = "Started";
|
|
8
|
+
AssistiveDndState[AssistiveDndState["Dragging"] = 2] = "Dragging";
|
|
9
|
+
AssistiveDndState[AssistiveDndState["Completed"] = 3] = "Completed";
|
|
10
|
+
AssistiveDndState[AssistiveDndState["Aborted"] = 4] = "Aborted";
|
|
11
|
+
})(AssistiveDndState || (exports.AssistiveDndState = AssistiveDndState = {}));
|
package/lib/cjs/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from "./core/create-tree";
|
|
|
3
3
|
export * from "./features/tree/types";
|
|
4
4
|
export { MainFeatureDef, InstanceBuilder } from "./features/main/types";
|
|
5
5
|
export * from "./features/drag-and-drop/types";
|
|
6
|
+
export * from "./features/keyboard-drag-and-drop/types";
|
|
6
7
|
export * from "./features/selection/types";
|
|
7
8
|
export * from "./features/async-data-loader/types";
|
|
8
9
|
export * from "./features/sync-data-loader/types";
|
|
@@ -16,6 +17,7 @@ export * from "./features/hotkeys-core/feature";
|
|
|
16
17
|
export * from "./features/async-data-loader/feature";
|
|
17
18
|
export * from "./features/sync-data-loader/feature";
|
|
18
19
|
export * from "./features/drag-and-drop/feature";
|
|
20
|
+
export * from "./features/keyboard-drag-and-drop/feature";
|
|
19
21
|
export * from "./features/search/feature";
|
|
20
22
|
export * from "./features/renaming/feature";
|
|
21
23
|
export * from "./features/expand-all/feature";
|
package/lib/cjs/index.js
CHANGED
|
@@ -18,6 +18,7 @@ __exportStar(require("./types/core"), exports);
|
|
|
18
18
|
__exportStar(require("./core/create-tree"), exports);
|
|
19
19
|
__exportStar(require("./features/tree/types"), exports);
|
|
20
20
|
__exportStar(require("./features/drag-and-drop/types"), exports);
|
|
21
|
+
__exportStar(require("./features/keyboard-drag-and-drop/types"), exports);
|
|
21
22
|
__exportStar(require("./features/selection/types"), exports);
|
|
22
23
|
__exportStar(require("./features/async-data-loader/types"), exports);
|
|
23
24
|
__exportStar(require("./features/sync-data-loader/types"), exports);
|
|
@@ -31,6 +32,7 @@ __exportStar(require("./features/hotkeys-core/feature"), exports);
|
|
|
31
32
|
__exportStar(require("./features/async-data-loader/feature"), exports);
|
|
32
33
|
__exportStar(require("./features/sync-data-loader/feature"), exports);
|
|
33
34
|
__exportStar(require("./features/drag-and-drop/feature"), exports);
|
|
35
|
+
__exportStar(require("./features/keyboard-drag-and-drop/feature"), exports);
|
|
34
36
|
__exportStar(require("./features/search/feature"), exports);
|
|
35
37
|
__exportStar(require("./features/renaming/feature"), exports);
|
|
36
38
|
__exportStar(require("./features/expand-all/feature"), exports);
|
|
@@ -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"];
|