@mk-drag-and-drop/dom 0.1.0 → 0.2.0
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/README.md +56 -32
- package/dist/controller/controller-internals.d.ts +4 -4
- package/dist/controller/create-drag-controller.d.ts +8 -8
- package/dist/controller/create-drag-controller.js +23 -53
- package/dist/draggable/create-draggable-binding.js +3 -3
- package/dist/droppable/create-drop-container-binding.js +4 -4
- package/dist/droppable/create-drop-container.d.ts +1 -1
- package/dist/droppable/create-drop-container.js +3 -3
- package/dist/droppable/create-droppable-binding.js +4 -4
- package/dist/droppable/create-droppable.d.ts +1 -1
- package/dist/droppable/create-droppable.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/input/pointer-activation.d.ts +4 -2
- package/dist/input/pointer-activation.js +28 -16
- package/dist/integration/index.d.ts +2 -2
- package/dist/integration/index.js +1 -1
- package/dist/runtime/drag-runtime-scope.d.ts +21 -0
- package/dist/runtime/{drag-runtime-handle.js → drag-runtime-scope.js} +8 -9
- package/dist/runtime/drag-runtime.d.ts +21 -17
- package/dist/runtime/drag-runtime.js +274 -155
- package/dist/runtime/lifecycle.d.ts +5 -0
- package/dist/runtime/types.d.ts +3 -2
- package/dist/sortable/create-sortable-binding.js +4 -4
- package/dist/sortable/create-sortable.d.ts +1 -1
- package/dist/sortable/create-sortable.js +3 -3
- package/dist/sortable/sortable-preview.js +20 -17
- package/dist/sortable/sortable-registry.d.ts +15 -6
- package/dist/sortable/sortable-registry.js +65 -47
- package/package.json +1 -1
- package/dist/runtime/drag-runtime-handle.d.ts +0 -22
|
@@ -16,13 +16,12 @@ export class DragRuntime {
|
|
|
16
16
|
session = { status: "idle" };
|
|
17
17
|
modifiers = [];
|
|
18
18
|
activeDragModifiers = [];
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
releaseActiveInputListeners = null;
|
|
20
|
+
restoreTextSelectionSuppression = null;
|
|
21
21
|
queuedPointerPosition = null;
|
|
22
22
|
pointerFrameId = null;
|
|
23
23
|
subscriptions = new Set();
|
|
24
|
-
|
|
25
|
-
bindingCleanupRecords = new Set();
|
|
24
|
+
staleDomBindingRecords = new Set();
|
|
26
25
|
lifecycleCallbacks = {};
|
|
27
26
|
lifecycleHelpers = {
|
|
28
27
|
getDropTargetRect: (dropTargetId) => this.getLifecycleDropTargetRect(dropTargetId),
|
|
@@ -37,7 +36,7 @@ export class DragRuntime {
|
|
|
37
36
|
updateOverlayHost;
|
|
38
37
|
targetingAlgorithm;
|
|
39
38
|
hasDragOverlay;
|
|
40
|
-
|
|
39
|
+
overlayRelease;
|
|
41
40
|
targetingConstraint;
|
|
42
41
|
pointerActivation = new PointerActivationController({
|
|
43
42
|
getConfiguration: () => this.pointerConfiguration,
|
|
@@ -96,12 +95,12 @@ export class DragRuntime {
|
|
|
96
95
|
this.updateOverlayHost = options.updateOverlayHost ?? noopUpdateOverlayHost;
|
|
97
96
|
this.targetingAlgorithm = options.targetingAlgorithm ?? pointerToCenter;
|
|
98
97
|
this.hasDragOverlay = options.hasDragOverlay ?? false;
|
|
99
|
-
this.
|
|
98
|
+
this.overlayRelease = options.overlayRelease ?? "auto";
|
|
100
99
|
this.targetingConstraint = options.targetingConstraint;
|
|
101
100
|
}
|
|
102
101
|
configure(input) {
|
|
103
102
|
this.hasDragOverlay = input.hasDragOverlay;
|
|
104
|
-
this.
|
|
103
|
+
this.overlayRelease = input.overlayRelease;
|
|
105
104
|
this.targetingAlgorithm = input.targetingAlgorithm;
|
|
106
105
|
this.targetingConstraint = input.targetingConstraint;
|
|
107
106
|
this.lifecycleCallbacks = input.lifecycleCallbacks;
|
|
@@ -110,7 +109,7 @@ export class DragRuntime {
|
|
|
110
109
|
this.pointerConfiguration = normalizePointerConfiguration(input.pointerConfiguration);
|
|
111
110
|
}
|
|
112
111
|
requestDragStart(input) {
|
|
113
|
-
this.
|
|
112
|
+
this.pruneDisconnectedDomBindings();
|
|
114
113
|
this.pointerActivation.request(input);
|
|
115
114
|
}
|
|
116
115
|
isKeyboardDragEnabled() {
|
|
@@ -120,8 +119,8 @@ export class DragRuntime {
|
|
|
120
119
|
return this.keyboardDrag.handleSourceKeyDown(input);
|
|
121
120
|
}
|
|
122
121
|
requestKeyboardDragStart(input) {
|
|
123
|
-
this.
|
|
124
|
-
this.
|
|
122
|
+
this.pruneDisconnectedDomBindings();
|
|
123
|
+
this.cancelPendingActivation();
|
|
125
124
|
if (this.isDragging ||
|
|
126
125
|
!this.keyboardDrag.isEnabled() ||
|
|
127
126
|
!input.element.isConnected) {
|
|
@@ -162,7 +161,7 @@ export class DragRuntime {
|
|
|
162
161
|
else {
|
|
163
162
|
pointerPosition.x += distance;
|
|
164
163
|
}
|
|
165
|
-
this.
|
|
164
|
+
this.updatePointerNowOrRelease(pointerPosition);
|
|
166
165
|
}
|
|
167
166
|
updatePointer(rawPointerPosition) {
|
|
168
167
|
if (this.session.status !== "dragging") {
|
|
@@ -177,7 +176,7 @@ export class DragRuntime {
|
|
|
177
176
|
const nextPointerPosition = this.queuedPointerPosition;
|
|
178
177
|
this.queuedPointerPosition = null;
|
|
179
178
|
if (nextPointerPosition) {
|
|
180
|
-
this.
|
|
179
|
+
this.updatePointerNowOrRelease(nextPointerPosition);
|
|
181
180
|
}
|
|
182
181
|
});
|
|
183
182
|
}
|
|
@@ -230,20 +229,38 @@ export class DragRuntime {
|
|
|
230
229
|
placementPosition: sortablePlacementPosition,
|
|
231
230
|
});
|
|
232
231
|
}
|
|
232
|
+
updatePointerNowOrRelease(rawPointerPosition) {
|
|
233
|
+
try {
|
|
234
|
+
this.updatePointerNow(rawPointerPosition);
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
this.releaseActiveDragResourcesAndRethrow(error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
finishDragAfterQueuedPointerUpdate(input) {
|
|
241
|
+
try {
|
|
242
|
+
this.flushQueuedPointerUpdate();
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
this.releaseActiveDragResourcesAndRethrow(error);
|
|
246
|
+
}
|
|
247
|
+
this.finishDrag(input);
|
|
248
|
+
}
|
|
233
249
|
endDrag() {
|
|
234
|
-
this.
|
|
235
|
-
this.finishDrag({
|
|
250
|
+
this.finishDragAfterQueuedPointerUpdate({
|
|
236
251
|
reason: "drop",
|
|
237
|
-
|
|
252
|
+
overlayRelease: this.overlayRelease,
|
|
238
253
|
});
|
|
239
254
|
}
|
|
240
255
|
cancelDrag() {
|
|
241
|
-
this.
|
|
242
|
-
this.finishDrag({
|
|
256
|
+
this.finishDragAfterQueuedPointerUpdate({
|
|
243
257
|
reason: "cancel",
|
|
244
|
-
|
|
258
|
+
overlayRelease: this.overlayRelease,
|
|
245
259
|
});
|
|
246
260
|
}
|
|
261
|
+
cancelPendingActivation() {
|
|
262
|
+
this.pointerActivation.cancelPendingActivation();
|
|
263
|
+
}
|
|
247
264
|
registerDropTarget(dropTargetId, element, group, options) {
|
|
248
265
|
const removedTargets = this.dropTargetRegistry.register(dropTargetId, element, group, options);
|
|
249
266
|
this.clearActiveDropTargetIdIfRemoved(removedTargets);
|
|
@@ -263,12 +280,53 @@ export class DragRuntime {
|
|
|
263
280
|
const removedTargets = this.dropTargetRegistry.unregister(containerId, element);
|
|
264
281
|
this.clearActiveDropTargetIdIfRemoved(removedTargets);
|
|
265
282
|
}
|
|
266
|
-
|
|
267
|
-
this.
|
|
283
|
+
releaseActiveDragResources() {
|
|
284
|
+
const activeSession = this.getDraggingSession();
|
|
285
|
+
this.cancelPendingActivation();
|
|
286
|
+
let firstReleaseError;
|
|
287
|
+
let hasReleaseError = false;
|
|
288
|
+
if (activeSession) {
|
|
289
|
+
try {
|
|
290
|
+
this.notifyActiveDragReset({
|
|
291
|
+
draggableId: activeSession.draggableId,
|
|
292
|
+
source: activeSession.source,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
firstReleaseError = error;
|
|
297
|
+
hasReleaseError = true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
268
300
|
this.resetActiveDragState();
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
301
|
+
try {
|
|
302
|
+
this.releaseActiveInputResources();
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
firstReleaseError = error;
|
|
306
|
+
hasReleaseError = true;
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
this.clearOverlayHost();
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
if (!hasReleaseError) {
|
|
313
|
+
firstReleaseError = error;
|
|
314
|
+
hasReleaseError = true;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (hasReleaseError) {
|
|
318
|
+
throw firstReleaseError;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
releaseActiveDragResourcesAndRethrow(error) {
|
|
322
|
+
try {
|
|
323
|
+
this.releaseActiveDragResources();
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// Preserve the original failure while still making a best effort to
|
|
327
|
+
// release resources that were acquired before it was thrown.
|
|
328
|
+
}
|
|
329
|
+
throw error;
|
|
272
330
|
}
|
|
273
331
|
getDropTargetRect(dropTargetId) {
|
|
274
332
|
return this.dropTargetRegistry.getViewportRect(dropTargetId);
|
|
@@ -302,16 +360,16 @@ export class DragRuntime {
|
|
|
302
360
|
...session,
|
|
303
361
|
overlayMeasurement,
|
|
304
362
|
});
|
|
305
|
-
this.
|
|
363
|
+
this.updatePointerNowOrRelease(session.rawPointerPosition);
|
|
306
364
|
}
|
|
307
365
|
remeasureDropTargets(input) {
|
|
308
366
|
const pruneGroup = input !== undefined && typeof input !== "string" && !Array.isArray(input)
|
|
309
367
|
? input.group
|
|
310
368
|
: undefined;
|
|
311
|
-
this.
|
|
369
|
+
this.pruneDisconnectedDomBindings();
|
|
312
370
|
this.removeDisconnectedDropTargets(pruneGroup);
|
|
313
371
|
this.dropTargetRegistry.remeasure(input);
|
|
314
|
-
this.
|
|
372
|
+
this.pruneDisconnectedDomBindings();
|
|
315
373
|
}
|
|
316
374
|
subscribe(subscription) {
|
|
317
375
|
this.subscriptions.add(subscription);
|
|
@@ -319,121 +377,110 @@ export class DragRuntime {
|
|
|
319
377
|
this.subscriptions.delete(subscription);
|
|
320
378
|
};
|
|
321
379
|
}
|
|
322
|
-
|
|
323
|
-
this.disposeCallbacks.add(callback);
|
|
324
|
-
return () => {
|
|
325
|
-
this.disposeCallbacks.delete(callback);
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
registerBindingCleanup(record) {
|
|
380
|
+
registerStaleDomBinding(record) {
|
|
329
381
|
const storedRecord = {
|
|
330
382
|
record,
|
|
331
383
|
hasBeenConnected: record.isConnected(),
|
|
332
384
|
};
|
|
333
|
-
// Keep registration O(1). Full
|
|
334
|
-
//
|
|
335
|
-
this.
|
|
385
|
+
// Keep registration O(1). Full stale DOM pruning runs on drag lifecycle and
|
|
386
|
+
// explicit remeasurement paths so bulk renders do not rescan prior bindings.
|
|
387
|
+
this.staleDomBindingRecords.add(storedRecord);
|
|
336
388
|
return () => {
|
|
337
|
-
if (!this.
|
|
389
|
+
if (!this.staleDomBindingRecords.delete(storedRecord)) {
|
|
338
390
|
return;
|
|
339
391
|
}
|
|
340
|
-
record.
|
|
392
|
+
record.release();
|
|
341
393
|
};
|
|
342
394
|
}
|
|
343
|
-
|
|
344
|
-
this.
|
|
395
|
+
pruneDisconnectedDomBindings() {
|
|
396
|
+
this.pruneDisconnectedDomBindingRecords();
|
|
345
397
|
}
|
|
346
|
-
|
|
347
|
-
return this.
|
|
348
|
-
}
|
|
349
|
-
dispose() {
|
|
350
|
-
this.cleanup();
|
|
351
|
-
this.disposeBindingCleanupRecords();
|
|
352
|
-
for (const disposeCallback of Array.from(this.disposeCallbacks)) {
|
|
353
|
-
disposeCallback();
|
|
354
|
-
}
|
|
355
|
-
this.disposeCallbacks.clear();
|
|
356
|
-
this.subscriptions.clear();
|
|
357
|
-
this.dropTargetRegistry.clear();
|
|
358
|
-
this.lifecycleCallbacks = {};
|
|
359
|
-
this.modifiers = [];
|
|
360
|
-
this.updateOverlayHost = noopUpdateOverlayHost;
|
|
398
|
+
getStaleDomBindingRecordCount() {
|
|
399
|
+
return this.staleDomBindingRecords.size;
|
|
361
400
|
}
|
|
362
401
|
startDragNow(input) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
402
|
+
this.cancelPendingActivation();
|
|
403
|
+
try {
|
|
404
|
+
if (this.targetingAlgorithm.mode === "rect" && !this.hasDragOverlay) {
|
|
405
|
+
throw new Error("The selected targeting algorithm requires a drag overlay. Provide dragOverlay or use a pointer-based targeting algorithm.");
|
|
406
|
+
}
|
|
407
|
+
this.pruneDisconnectedDomBindings();
|
|
408
|
+
const rawPointerPosition = input.pointerPosition;
|
|
409
|
+
const activeDragModifiers = createActiveDragModifiers({
|
|
410
|
+
modifiers: this.modifiers,
|
|
411
|
+
setupInput: {
|
|
412
|
+
draggableId: input.draggableId,
|
|
413
|
+
group: input.group,
|
|
414
|
+
sourceRect: input.sourceRect,
|
|
415
|
+
initialPointerPosition: rawPointerPosition,
|
|
416
|
+
},
|
|
417
|
+
});
|
|
418
|
+
this.activeDragModifiers = activeDragModifiers;
|
|
419
|
+
const effectivePointerPosition = applyDragModifiers({
|
|
420
|
+
activeModifiers: activeDragModifiers,
|
|
371
421
|
draggableId: input.draggableId,
|
|
372
422
|
group: input.group,
|
|
373
423
|
sourceRect: input.sourceRect,
|
|
374
424
|
initialPointerPosition: rawPointerPosition,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
425
|
+
rawPointerPosition,
|
|
426
|
+
});
|
|
427
|
+
const sourceContainerId = this.dropTargetRegistry.getDropTargetRegistration(input.draggableId, input.group)?.containerId ?? null;
|
|
428
|
+
const sourceSortablePlacement = this.dropTargetRegistry.getSortableItemPlacement(input.draggableId, input.group);
|
|
429
|
+
const nextSession = {
|
|
430
|
+
status: "dragging",
|
|
431
|
+
source: input.inputType,
|
|
432
|
+
draggableId: input.draggableId,
|
|
433
|
+
group: input.group,
|
|
434
|
+
sourceRect: input.sourceRect,
|
|
435
|
+
sourceContainerId,
|
|
436
|
+
sourceSortablePlacement,
|
|
437
|
+
overlayMeasurement: null,
|
|
438
|
+
startPointerPosition: rawPointerPosition,
|
|
439
|
+
rawPointerPosition,
|
|
440
|
+
pointerPosition: effectivePointerPosition,
|
|
441
|
+
activeDropTargetId: null,
|
|
442
|
+
};
|
|
443
|
+
this.setSession(nextSession);
|
|
444
|
+
this.remeasureDropTargets({ group: input.group });
|
|
445
|
+
const dragStartEvent = {
|
|
446
|
+
draggableId: input.draggableId,
|
|
447
|
+
source: input.inputType,
|
|
448
|
+
pointerPosition: effectivePointerPosition,
|
|
449
|
+
sourceRect: input.sourceRect,
|
|
450
|
+
};
|
|
451
|
+
const startOverlayRect = this.hasDragOverlay
|
|
452
|
+
? this.getCurrentDragRectAt(effectivePointerPosition)
|
|
453
|
+
: null;
|
|
454
|
+
const dragStartSubscriptionEvent = {
|
|
455
|
+
...dragStartEvent,
|
|
456
|
+
placementPosition: this.getSortablePlacementPosition({
|
|
457
|
+
pointerPosition: effectivePointerPosition,
|
|
458
|
+
overlayRect: startOverlayRect,
|
|
459
|
+
}),
|
|
460
|
+
};
|
|
461
|
+
this.notifyDragStartSubscriptions(dragStartSubscriptionEvent);
|
|
462
|
+
this.updateOverlayHost({
|
|
463
|
+
type: "mount",
|
|
464
|
+
state: {
|
|
465
|
+
dragState: this.createDragState(nextSession),
|
|
466
|
+
phase: "dragging",
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
this.suppressTextSelection();
|
|
470
|
+
if (input.inputType === "pointer") {
|
|
471
|
+
this.bindPointerWindowListeners(input.pointerId);
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
this.bindKeyboardWindowListeners();
|
|
475
|
+
}
|
|
476
|
+
this.notifyDragStartLifecycle(dragStartEvent);
|
|
414
477
|
}
|
|
415
|
-
|
|
416
|
-
this.
|
|
478
|
+
catch (error) {
|
|
479
|
+
this.releaseActiveDragResourcesAndRethrow(error);
|
|
417
480
|
}
|
|
418
|
-
const dragStartEvent = {
|
|
419
|
-
draggableId: input.draggableId,
|
|
420
|
-
source: input.inputType,
|
|
421
|
-
pointerPosition: effectivePointerPosition,
|
|
422
|
-
sourceRect: input.sourceRect,
|
|
423
|
-
};
|
|
424
|
-
const startOverlayRect = this.hasDragOverlay
|
|
425
|
-
? this.getCurrentDragRectAt(effectivePointerPosition)
|
|
426
|
-
: null;
|
|
427
|
-
this.notifyDragStart(dragStartEvent, {
|
|
428
|
-
...dragStartEvent,
|
|
429
|
-
placementPosition: this.getSortablePlacementPosition({
|
|
430
|
-
pointerPosition: effectivePointerPosition,
|
|
431
|
-
overlayRect: startOverlayRect,
|
|
432
|
-
}),
|
|
433
|
-
});
|
|
434
481
|
}
|
|
435
482
|
finishDrag(input) {
|
|
436
|
-
this.
|
|
483
|
+
this.cancelPendingActivation();
|
|
437
484
|
const session = this.getDraggingSession();
|
|
438
485
|
const releasedDragState = session
|
|
439
486
|
? this.createDragState(session)
|
|
@@ -462,7 +509,15 @@ export class DragRuntime {
|
|
|
462
509
|
})
|
|
463
510
|
: null;
|
|
464
511
|
this.resetActiveDragState();
|
|
465
|
-
|
|
512
|
+
let finishError;
|
|
513
|
+
let hasFinishError = false;
|
|
514
|
+
try {
|
|
515
|
+
this.releaseActiveInputResources();
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
finishError = error;
|
|
519
|
+
hasFinishError = true;
|
|
520
|
+
}
|
|
466
521
|
if (session && result) {
|
|
467
522
|
this.lifecycleDropTargetRectSnapshot = lifecycleDropTargetRectSnapshot;
|
|
468
523
|
try {
|
|
@@ -481,25 +536,60 @@ export class DragRuntime {
|
|
|
481
536
|
});
|
|
482
537
|
}
|
|
483
538
|
}
|
|
539
|
+
catch (error) {
|
|
540
|
+
finishError = error;
|
|
541
|
+
hasFinishError = true;
|
|
542
|
+
}
|
|
484
543
|
finally {
|
|
485
544
|
this.lifecycleDropTargetRectSnapshot = null;
|
|
486
545
|
}
|
|
487
546
|
}
|
|
488
|
-
|
|
489
|
-
this.
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
dragState: releasedDragState,
|
|
493
|
-
phase: "released",
|
|
494
|
-
},
|
|
547
|
+
try {
|
|
548
|
+
this.releaseOverlayAfterDrag({
|
|
549
|
+
overlayRelease: input.overlayRelease,
|
|
550
|
+
releasedDragState,
|
|
495
551
|
});
|
|
496
552
|
}
|
|
497
|
-
|
|
498
|
-
|
|
553
|
+
catch (error) {
|
|
554
|
+
if (!hasFinishError) {
|
|
555
|
+
finishError = error;
|
|
556
|
+
hasFinishError = true;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (hasFinishError) {
|
|
560
|
+
throw finishError;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
releaseOverlayAfterDrag(input) {
|
|
564
|
+
if (input.overlayRelease === "manual" &&
|
|
565
|
+
input.releasedDragState &&
|
|
566
|
+
this.hasDragOverlay) {
|
|
567
|
+
try {
|
|
568
|
+
this.updateOverlayHost({
|
|
569
|
+
type: "release",
|
|
570
|
+
state: {
|
|
571
|
+
dragState: input.releasedDragState,
|
|
572
|
+
phase: "released",
|
|
573
|
+
},
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
catch (error) {
|
|
577
|
+
try {
|
|
578
|
+
this.clearOverlayHost();
|
|
579
|
+
}
|
|
580
|
+
catch {
|
|
581
|
+
// Preserve the overlay release error while still making a best effort
|
|
582
|
+
// to clear the host state.
|
|
583
|
+
}
|
|
584
|
+
throw error;
|
|
585
|
+
}
|
|
586
|
+
return;
|
|
499
587
|
}
|
|
588
|
+
this.clearOverlayHost();
|
|
500
589
|
}
|
|
501
590
|
bindPointerWindowListeners(pointerId) {
|
|
502
|
-
this.
|
|
591
|
+
this.releaseActiveInputListeners?.();
|
|
592
|
+
let listenersReleased = false;
|
|
503
593
|
const handlePointerMove = (event) => {
|
|
504
594
|
if (event.pointerId !== pointerId) {
|
|
505
595
|
return;
|
|
@@ -524,25 +614,29 @@ export class DragRuntime {
|
|
|
524
614
|
window.addEventListener("pointermove", handlePointerMove);
|
|
525
615
|
window.addEventListener("pointerup", handlePointerUp);
|
|
526
616
|
window.addEventListener("pointercancel", handlePointerCancel);
|
|
527
|
-
this.
|
|
617
|
+
this.releaseActiveInputListeners = () => {
|
|
618
|
+
if (listenersReleased) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
listenersReleased = true;
|
|
528
622
|
window.removeEventListener("pointermove", handlePointerMove);
|
|
529
623
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
530
624
|
window.removeEventListener("pointercancel", handlePointerCancel);
|
|
531
625
|
};
|
|
532
626
|
}
|
|
533
627
|
bindKeyboardWindowListeners() {
|
|
534
|
-
this.
|
|
535
|
-
this.
|
|
628
|
+
this.releaseActiveInputListeners?.();
|
|
629
|
+
this.releaseActiveInputListeners = this.keyboardDrag.bindWindowListeners();
|
|
536
630
|
}
|
|
537
631
|
suppressTextSelection() {
|
|
538
|
-
this.
|
|
632
|
+
this.restoreTextSelectionSuppression?.();
|
|
539
633
|
const root = document.documentElement;
|
|
540
634
|
const body = document.body;
|
|
541
635
|
const previousRootUserSelect = root.style.userSelect;
|
|
542
636
|
const previousBodyUserSelect = body.style.userSelect;
|
|
543
637
|
root.style.userSelect = "none";
|
|
544
638
|
body.style.userSelect = "none";
|
|
545
|
-
this.
|
|
639
|
+
this.restoreTextSelectionSuppression = () => {
|
|
546
640
|
root.style.userSelect = previousRootUserSelect;
|
|
547
641
|
body.style.userSelect = previousBodyUserSelect;
|
|
548
642
|
};
|
|
@@ -552,11 +646,35 @@ export class DragRuntime {
|
|
|
552
646
|
this.setSession({ status: "idle" });
|
|
553
647
|
this.activeDragModifiers = [];
|
|
554
648
|
}
|
|
555
|
-
|
|
556
|
-
this.
|
|
557
|
-
this.
|
|
558
|
-
this.
|
|
559
|
-
this.
|
|
649
|
+
releaseActiveInputResources() {
|
|
650
|
+
const releaseActiveInputListeners = this.releaseActiveInputListeners;
|
|
651
|
+
this.releaseActiveInputListeners = null;
|
|
652
|
+
const restoreTextSelectionSuppression = this.restoreTextSelectionSuppression;
|
|
653
|
+
this.restoreTextSelectionSuppression = null;
|
|
654
|
+
let releaseError;
|
|
655
|
+
let hasReleaseError = false;
|
|
656
|
+
try {
|
|
657
|
+
releaseActiveInputListeners?.();
|
|
658
|
+
}
|
|
659
|
+
catch (error) {
|
|
660
|
+
releaseError = error;
|
|
661
|
+
hasReleaseError = true;
|
|
662
|
+
}
|
|
663
|
+
try {
|
|
664
|
+
restoreTextSelectionSuppression?.();
|
|
665
|
+
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
if (!hasReleaseError) {
|
|
668
|
+
releaseError = error;
|
|
669
|
+
hasReleaseError = true;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (hasReleaseError) {
|
|
673
|
+
throw releaseError;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
clearOverlayHost() {
|
|
677
|
+
this.updateOverlayHost({ type: "unmount" });
|
|
560
678
|
}
|
|
561
679
|
flushQueuedPointerUpdate() {
|
|
562
680
|
if (this.pointerFrameId !== null) {
|
|
@@ -697,8 +815,8 @@ export class DragRuntime {
|
|
|
697
815
|
const removedTargets = this.dropTargetRegistry.pruneDisconnected(group);
|
|
698
816
|
this.clearActiveDropTargetIdIfRemoved(removedTargets);
|
|
699
817
|
}
|
|
700
|
-
|
|
701
|
-
for (const storedRecord of Array.from(this.
|
|
818
|
+
pruneDisconnectedDomBindingRecords(skipRecord) {
|
|
819
|
+
for (const storedRecord of Array.from(this.staleDomBindingRecords)) {
|
|
702
820
|
if (storedRecord === skipRecord) {
|
|
703
821
|
continue;
|
|
704
822
|
}
|
|
@@ -709,14 +827,8 @@ export class DragRuntime {
|
|
|
709
827
|
if (!storedRecord.hasBeenConnected) {
|
|
710
828
|
continue;
|
|
711
829
|
}
|
|
712
|
-
this.
|
|
713
|
-
storedRecord.record.
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
disposeBindingCleanupRecords() {
|
|
717
|
-
for (const storedRecord of Array.from(this.bindingCleanupRecords)) {
|
|
718
|
-
this.bindingCleanupRecords.delete(storedRecord);
|
|
719
|
-
storedRecord.record.cleanup();
|
|
830
|
+
this.staleDomBindingRecords.delete(storedRecord);
|
|
831
|
+
storedRecord.record.release();
|
|
720
832
|
}
|
|
721
833
|
}
|
|
722
834
|
clearActiveDropTargetIdIfRemoved(removedTargets) {
|
|
@@ -734,17 +846,19 @@ export class DragRuntime {
|
|
|
734
846
|
activeDropTargetId: null,
|
|
735
847
|
});
|
|
736
848
|
}
|
|
737
|
-
|
|
738
|
-
this.lifecycleCallbacks.onDragStart?.(event, this.lifecycleHelpers);
|
|
849
|
+
notifyDragStartSubscriptions(subscriptionEvent) {
|
|
739
850
|
for (const subscription of Array.from(this.subscriptions)) {
|
|
740
851
|
subscription.onDragStart?.(subscriptionEvent);
|
|
741
852
|
}
|
|
742
853
|
}
|
|
854
|
+
notifyDragStartLifecycle(event) {
|
|
855
|
+
this.lifecycleCallbacks.onDragStart?.(event, this.lifecycleHelpers);
|
|
856
|
+
}
|
|
743
857
|
notifyDragUpdate(event, subscriptionEvent) {
|
|
744
|
-
this.lifecycleCallbacks.onDragUpdate?.(event, this.lifecycleHelpers);
|
|
745
858
|
for (const subscription of Array.from(this.subscriptions)) {
|
|
746
859
|
subscription.onDragUpdate?.(subscriptionEvent);
|
|
747
860
|
}
|
|
861
|
+
this.lifecycleCallbacks.onDragUpdate?.(event, this.lifecycleHelpers);
|
|
748
862
|
}
|
|
749
863
|
notifyDragEnd(event) {
|
|
750
864
|
for (const subscription of Array.from(this.subscriptions)) {
|
|
@@ -758,6 +872,11 @@ export class DragRuntime {
|
|
|
758
872
|
}
|
|
759
873
|
this.lifecycleCallbacks.onDrop?.(event, this.lifecycleHelpers);
|
|
760
874
|
}
|
|
875
|
+
notifyActiveDragReset(event) {
|
|
876
|
+
for (const subscription of Array.from(this.subscriptions)) {
|
|
877
|
+
subscription.onActiveDragReset?.(event);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
761
880
|
}
|
|
762
881
|
function areOverlayMeasurementsEqual(previous, next) {
|
|
763
882
|
if (previous === next) {
|
|
@@ -27,6 +27,10 @@ export type DropEvent = {
|
|
|
27
27
|
dropTargetId: string;
|
|
28
28
|
sortablePlacement?: SortableDropPlacement;
|
|
29
29
|
};
|
|
30
|
+
export type ActiveDragResetEvent = {
|
|
31
|
+
draggableId: string;
|
|
32
|
+
source: DragSource;
|
|
33
|
+
};
|
|
30
34
|
export type DragLifecycleHelpers = {
|
|
31
35
|
getDropTargetRect: (dropTargetId: string) => DragRect | null;
|
|
32
36
|
};
|
|
@@ -41,4 +45,5 @@ export type DragRuntimeSubscription = {
|
|
|
41
45
|
onDragUpdate?: (event: DragUpdateEvent) => void;
|
|
42
46
|
onDragEnd?: (event: DragEndEvent) => void;
|
|
43
47
|
onDrop?: (event: DropEvent) => void;
|
|
48
|
+
onActiveDragReset?: (event: ActiveDragResetEvent) => void;
|
|
44
49
|
};
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type DragState = {
|
|
|
15
15
|
pointerPosition: Point;
|
|
16
16
|
};
|
|
17
17
|
export type DragOverlayPhase = "dragging" | "released";
|
|
18
|
+
export type OverlayReleaseMode = "auto" | "manual";
|
|
18
19
|
export type DragOverlayRenderState = {
|
|
19
20
|
dragState: DragState;
|
|
20
21
|
phase: DragOverlayPhase;
|
|
@@ -50,13 +51,13 @@ export type DragRuntimeOptions = {
|
|
|
50
51
|
targetingAlgorithm?: TargetingAlgorithm;
|
|
51
52
|
targetingConstraint?: TargetingConstraint;
|
|
52
53
|
hasDragOverlay?: boolean;
|
|
53
|
-
|
|
54
|
+
overlayRelease?: OverlayReleaseMode;
|
|
54
55
|
};
|
|
55
56
|
export type DragRuntimeConfigureInput = {
|
|
56
57
|
targetingAlgorithm: TargetingAlgorithm;
|
|
57
58
|
targetingConstraint: TargetingConstraint | undefined;
|
|
58
59
|
hasDragOverlay: boolean;
|
|
59
|
-
|
|
60
|
+
overlayRelease: OverlayReleaseMode;
|
|
60
61
|
lifecycleCallbacks: DragLifecycleCallbacks;
|
|
61
62
|
keyboardConfiguration?: KeyboardConfiguration;
|
|
62
63
|
modifiers?: readonly DragModifierInput[];
|