@headless-tree/core 0.0.0-20250730213235 → 0.0.0-20250807163338

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 CHANGED
@@ -1,6 +1,10 @@
1
1
  # @headless-tree/core
2
2
 
3
- ## 0.0.0-20250730213235
3
+ ## 0.0.0-20250807163338
4
+
5
+ ### Minor Changes
6
+
7
+ - 21d1679: add `canDragForeignDragObjectOver` to allow customizing whether a draggable visualization should be shown when dragging foreign data. This allows differentiating logic between drag-over and drop (via the existing `canDropForeignDataObject`), since for the latter `dataTransfer.getData` is not available by default in browsers.
4
8
 
5
9
  ### Patch Changes
6
10
 
@@ -10,6 +14,7 @@
10
14
  - b41e1d2: fixed a bug where ending drag without successful drop doesn't properly reset drag line (#132)
11
15
  - b413f74: Fix `aria-posinset` and `aria-level` to be 1-based indexing
12
16
  - a250b3b: Fix a bug where expand from the initial keyboard focus fails when rootItemId is an empty string
17
+ - 62867e8: Introduced a short delay before hiding the drag line when leaving a drag target, which helps to reduce flickering of the dragline when moving between items
13
18
  - 662e2a8: Improved customizability of checkboxes feature (still alpha state), allowing you to customize `propagateCheckedState` and `canCheckFolders` independently
14
19
  - 662e2a8: Changed to new buildtool in core packages (now using tsup) to hopefully fix some ESM/CJS integrations
15
20
 
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  interface DndDataRef {
2
2
  lastDragCode?: string;
3
3
  lastAllowDrop?: boolean;
4
+ lastDragEnter?: number;
4
5
  windowDragEndListener?: () => void;
5
6
  }
