From 172b1f68c7d957b13927eebba0b8c41a34c2b586 Mon Sep 17 00:00:00 2001 From: Andreas Dorner Date: Tue, 17 Dec 2024 09:50:25 +0100 Subject: [PATCH] [feat] drag start predicate --- src/cdk/drag-drop/directives/config.ts | 3 +++ src/cdk/drag-drop/directives/drag.ts | 13 ++++++++++++- src/cdk/drag-drop/drag-ref.ts | 9 +++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/cdk/drag-drop/directives/config.ts b/src/cdk/drag-drop/directives/config.ts index 7e44425d85e5..d57425aa0ec3 100644 --- a/src/cdk/drag-drop/directives/config.ts +++ b/src/cdk/drag-drop/directives/config.ts @@ -12,6 +12,9 @@ import {DragRefConfig, Point, DragRef} from '../drag-ref'; /** Possible values that can be used to configure the drag start delay. */ export type DragStartDelay = number | {touch: number; mouse: number}; +/** Function that is used to determine whether a drag operation is allowed to start. */ +export type DragStartPredicate = (event: MouseEvent | TouchEvent) => boolean; + /** Possible axis along which dragging can be locked. */ export type DragAxis = 'x' | 'y'; diff --git a/src/cdk/drag-drop/directives/drag.ts b/src/cdk/drag-drop/directives/drag.ts index 8ec7fab27f5e..8c566d2f05c3 100644 --- a/src/cdk/drag-drop/directives/drag.ts +++ b/src/cdk/drag-drop/directives/drag.ts @@ -46,7 +46,13 @@ import {CDK_DRAG_PARENT} from '../drag-parent'; import {DragRef, Point, PreviewContainer} from '../drag-ref'; import type {CdkDropList} from './drop-list'; import {DragDrop} from '../drag-drop'; -import {CDK_DRAG_CONFIG, DragDropConfig, DragStartDelay, DragAxis} from './config'; +import { + CDK_DRAG_CONFIG, + DragDropConfig, + DragStartDelay, + DragAxis, + DragStartPredicate, +} from './config'; import {assertElementNode} from './assertions'; import {DragDropRegistry} from '../drag-drop-registry'; @@ -114,6 +120,9 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { */ @Input('cdkDragStartDelay') dragStartDelay: DragStartDelay; + /** Function that is used to determine whether a drag operation is allowed to start. */ + @Input('cdkDragStartPredicate') dragStartPredicate?: DragStartPredicate; + /** * Sets the position of a `CdkDrag` that is outside of a drop container. * Can be used to restore the element's position for a returning user. @@ -430,6 +439,7 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { if (!ref.isDragging()) { const dir = this._dir; const dragStartDelay = this.dragStartDelay; + const dragStartPredicate = this.dragStartPredicate; const placeholder = this._placeholderTemplate ? { template: this._placeholderTemplate.templateRef, @@ -453,6 +463,7 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { typeof dragStartDelay === 'object' && dragStartDelay ? dragStartDelay : coerceNumberProperty(dragStartDelay); + ref.dragStartPredicate = dragStartPredicate; ref.constrainPosition = this.constrainPosition; ref.previewClass = this.previewClass; ref diff --git a/src/cdk/drag-drop/drag-ref.ts b/src/cdk/drag-drop/drag-ref.ts index 0d20f2aa38e6..09b2faff0e17 100644 --- a/src/cdk/drag-drop/drag-ref.ts +++ b/src/cdk/drag-drop/drag-ref.ts @@ -39,6 +39,7 @@ import { import {DragDropRegistry} from './drag-drop-registry'; import type {DropListRef} from './drop-list-ref'; import {DragPreviewTemplate, PreviewRef} from './preview-ref'; +import {DragStartPredicate} from './directives/config'; /** Object that can be used to configure the behavior of DragRef. */ export interface DragRefConfig { @@ -286,6 +287,9 @@ export class DragRef { */ dragStartDelay: number | {touch: number; mouse: number} = 0; + /** Function that is used to determine whether a drag operation is allowed to start. */ + dragStartPredicate: DragStartPredicate | undefined; + /** Class to be added to the preview element. */ previewClass: string | string[] | undefined; @@ -904,6 +908,11 @@ export class DragRef { ? isFakeTouchstartFromScreenReader(event as TouchEvent) : isFakeMousedownFromScreenReader(event as MouseEvent); + // Check the drag start predicate if one is provided + if (this.dragStartPredicate && !this.dragStartPredicate(event)) { + return; + } + // If the event started from an element with the native HTML drag&drop, it'll interfere // with our own dragging (e.g. `img` tags do it by default). Prevent the default action // to stop it from happening. Note that preventing on `dragstart` also seems to work, but