@mk-drag-and-drop/dom 0.1.0 → 0.3.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 +111 -35
- package/dist/controller/controller-internals.d.ts +4 -4
- package/dist/controller/create-drag-controller.d.ts +11 -8
- package/dist/controller/create-drag-controller.js +29 -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 +279 -155
- package/dist/runtime/lifecycle.d.ts +7 -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 +2 -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
|
}
|
|
@@ -222,6 +221,7 @@ export class DragRuntime {
|
|
|
222
221
|
draggableId: nextSession.draggableId,
|
|
223
222
|
source: nextSession.source,
|
|
224
223
|
pointerPosition,
|
|
224
|
+
overlayRect,
|
|
225
225
|
activeDropTargetId: nextSession.activeDropTargetId,
|
|
226
226
|
previousDropTargetId,
|
|
227
227
|
};
|
|
@@ -230,20 +230,38 @@ export class DragRuntime {
|
|
|
230
230
|
placementPosition: sortablePlacementPosition,
|
|
231
231
|
});
|
|
232
232
|
}
|
|
233
|
+
updatePointerNowOrRelease(rawPointerPosition) {
|
|
234
|
+
try {
|
|
235
|
+
this.updatePointerNow(rawPointerPosition);
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
this.releaseActiveDragResourcesAndRethrow(error);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
finishDragAfterQueuedPointerUpdate(input) {
|
|
242
|
+
try {
|
|
243
|
+
this.flushQueuedPointerUpdate();
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
this.releaseActiveDragResourcesAndRethrow(error);
|
|
247
|
+
}
|
|
248
|
+
this.finishDrag(input);
|
|
249
|
+
}
|
|
233
250
|
endDrag() {
|
|
234
|
-
this.
|
|
235
|
-
this.finishDrag({
|
|
251
|
+
this.finishDragAfterQueuedPointerUpdate({
|
|
236
252
|
reason: "drop",
|
|
237
|
-
|
|
253
|
+
overlayRelease: this.overlayRelease,
|
|
238
254
|
});
|
|
239
255
|
}
|
|
240
256
|
cancelDrag() {
|
|
241
|
-
this.
|
|
242
|
-
this.finishDrag({
|
|
257
|
+
this.finishDragAfterQueuedPointerUpdate({
|
|
243
258
|
reason: "cancel",
|
|
244
|
-
|
|
259
|
+
overlayRelease: this.overlayRelease,
|
|
245
260
|
});
|
|
246
261
|
}
|
|
262
|
+
cancelPendingActivation() {
|
|
263
|
+
this.pointerActivation.cancelPendingActivation();
|
|
264
|
+
}
|
|
247
265
|
registerDropTarget(dropTargetId, element, group, options) {
|
|
248
266
|
const removedTargets = this.dropTargetRegistry.register(dropTargetId, element, group, options);
|
|
249
267
|
this.clearActiveDropTargetIdIfRemoved(removedTargets);
|
|
@@ -263,12 +281,53 @@ export class DragRuntime {
|
|
|
263
281
|
const removedTargets = this.dropTargetRegistry.unregister(containerId, element);
|
|
264
282
|
this.clearActiveDropTargetIdIfRemoved(removedTargets);
|
|
265
283
|
}
|
|
266
|
-
|
|
267
|
-
this.
|
|
284
|
+
releaseActiveDragResources() {
|
|
285
|
+
const activeSession = this.getDraggingSession();
|
|
286
|
+
this.cancelPendingActivation();
|
|
287
|
+
let firstReleaseError;
|
|
288
|
+
let hasReleaseError = false;
|
|
289
|
+
if (activeSession) {
|
|
290
|
+
try {
|
|
291
|
+
this.notifyActiveDragReset({
|
|
292
|
+
draggableId: activeSession.draggableId,
|
|
293
|
+
source: activeSession.source,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
firstReleaseError = error;
|
|
298
|
+
hasReleaseError = true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
268
301
|
this.resetActiveDragState();
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
302
|
+
try {
|
|
303
|
+
this.releaseActiveInputResources();
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
firstReleaseError = error;
|
|
307
|
+
hasReleaseError = true;
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
this.clearOverlayHost();
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
if (!hasReleaseError) {
|
|
314
|
+
firstReleaseError = error;
|
|
315
|
+
hasReleaseError = true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (hasReleaseError) {
|
|
319
|
+
throw firstReleaseError;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
releaseActiveDragResourcesAndRethrow(error) {
|
|
323
|
+
try {
|
|
324
|
+
this.releaseActiveDragResources();
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
// Preserve the original failure while still making a best effort to
|
|
328
|
+
// release resources that were acquired before it was thrown.
|
|
329
|
+
}
|
|
330
|
+
throw error;
|
|
272
331
|
}
|
|
273
332
|
getDropTargetRect(dropTargetId) {
|
|
274
333
|
return this.dropTargetRegistry.getViewportRect(dropTargetId);
|
|
@@ -302,16 +361,16 @@ export class DragRuntime {
|
|
|
302
361
|
...session,
|
|
303
362
|
overlayMeasurement,
|
|
304
363
|
});
|
|
305
|
-
this.
|
|
364
|
+
this.updatePointerNowOrRelease(session.rawPointerPosition);
|
|
306
365
|
}
|
|
307
366
|
remeasureDropTargets(input) {
|
|
308
367
|
const pruneGroup = input !== undefined && typeof input !== "string" && !Array.isArray(input)
|
|
309
368
|
? input.group
|
|
310
369
|
: undefined;
|
|
311
|
-
this.
|
|
370
|
+
this.pruneDisconnectedDomBindings();
|
|
312
371
|
this.removeDisconnectedDropTargets(pruneGroup);
|
|
313
372
|
this.dropTargetRegistry.remeasure(input);
|
|
314
|
-
this.
|
|
373
|
+
this.pruneDisconnectedDomBindings();
|
|
315
374
|
}
|
|
316
375
|
subscribe(subscription) {
|
|
317
376
|
this.subscriptions.add(subscription);
|
|
@@ -319,121 +378,110 @@ export class DragRuntime {
|
|
|
319
378
|
this.subscriptions.delete(subscription);
|
|
320
379
|
};
|
|
321
380
|
}
|
|
322
|
-
|
|
323
|
-
this.disposeCallbacks.add(callback);
|
|
324
|
-
return () => {
|
|
325
|
-
this.disposeCallbacks.delete(callback);
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
registerBindingCleanup(record) {
|
|
381
|
+
registerStaleDomBinding(record) {
|
|
329
382
|
const storedRecord = {
|
|
330
383
|
record,
|
|
331
384
|
hasBeenConnected: record.isConnected(),
|
|
332
385
|
};
|
|
333
|
-
// Keep registration O(1). Full
|
|
334
|
-
//
|
|
335
|
-
this.
|
|
386
|
+
// Keep registration O(1). Full stale DOM pruning runs on drag lifecycle and
|
|
387
|
+
// explicit remeasurement paths so bulk renders do not rescan prior bindings.
|
|
388
|
+
this.staleDomBindingRecords.add(storedRecord);
|
|
336
389
|
return () => {
|
|
337
|
-
if (!this.
|
|
390
|
+
if (!this.staleDomBindingRecords.delete(storedRecord)) {
|
|
338
391
|
return;
|
|
339
392
|
}
|
|
340
|
-
record.
|
|
393
|
+
record.release();
|
|
341
394
|
};
|
|
342
395
|
}
|
|
343
|
-
|
|
344
|
-
this.
|
|
396
|
+
pruneDisconnectedDomBindings() {
|
|
397
|
+
this.pruneDisconnectedDomBindingRecords();
|
|
345
398
|
}
|
|
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;
|
|
399
|
+
getStaleDomBindingRecordCount() {
|
|
400
|
+
return this.staleDomBindingRecords.size;
|
|
361
401
|
}
|
|
362
402
|
startDragNow(input) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
403
|
+
this.cancelPendingActivation();
|
|
404
|
+
try {
|
|
405
|
+
if (this.targetingAlgorithm.mode === "rect" && !this.hasDragOverlay) {
|
|
406
|
+
throw new Error("The selected targeting algorithm requires a drag overlay. Provide dragOverlay or use a pointer-based targeting algorithm.");
|
|
407
|
+
}
|
|
408
|
+
this.pruneDisconnectedDomBindings();
|
|
409
|
+
const rawPointerPosition = input.pointerPosition;
|
|
410
|
+
const activeDragModifiers = createActiveDragModifiers({
|
|
411
|
+
modifiers: this.modifiers,
|
|
412
|
+
setupInput: {
|
|
413
|
+
draggableId: input.draggableId,
|
|
414
|
+
group: input.group,
|
|
415
|
+
sourceRect: input.sourceRect,
|
|
416
|
+
initialPointerPosition: rawPointerPosition,
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
this.activeDragModifiers = activeDragModifiers;
|
|
420
|
+
const effectivePointerPosition = applyDragModifiers({
|
|
421
|
+
activeModifiers: activeDragModifiers,
|
|
371
422
|
draggableId: input.draggableId,
|
|
372
423
|
group: input.group,
|
|
373
424
|
sourceRect: input.sourceRect,
|
|
374
425
|
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
|
-
|
|
426
|
+
rawPointerPosition,
|
|
427
|
+
});
|
|
428
|
+
const sourceContainerId = this.dropTargetRegistry.getDropTargetRegistration(input.draggableId, input.group)?.containerId ?? null;
|
|
429
|
+
const sourceSortablePlacement = this.dropTargetRegistry.getSortableItemPlacement(input.draggableId, input.group);
|
|
430
|
+
const nextSession = {
|
|
431
|
+
status: "dragging",
|
|
432
|
+
source: input.inputType,
|
|
433
|
+
draggableId: input.draggableId,
|
|
434
|
+
group: input.group,
|
|
435
|
+
sourceRect: input.sourceRect,
|
|
436
|
+
sourceContainerId,
|
|
437
|
+
sourceSortablePlacement,
|
|
438
|
+
overlayMeasurement: null,
|
|
439
|
+
startPointerPosition: rawPointerPosition,
|
|
440
|
+
rawPointerPosition,
|
|
441
|
+
pointerPosition: effectivePointerPosition,
|
|
442
|
+
activeDropTargetId: null,
|
|
443
|
+
};
|
|
444
|
+
this.setSession(nextSession);
|
|
445
|
+
this.remeasureDropTargets({ group: input.group });
|
|
446
|
+
const dragStartEvent = {
|
|
447
|
+
draggableId: input.draggableId,
|
|
448
|
+
source: input.inputType,
|
|
449
|
+
pointerPosition: effectivePointerPosition,
|
|
450
|
+
sourceRect: input.sourceRect,
|
|
451
|
+
};
|
|
452
|
+
const startOverlayRect = this.hasDragOverlay
|
|
453
|
+
? this.getCurrentDragRectAt(effectivePointerPosition)
|
|
454
|
+
: null;
|
|
455
|
+
const dragStartSubscriptionEvent = {
|
|
456
|
+
...dragStartEvent,
|
|
457
|
+
placementPosition: this.getSortablePlacementPosition({
|
|
458
|
+
pointerPosition: effectivePointerPosition,
|
|
459
|
+
overlayRect: startOverlayRect,
|
|
460
|
+
}),
|
|
461
|
+
};
|
|
462
|
+
this.notifyDragStartSubscriptions(dragStartSubscriptionEvent);
|
|
463
|
+
this.updateOverlayHost({
|
|
464
|
+
type: "mount",
|
|
465
|
+
state: {
|
|
466
|
+
dragState: this.createDragState(nextSession),
|
|
467
|
+
phase: "dragging",
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
this.suppressTextSelection();
|
|
471
|
+
if (input.inputType === "pointer") {
|
|
472
|
+
this.bindPointerWindowListeners(input.pointerId);
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
this.bindKeyboardWindowListeners();
|
|
476
|
+
}
|
|
477
|
+
this.notifyDragStartLifecycle(dragStartEvent);
|
|
414
478
|
}
|
|
415
|
-
|
|
416
|
-
this.
|
|
479
|
+
catch (error) {
|
|
480
|
+
this.releaseActiveDragResourcesAndRethrow(error);
|
|
417
481
|
}
|
|
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
482
|
}
|
|
435
483
|
finishDrag(input) {
|
|
436
|
-
this.
|
|
484
|
+
this.cancelPendingActivation();
|
|
437
485
|
const session = this.getDraggingSession();
|
|
438
486
|
const releasedDragState = session
|
|
439
487
|
? this.createDragState(session)
|
|
@@ -452,6 +500,9 @@ export class DragRuntime {
|
|
|
452
500
|
? "dropped"
|
|
453
501
|
: "invalid-target"
|
|
454
502
|
: null;
|
|
503
|
+
const overlayRect = session && this.hasDragOverlay
|
|
504
|
+
? this.getCurrentDragRectAt(session.pointerPosition)
|
|
505
|
+
: null;
|
|
455
506
|
const sortablePlacement = session && dropTargetId
|
|
456
507
|
? this.getDropEventSortablePlacement(session, dropTargetId)
|
|
457
508
|
: undefined;
|
|
@@ -462,7 +513,15 @@ export class DragRuntime {
|
|
|
462
513
|
})
|
|
463
514
|
: null;
|
|
464
515
|
this.resetActiveDragState();
|
|
465
|
-
|
|
516
|
+
let finishError;
|
|
517
|
+
let hasFinishError = false;
|
|
518
|
+
try {
|
|
519
|
+
this.releaseActiveInputResources();
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
finishError = error;
|
|
523
|
+
hasFinishError = true;
|
|
524
|
+
}
|
|
466
525
|
if (session && result) {
|
|
467
526
|
this.lifecycleDropTargetRectSnapshot = lifecycleDropTargetRectSnapshot;
|
|
468
527
|
try {
|
|
@@ -470,6 +529,7 @@ export class DragRuntime {
|
|
|
470
529
|
draggableId: session.draggableId,
|
|
471
530
|
source: session.source,
|
|
472
531
|
result,
|
|
532
|
+
overlayRect,
|
|
473
533
|
dropTargetId,
|
|
474
534
|
});
|
|
475
535
|
if (result === "dropped" && dropTargetId) {
|
|
@@ -481,25 +541,60 @@ export class DragRuntime {
|
|
|
481
541
|
});
|
|
482
542
|
}
|
|
483
543
|
}
|
|
544
|
+
catch (error) {
|
|
545
|
+
finishError = error;
|
|
546
|
+
hasFinishError = true;
|
|
547
|
+
}
|
|
484
548
|
finally {
|
|
485
549
|
this.lifecycleDropTargetRectSnapshot = null;
|
|
486
550
|
}
|
|
487
551
|
}
|
|
488
|
-
|
|
489
|
-
this.
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
dragState: releasedDragState,
|
|
493
|
-
phase: "released",
|
|
494
|
-
},
|
|
552
|
+
try {
|
|
553
|
+
this.releaseOverlayAfterDrag({
|
|
554
|
+
overlayRelease: input.overlayRelease,
|
|
555
|
+
releasedDragState,
|
|
495
556
|
});
|
|
496
557
|
}
|
|
497
|
-
|
|
498
|
-
|
|
558
|
+
catch (error) {
|
|
559
|
+
if (!hasFinishError) {
|
|
560
|
+
finishError = error;
|
|
561
|
+
hasFinishError = true;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (hasFinishError) {
|
|
565
|
+
throw finishError;
|
|
499
566
|
}
|
|
500
567
|
}
|
|
568
|
+
releaseOverlayAfterDrag(input) {
|
|
569
|
+
if (input.overlayRelease === "manual" &&
|
|
570
|
+
input.releasedDragState &&
|
|
571
|
+
this.hasDragOverlay) {
|
|
572
|
+
try {
|
|
573
|
+
this.updateOverlayHost({
|
|
574
|
+
type: "release",
|
|
575
|
+
state: {
|
|
576
|
+
dragState: input.releasedDragState,
|
|
577
|
+
phase: "released",
|
|
578
|
+
},
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
catch (error) {
|
|
582
|
+
try {
|
|
583
|
+
this.clearOverlayHost();
|
|
584
|
+
}
|
|
585
|
+
catch {
|
|
586
|
+
// Preserve the overlay release error while still making a best effort
|
|
587
|
+
// to clear the host state.
|
|
588
|
+
}
|
|
589
|
+
throw error;
|
|
590
|
+
}
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
this.clearOverlayHost();
|
|
594
|
+
}
|
|
501
595
|
bindPointerWindowListeners(pointerId) {
|
|
502
|
-
this.
|
|
596
|
+
this.releaseActiveInputListeners?.();
|
|
597
|
+
let listenersReleased = false;
|
|
503
598
|
const handlePointerMove = (event) => {
|
|
504
599
|
if (event.pointerId !== pointerId) {
|
|
505
600
|
return;
|
|
@@ -524,25 +619,29 @@ export class DragRuntime {
|
|
|
524
619
|
window.addEventListener("pointermove", handlePointerMove);
|
|
525
620
|
window.addEventListener("pointerup", handlePointerUp);
|
|
526
621
|
window.addEventListener("pointercancel", handlePointerCancel);
|
|
527
|
-
this.
|
|
622
|
+
this.releaseActiveInputListeners = () => {
|
|
623
|
+
if (listenersReleased) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
listenersReleased = true;
|
|
528
627
|
window.removeEventListener("pointermove", handlePointerMove);
|
|
529
628
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
530
629
|
window.removeEventListener("pointercancel", handlePointerCancel);
|
|
531
630
|
};
|
|
532
631
|
}
|
|
533
632
|
bindKeyboardWindowListeners() {
|
|
534
|
-
this.
|
|
535
|
-
this.
|
|
633
|
+
this.releaseActiveInputListeners?.();
|
|
634
|
+
this.releaseActiveInputListeners = this.keyboardDrag.bindWindowListeners();
|
|
536
635
|
}
|
|
537
636
|
suppressTextSelection() {
|
|
538
|
-
this.
|
|
637
|
+
this.restoreTextSelectionSuppression?.();
|
|
539
638
|
const root = document.documentElement;
|
|
540
639
|
const body = document.body;
|
|
541
640
|
const previousRootUserSelect = root.style.userSelect;
|
|
542
641
|
const previousBodyUserSelect = body.style.userSelect;
|
|
543
642
|
root.style.userSelect = "none";
|
|
544
643
|
body.style.userSelect = "none";
|
|
545
|
-
this.
|
|
644
|
+
this.restoreTextSelectionSuppression = () => {
|
|
546
645
|
root.style.userSelect = previousRootUserSelect;
|
|
547
646
|
body.style.userSelect = previousBodyUserSelect;
|
|
548
647
|
};
|
|
@@ -552,11 +651,35 @@ export class DragRuntime {
|
|
|
552
651
|
this.setSession({ status: "idle" });
|
|
553
652
|
this.activeDragModifiers = [];
|
|
554
653
|
}
|
|
555
|
-
|
|
556
|
-
this.
|
|
557
|
-
this.
|
|
558
|
-
this.
|
|
559
|
-
this.
|
|
654
|
+
releaseActiveInputResources() {
|
|
655
|
+
const releaseActiveInputListeners = this.releaseActiveInputListeners;
|
|
656
|
+
this.releaseActiveInputListeners = null;
|
|
657
|
+
const restoreTextSelectionSuppression = this.restoreTextSelectionSuppression;
|
|
658
|
+
this.restoreTextSelectionSuppression = null;
|
|
659
|
+
let releaseError;
|
|
660
|
+
let hasReleaseError = false;
|
|
661
|
+
try {
|
|
662
|
+
releaseActiveInputListeners?.();
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
releaseError = error;
|
|
666
|
+
hasReleaseError = true;
|
|
667
|
+
}
|
|
668
|
+
try {
|
|
669
|
+
restoreTextSelectionSuppression?.();
|
|
670
|
+
}
|
|
671
|
+
catch (error) {
|
|
672
|
+
if (!hasReleaseError) {
|
|
673
|
+
releaseError = error;
|
|
674
|
+
hasReleaseError = true;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (hasReleaseError) {
|
|
678
|
+
throw releaseError;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
clearOverlayHost() {
|
|
682
|
+
this.updateOverlayHost({ type: "unmount" });
|
|
560
683
|
}
|
|
561
684
|
flushQueuedPointerUpdate() {
|
|
562
685
|
if (this.pointerFrameId !== null) {
|
|
@@ -697,8 +820,8 @@ export class DragRuntime {
|
|
|
697
820
|
const removedTargets = this.dropTargetRegistry.pruneDisconnected(group);
|
|
698
821
|
this.clearActiveDropTargetIdIfRemoved(removedTargets);
|
|
699
822
|
}
|
|
700
|
-
|
|
701
|
-
for (const storedRecord of Array.from(this.
|
|
823
|
+
pruneDisconnectedDomBindingRecords(skipRecord) {
|
|
824
|
+
for (const storedRecord of Array.from(this.staleDomBindingRecords)) {
|
|
702
825
|
if (storedRecord === skipRecord) {
|
|
703
826
|
continue;
|
|
704
827
|
}
|
|
@@ -709,14 +832,8 @@ export class DragRuntime {
|
|
|
709
832
|
if (!storedRecord.hasBeenConnected) {
|
|
710
833
|
continue;
|
|
711
834
|
}
|
|
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();
|
|
835
|
+
this.staleDomBindingRecords.delete(storedRecord);
|
|
836
|
+
storedRecord.record.release();
|
|
720
837
|
}
|
|
721
838
|
}
|
|
722
839
|
clearActiveDropTargetIdIfRemoved(removedTargets) {
|
|
@@ -734,17 +851,19 @@ export class DragRuntime {
|
|
|
734
851
|
activeDropTargetId: null,
|
|
735
852
|
});
|
|
736
853
|
}
|
|
737
|
-
|
|
738
|
-
this.lifecycleCallbacks.onDragStart?.(event, this.lifecycleHelpers);
|
|
854
|
+
notifyDragStartSubscriptions(subscriptionEvent) {
|
|
739
855
|
for (const subscription of Array.from(this.subscriptions)) {
|
|
740
856
|
subscription.onDragStart?.(subscriptionEvent);
|
|
741
857
|
}
|
|
742
858
|
}
|
|
859
|
+
notifyDragStartLifecycle(event) {
|
|
860
|
+
this.lifecycleCallbacks.onDragStart?.(event, this.lifecycleHelpers);
|
|
861
|
+
}
|
|
743
862
|
notifyDragUpdate(event, subscriptionEvent) {
|
|
744
|
-
this.lifecycleCallbacks.onDragUpdate?.(event, this.lifecycleHelpers);
|
|
745
863
|
for (const subscription of Array.from(this.subscriptions)) {
|
|
746
864
|
subscription.onDragUpdate?.(subscriptionEvent);
|
|
747
865
|
}
|
|
866
|
+
this.lifecycleCallbacks.onDragUpdate?.(event, this.lifecycleHelpers);
|
|
748
867
|
}
|
|
749
868
|
notifyDragEnd(event) {
|
|
750
869
|
for (const subscription of Array.from(this.subscriptions)) {
|
|
@@ -758,6 +877,11 @@ export class DragRuntime {
|
|
|
758
877
|
}
|
|
759
878
|
this.lifecycleCallbacks.onDrop?.(event, this.lifecycleHelpers);
|
|
760
879
|
}
|
|
880
|
+
notifyActiveDragReset(event) {
|
|
881
|
+
for (const subscription of Array.from(this.subscriptions)) {
|
|
882
|
+
subscription.onActiveDragReset?.(event);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
761
885
|
}
|
|
762
886
|
function areOverlayMeasurementsEqual(previous, next) {
|
|
763
887
|
if (previous === next) {
|
|
@@ -12,6 +12,7 @@ export type DragUpdateEvent = {
|
|
|
12
12
|
draggableId: string;
|
|
13
13
|
source: DragSource;
|
|
14
14
|
pointerPosition: DragPoint;
|
|
15
|
+
overlayRect: DragRect | null;
|
|
15
16
|
activeDropTargetId: string | null;
|
|
16
17
|
previousDropTargetId: string | null;
|
|
17
18
|
};
|
|
@@ -19,6 +20,7 @@ export type DragEndEvent = {
|
|
|
19
20
|
draggableId: string;
|
|
20
21
|
source: DragSource;
|
|
21
22
|
result: DragEndResult;
|
|
23
|
+
overlayRect: DragRect | null;
|
|
22
24
|
dropTargetId: string | null;
|
|
23
25
|
};
|
|
24
26
|
export type DropEvent = {
|
|
@@ -27,6 +29,10 @@ export type DropEvent = {
|
|
|
27
29
|
dropTargetId: string;
|
|
28
30
|
sortablePlacement?: SortableDropPlacement;
|
|
29
31
|
};
|
|
32
|
+
export type ActiveDragResetEvent = {
|
|
33
|
+
draggableId: string;
|
|
34
|
+
source: DragSource;
|
|
35
|
+
};
|
|
30
36
|
export type DragLifecycleHelpers = {
|
|
31
37
|
getDropTargetRect: (dropTargetId: string) => DragRect | null;
|
|
32
38
|
};
|
|
@@ -41,4 +47,5 @@ export type DragRuntimeSubscription = {
|
|
|
41
47
|
onDragUpdate?: (event: DragUpdateEvent) => void;
|
|
42
48
|
onDragEnd?: (event: DragEndEvent) => void;
|
|
43
49
|
onDrop?: (event: DropEvent) => void;
|
|
50
|
+
onActiveDragReset?: (event: ActiveDragResetEvent) => void;
|
|
44
51
|
};
|