Skip to content

Commit 761f5fd

Browse files
authored
fix(cdk/drag-drop): stop pointer events on placeholder (#24404)
Removes the pointer events from the drag placeholder so that the user can't interact with it while the preview is animating. Fixes #24403.
1 parent ea6fdb9 commit 761f5fd

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

src/cdk/drag-drop/directives/drag.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,18 @@ describe('CdkDrag', () => {
259259

260260
expect(dragElement.style.transform).toBeFalsy();
261261
}));
262+
263+
it('should prevent the default dragstart action', fakeAsync(() => {
264+
const fixture = createComponent(StandaloneDraggable);
265+
fixture.detectChanges();
266+
const event = dispatchFakeEvent(
267+
fixture.componentInstance.dragElement.nativeElement,
268+
'dragstart',
269+
);
270+
fixture.detectChanges();
271+
272+
expect(event.defaultPrevented).toBe(true);
273+
}));
262274
});
263275

264276
describe('touch dragging', () => {
@@ -2952,6 +2964,9 @@ describe('CdkDrag', () => {
29522964
expect(placeholder.textContent!.trim())
29532965
.withContext('Expected placeholder content to match element')
29542966
.toContain('One');
2967+
expect(placeholder.style.pointerEvents)
2968+
.withContext('Expected pointer events to be disabled on placeholder')
2969+
.toBe('none');
29552970

29562971
dispatchMouseEvent(document, 'mouseup');
29572972
fixture.detectChanges();

src/cdk/drag-drop/drag-ref.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,9 @@ export class DragRef<T = any> {
442442
this._ngZone.runOutsideAngular(() => {
443443
element.addEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
444444
element.addEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
445+
// Usually this isn't necessary since the we prevent the default action in `pointerDown`,
446+
// but some cases like dragging of links can slip through (see #24403).
447+
element.addEventListener('dragstart', preventDefault, activeEventListenerOptions);
445448
});
446449
this._initialTransform = undefined;
447450
this._rootElement = element;
@@ -1159,6 +1162,9 @@ export class DragRef<T = any> {
11591162
placeholder = deepCloneNode(this._rootElement);
11601163
}
11611164

1165+
// Stop pointer events on the preview so the user can't
1166+
// interact with it while the preview is animating.
1167+
placeholder.style.pointerEvents = 'none';
11621168
placeholder.classList.add('cdk-drag-placeholder');
11631169
return placeholder;
11641170
}
@@ -1290,6 +1296,7 @@ export class DragRef<T = any> {
12901296
private _removeRootElementListeners(element: HTMLElement) {
12911297
element.removeEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
12921298
element.removeEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
1299+
element.removeEventListener('dragstart', preventDefault, activeEventListenerOptions);
12931300
}
12941301

12951302
/**
@@ -1555,3 +1562,8 @@ function matchElementSize(target: HTMLElement, sourceRect: ClientRect): void {
15551562
target.style.height = `${sourceRect.height}px`;
15561563
target.style.transform = getTransform(sourceRect.left, sourceRect.top);
15571564
}
1565+
1566+
/** Utility to prevent the default action of an event. */
1567+
function preventDefault(event: Event): void {
1568+
event.preventDefault();
1569+
}

0 commit comments

Comments
 (0)