6
7
  interface DndState<T> {
@@ -45,13 +46,22 @@ type DragAndDropFeatureDef<T> = {
45
46
  createForeignDragObject?: (items: ItemInstance<T>[]) => {
46
47
  format: string;
47
48
  data: any;
49
+ dropEffect?: DataTransfer["dropEffect"];
50
+ effectAllowed?: DataTransfer["effectAllowed"];
48
51
  };
49
52
  setDragImage?: (items: ItemInstance<T>[]) => {
50
53
  imgElement: Element;
51
54
  xOffset?: number;
52
55
  yOffset?: number;
53
56
  };
57
+ /** Checks if a foreign drag object can be dropped on a target, validating that an actual drop can commence based on
58
+ * the data in the DataTransfer object. */
54
59
  canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
60
+ /** Checks if a droppable visualization should be displayed when dragging a foreign object over a target. Since this
61
+ * is executed on a dragover event, `dataTransfer.getData()` is not available, so `dataTransfer.effectAllowed` or
62
+ * `dataTransfer.types` should be used instead. Before actually completing the drag, @{link canDropForeignDragObject}
63
+ * will be called by HT before applying the drop. */
64
+ canDragForeignDragObjectOver?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
55
65
  onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
56
66
  onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
57
67
  onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  interface DndDataRef {
2
2
  lastDragCode?: string;
3
3
  lastAllowDrop?: boolean;
4
+ lastDragEnter?: number;
4
5
  windowDragEndListener?: () => void;
5
6
  }
6
7
  interface DndState<T> {
@@ -45,13 +46,22 @@ type DragAndDropFeatureDef<T> = {
45
46
  createForeignDragObject?: (items: ItemInstance<T>[]) => {
46
47
  format: string;
47
48
  data: any;
49
+ dropEffect?: DataTransfer["dropEffect"];
50
+ effectAllowed?: DataTransfer["effectAllowed"];
48
51
  };
49
52
  setDragImage?: (items: ItemInstance<T>[]) => {
50
53
  imgElement: Element;
51
54
  xOffset?: number;
52
55
  yOffset?: number;
53
56
  };
57
+ /** Checks if a foreign drag object can be dropped on a target, validating that an actual drop can commence based on
58
+ * the data in the DataTransfer object. */
54
59
  canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
60
+ /** Checks if a droppable visualization should be displayed when dragging a foreign object over a target. Since this
61
+ * is executed on a dragover event, `dataTransfer.getData()` is not available, so `dataTransfer.effectAllowed` or
62
+ * `dataTransfer.types` should be used instead. Before actually completing the drag, @{link canDropForeignDragObject}
63
+ * will be called by HT before applying the drop. */
64
+ canDragForeignDragObjectOver?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
55
65
  onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
56
66
  onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
57
67
  onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
package/dist/index.js CHANGED
@@ -1372,12 +1372,14 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
1372
1372
  };
1373
1373
 
1374
1374
  // src/features/drag-and-drop/feature.ts
1375
+ var defaultCanDropForeignDragObject = () => false;
1375
1376
  var dragAndDropFeature = {
1376
1377
  key: "drag-and-drop",
1377
1378
  deps: ["selection"],
1378
1379
  getDefaultConfig: (defaultConfig, tree) => __spreadValues({
1379
1380
  canDrop: (_, target) => target.item.isFolder(),
1380
- canDropForeignDragObject: () => false,
1381
+ canDropForeignDragObject: defaultCanDropForeignDragObject,
1382
+ canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
1381
1383
  setDndState: makeStateUpdater("dnd", tree),
1382
1384
  canReorder: true
1383
1385
  }, defaultConfig),
@@ -1476,7 +1478,7 @@ var dragAndDropFeature = {
1476
1478
  draggable: true,
1477
1479
  onDragEnter: (e) => e.preventDefault(),
1478
1480
  onDragStart: (e) => {
1479
- var _a, _b, _c, _d;
1481
+ var _a, _b, _c;
1480
1482
  const selectedItems = tree.getSelectedItems();
1481
1483
  const items = selectedItems.includes(item) ? selectedItems : [item];
1482
1484
  const config = tree.getConfig();
@@ -1491,9 +1493,11 @@ var dragAndDropFeature = {
1491
1493
  const { imgElement, xOffset, yOffset } = config.setDragImage(items);
1492
1494
  (_c = e.dataTransfer) == null ? void 0 : _c.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
1493
1495
  }
1494
- if (config.createForeignDragObject) {
1495
- const { format, data } = config.createForeignDragObject(items);
1496
- (_d = e.dataTransfer) == null ? void 0 : _d.setData(format, data);
1496
+ if (config.createForeignDragObject && e.dataTransfer) {
1497
+ const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
1498
+ e.dataTransfer.setData(format, data);
1499
+ if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
1500
+ if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
1497
1501
  }
1498
1502
  tree.applySubStateUpdate("dnd", {
1499
1503
  draggedItems: items,
@@ -1502,6 +1506,7 @@ var dragAndDropFeature = {
1502
1506
  },
1503
1507
  onDragOver: (e) => {
1504
1508
  var _a, _b, _c;
1509
+ e.stopPropagation();
1505
1510
  const dataRef = tree.getDataRef();
1506
1511
  const nextDragCode = getDragCode(e, item, tree);
1507
1512
  if (nextDragCode === dataRef.current.lastDragCode) {
@@ -1511,8 +1516,9 @@ var dragAndDropFeature = {
1511
1516
  return;
1512
1517
  }
1513
1518
  dataRef.current.lastDragCode = nextDragCode;
1519
+ dataRef.current.lastDragEnter = Date.now();
1514
1520
  const target = getDragTarget(e, item, tree);
1515
- if (!((_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems) && (!e.dataTransfer || !((_c = (_b = tree.getConfig()).canDropForeignDragObject) == null ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
1521
+ if (!((_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems) && (!e.dataTransfer || !((_c = (_b = tree.getConfig()).canDragForeignDragObjectOver) == null ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
1516
1522
  dataRef.current.lastAllowDrop = false;
1517
1523
  return;
1518
1524
  }
@@ -1528,20 +1534,29 @@ var dragAndDropFeature = {
1528
1534
  e.preventDefault();
1529
1535
  },
1530
1536
  onDragLeave: () => {
1531
- const dataRef = tree.getDataRef();
1532
- dataRef.current.lastDragCode = "no-drag";
1533
- tree.applySubStateUpdate("dnd", (state) => __spreadProps(__spreadValues({}, state), {
1534
- draggingOverItem: void 0,
1535
- dragTarget: void 0
1536
- }));
1537
+ setTimeout(() => {
1538
+ var _a;
1539
+ const dataRef = tree.getDataRef();
1540
+ if (((_a = dataRef.current.lastDragEnter) != null ? _a : 0) + 100 >= Date.now()) return;
1541
+ dataRef.current.lastDragCode = "no-drag";
1542
+ tree.applySubStateUpdate("dnd", (state) => __spreadProps(__spreadValues({}, state), {
1543
+ draggingOverItem: void 0,
1544
+ dragTarget: void 0
1545
+ }));
1546
+ }, 100);
1537
1547
  },
1538
1548
  onDragEnd: (e) => {
1539
- var _a, _b, _c, _d;
1549
+ var _a, _b;
1550
+ const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
1540
1551
  const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
1541
1552
  if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
1542
1553
  return;
1543
1554
  }
1544
- (_d = (_c = tree.getConfig()).onCompleteForeignDrop) == null ? void 0 : _d.call(_c, draggedItems);
1555
+ const target = getDragTarget(e, item, tree);
1556
+ if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
1557
+ return;
1558
+ }
1559
+ onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
1545
1560
  },
1546
1561
  onDrop: (e) => __async(null, null, function* () {
1547
1562
  var _a, _b, _c;
package/dist/index.mjs CHANGED
@@ -1328,12 +1328,14 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
1328
1328
  };
1329
1329
 
1330
1330
  // src/features/drag-and-drop/feature.ts
1331
+ var defaultCanDropForeignDragObject = () => false;
1331
1332
  var dragAndDropFeature = {
1332
1333
  key: "drag-and-drop",
1333
1334
  deps: ["selection"],
1334
1335
  getDefaultConfig: (defaultConfig, tree) => __spreadValues({
1335
1336
  canDrop: (_, target) => target.item.isFolder(),
1336
- canDropForeignDragObject: () => false,
1337
+ canDropForeignDragObject: defaultCanDropForeignDragObject,
1338
+ canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
1337
1339
  setDndState: makeStateUpdater("dnd", tree),
1338
1340
  canReorder: true
1339
1341
  }, defaultConfig),
@@ -1432,7 +1434,7 @@ var dragAndDropFeature = {
1432
1434
  draggable: true,
1433
1435
  onDragEnter: (e) => e.preventDefault(),
1434
1436
  onDragStart: (e) => {
1435
- var _a, _b, _c, _d;
1437
+ var _a, _b, _c;
1436
1438
  const selectedItems = tree.getSelectedItems();
1437
1439
  const items = selectedItems.includes(item) ? selectedItems : [item];
1438
1440
  const config = tree.getConfig();
@@ -1447,9 +1449,11 @@ var dragAndDropFeature = {
1447
1449
  const { imgElement, xOffset, yOffset } = config.setDragImage(items);
1448
1450
  (_c = e.dataTransfer) == null ? void 0 : _c.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
1449
1451
  }
1450
- if (config.createForeignDragObject) {
1451
- const { format, data } = config.createForeignDragObject(items);
1452
- (_d = e.dataTransfer) == null ? void 0 : _d.setData(format, data);
1452
+ if (config.createForeignDragObject && e.dataTransfer) {
1453
+ const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
1454
+ e.dataTransfer.setData(format, data);
1455
+ if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
1456
+ if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
1453
1457
  }
1454
1458
  tree.applySubStateUpdate("dnd", {
1455
1459
  draggedItems: items,
@@ -1458,6 +1462,7 @@ var dragAndDropFeature = {
1458
1462
  },
1459
1463
  onDragOver: (e) => {
1460
1464
  var _a, _b, _c;
1465
+ e.stopPropagation();
1461
1466
  const dataRef = tree.getDataRef();
1462
1467
  const nextDragCode = getDragCode(e, item, tree);
1463
1468
  if (nextDragCode === dataRef.current.lastDragCode) {
@@ -1467,8 +1472,9 @@ var dragAndDropFeature = {
1467
1472
  return;
1468
1473
  }
1469
1474
  dataRef.current.lastDragCode = nextDragCode;
1475
+ dataRef.current.lastDragEnter = Date.now();
1470
1476
  const target = getDragTarget(e, item, tree);
1471
- if (!((_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems) && (!e.dataTransfer || !((_c = (_b = tree.getConfig()).canDropForeignDragObject) == null ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
1477
+ if (!((_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems) && (!e.dataTransfer || !((_c = (_b = tree.getConfig()).canDragForeignDragObjectOver) == null ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
1472
1478
  dataRef.current.lastAllowDrop = false;
1473
1479
  return;
1474
1480
  }
@@ -1484,20 +1490,29 @@ var dragAndDropFeature = {
1484
1490
  e.preventDefault();
1485
1491
  },
1486
1492
  onDragLeave: () => {
1487
- const dataRef = tree.getDataRef();
1488
- dataRef.current.lastDragCode = "no-drag";
1489
- tree.applySubStateUpdate("dnd", (state) => __spreadProps(__spreadValues({}, state), {
1490
- draggingOverItem: void 0,
1491
- dragTarget: void 0
1492
- }));
1493
+ setTimeout(() => {
1494
+ var _a;
1495
+ const dataRef = tree.getDataRef();
1496
+ if (((_a = dataRef.current.lastDragEnter) != null ? _a : 0) + 100 >= Date.now()) return;
1497
+ dataRef.current.lastDragCode = "no-drag";
1498
+ tree.applySubStateUpdate("dnd", (state) => __spreadProps(__spreadValues({}, state), {
1499
+ draggingOverItem: void 0,
1500
+ dragTarget: void 0
1501
+ }));
1502
+ }, 100);
1493
1503
  },
1494
1504
  onDragEnd: (e) => {
1495
- var _a, _b, _c, _d;
1505
+ var _a, _b;
1506
+ const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
1496
1507
  const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
1497
1508
  if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
1498
1509
  return;
1499
1510
  }
1500
- (_d = (_c = tree.getConfig()).onCompleteForeignDrop) == null ? void 0 : _d.call(_c, draggedItems);
1511
+ const target = getDragTarget(e, item, tree);
1512
+ if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
1513
+ return;
1514
+ }
1515
+ onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
1501
1516
  },
1502
1517
  onDrop: (e) => __async(null, null, function* () {
1503
1518
  var _a, _b, _c;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@headless-tree/core",
3
- "version": "0.0.0-20250730213235",
3
+ "version": "0.0.0-20250807163338",
4
4
  "main": "dist/index.d.ts",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.mts",
@@ -300,6 +300,9 @@ describe("core-feature/drag-and-drop", () => {
300
300
 
301
301
  it("drags foreign object inside tree, on folder", () => {
302
302
  tree.mockedHandler("canDropForeignDragObject").mockReturnValue(true);
303
+ tree
304
+ .mockedHandler("canDragForeignDragObjectOver")
305
+ .mockReturnValue(true);
303
306
  const onDropForeignDragObject = tree.mockedHandler(
304
307
  "onDropForeignDragObject",
305
308
  );
@@ -318,6 +321,9 @@ describe("core-feature/drag-and-drop", () => {
318
321
  tree
319
322
  .mockedHandler("canDropForeignDragObject")
320
323
  .mockImplementation((_, target) => target.item.isFolder());
324
+ tree
325
+ .mockedHandler("canDragForeignDragObjectOver")
326
+ .mockImplementation((_, target) => target.item.isFolder());
321
327
  const onDropForeignDragObject = tree.mockedHandler(
322
328
  "onDropForeignDragObject",
323
329
  );
@@ -340,6 +346,9 @@ describe("core-feature/drag-and-drop", () => {
340
346
 
341
347
  it("doesnt drag foreign object inside tree if not allowed", () => {
342
348
  tree.mockedHandler("canDropForeignDragObject").mockReturnValue(false);
349
+ tree
350
+ .mockedHandler("canDragForeignDragObjectOver")
351
+ .mockReturnValue(false);
343
352
  const onDropForeignDragObject = tree.mockedHandler(
344
353
  "onDropForeignDragObject",
345
354
  );
@@ -8,13 +8,18 @@ import {
8
8
  } from "./utils";
9
9
  import { makeStateUpdater } from "../../utils";
10
10
 
11
+ const defaultCanDropForeignDragObject = () => false;
11
12
  export const dragAndDropFeature: FeatureImplementation = {
12
13
  key: "drag-and-drop",
13
14
  deps: ["selection"],
14
15
 
15
16
  getDefaultConfig: (defaultConfig, tree) => ({
16
17
  canDrop: (_, target) => target.item.isFolder(),
17
- canDropForeignDragObject: () => false,
18
+ canDropForeignDragObject: defaultCanDropForeignDragObject,
19
+ canDragForeignDragObjectOver:
20
+ defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject
21
+ ? (dataTransfer) => dataTransfer.effectAllowed !== "none"
22
+ : () => false,
18
23
  setDndState: makeStateUpdater("dnd", tree),
19
24
  canReorder: true,
20
25
  ...defaultConfig,
@@ -162,9 +167,13 @@ export const dragAndDropFeature: FeatureImplementation = {
162
167
  e.dataTransfer?.setDragImage(imgElement, xOffset ?? 0, yOffset ?? 0);
163
168
  }
164
169
 
165
- if (config.createForeignDragObject) {
166
- const { format, data } = config.createForeignDragObject(items);
167
- e.dataTransfer?.setData(format, data);
170
+ if (config.createForeignDragObject && e.dataTransfer) {
171
+ const { format, data, dropEffect, effectAllowed } =
172
+ config.createForeignDragObject(items);
173
+ e.dataTransfer.setData(format, data);
174
+
175
+ if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
176
+ if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
168
177
  }
169
178
 
170
179
  tree.applySubStateUpdate("dnd", {
@@ -174,6 +183,7 @@ export const dragAndDropFeature: FeatureImplementation = {
174
183
  },
175
184
 
176
185
  onDragOver: (e: DragEvent) => {
186
+ e.stopPropagation(); // don't bubble up to container dragover
177
187
  const dataRef = tree.getDataRef<DndDataRef>();
178
188
  const nextDragCode = getDragCode(e, item, tree);
179
189
  if (nextDragCode === dataRef.current.lastDragCode) {
@@ -183,6 +193,7 @@ export const dragAndDropFeature: FeatureImplementation = {
183
193
  return;
184
194
  }
185
195
  dataRef.current.lastDragCode = nextDragCode;
196
+ dataRef.current.lastDragEnter = Date.now();
186
197
 
187
198
  const target = getDragTarget(e, item, tree);
188
199
 
@@ -191,7 +202,7 @@ export const dragAndDropFeature: FeatureImplementation = {
191
202
  (!e.dataTransfer ||
192
203
  !tree
193
204
  .getConfig()
194
- .canDropForeignDragObject?.(e.dataTransfer, target))
205
+ .canDragForeignDragObjectOver?.(e.dataTransfer, target))
195
206
  ) {
196
207
  dataRef.current.lastAllowDrop = false;
197
208
  return;
@@ -212,23 +223,37 @@ export const dragAndDropFeature: FeatureImplementation = {
212
223
  },
213
224
 
214
225
  onDragLeave: () => {
215
- const dataRef = tree.getDataRef<DndDataRef>();
216
- dataRef.current.lastDragCode = "no-drag";
217
- tree.applySubStateUpdate("dnd", (state) => ({
218
- ...state,
219
- draggingOverItem: undefined,
220
- dragTarget: undefined,
221
- }));
226
+ setTimeout(() => {
227
+ const dataRef = tree.getDataRef<DndDataRef>();
228
+ if ((dataRef.current.lastDragEnter ?? 0) + 100 >= Date.now()) return;
229
+ dataRef.current.lastDragCode = "no-drag";
230
+ tree.applySubStateUpdate("dnd", (state) => ({
231
+ ...state,
232
+ draggingOverItem: undefined,
233
+ dragTarget: undefined,
234
+ }));
235
+ }, 100);
222
236
  },
223
237
 
224
238
  onDragEnd: (e: DragEvent) => {
239
+ const { onCompleteForeignDrop, canDragForeignDragObjectOver } =
240
+ tree.getConfig();
225
241
  const draggedItems = tree.getState().dnd?.draggedItems;
226
242
 
227
243
  if (e.dataTransfer?.dropEffect === "none" || !draggedItems) {
228
244
  return;
229
245
  }
230
246
 
231
- tree.getConfig().onCompleteForeignDrop?.(draggedItems);
247
+ const target = getDragTarget(e, item, tree);
248
+ if (
249
+ canDragForeignDragObjectOver &&
250
+ e.dataTransfer &&
251
+ !canDragForeignDragObjectOver(e.dataTransfer, target)
252
+ ) {
253
+ return;
254
+ }
255
+
256
+ onCompleteForeignDrop?.(draggedItems);
232
257
  },
233
258
 
234
259
  onDrop: async (e: DragEvent) => {
@@ -3,6 +3,7 @@ import { ItemInstance, SetStateFn } from "../../types/core";
3
3
  export interface DndDataRef {
4
4
  lastDragCode?: string;
5
5
  lastAllowDrop?: boolean;
6
+ lastDragEnter?: number;
6
7
  windowDragEndListener?: () => void;
7
8
  }
8
9
 
@@ -58,16 +59,31 @@ export type DragAndDropFeatureDef<T> = {
58
59
  createForeignDragObject?: (items: ItemInstance<T>[]) => {
59
60
  format: string;
60
61
  data: any;
62
+ dropEffect?: DataTransfer["dropEffect"];
63
+ effectAllowed?: DataTransfer["effectAllowed"];
61
64
  };
62
65
  setDragImage?: (items: ItemInstance<T>[]) => {
63
66
  imgElement: Element;
64
67
  xOffset?: number;
65
68
  yOffset?: number;
66
69
  };
70
+
71
+ /** Checks if a foreign drag object can be dropped on a target, validating that an actual drop can commence based on
72
+ * the data in the DataTransfer object. */
67
73
  canDropForeignDragObject?: (
68
74
  dataTransfer: DataTransfer,
69
75
  target: DragTarget<T>,
70
76
  ) => boolean;
77
+
78
+ /** Checks if a droppable visualization should be displayed when dragging a foreign object over a target. Since this
79
+ * is executed on a dragover event, `dataTransfer.getData()` is not available, so `dataTransfer.effectAllowed` or
80
+ * `dataTransfer.types` should be used instead. Before actually completing the drag, @{link canDropForeignDragObject}
81
+ * will be called by HT before applying the drop. */
82
+ canDragForeignDragObjectOver?: (
83
+ dataTransfer: DataTransfer,
84
+ target: DragTarget<T>,
85
+ ) => boolean;
86
+
71
87
  onDrop?: (
72
88
  items: ItemInstance<T>[],
73
89
  target: DragTarget<T>,