From 43c7a7df1a6d39ee9eae14aaf3be85f4c561cecf Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Mon, 14 Oct 2019 20:52:45 +0200 Subject: [PATCH] =?UTF-8?q?feat(drag-drop):=20allow=20drag=20start=20delay?= =?UTF-8?q?=20to=20be=20configured=20based=E2=80=A6=20(#17301)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows the consumer to configure the drag start delay based on whether it's a touch event or mouse event. Fixes #17260. --- src/cdk/drag-drop/directives/drag.spec.ts | 23 ++++++++++++++++++++++- src/cdk/drag-drop/directives/drag.ts | 6 ++++-- src/cdk/drag-drop/drag-ref.ts | 17 +++++++++++++++-- tools/public_api_guard/cdk/drag-drop.d.ts | 10 ++++++++-- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/cdk/drag-drop/directives/drag.spec.ts b/src/cdk/drag-drop/directives/drag.spec.ts index 0d619c0e7375..8984ff6ef806 100644 --- a/src/cdk/drag-drop/directives/drag.spec.ts +++ b/src/cdk/drag-drop/directives/drag.spec.ts @@ -993,6 +993,27 @@ describe('CdkDrag', () => { 'Expected element to be dragged after all the time has passed.'); })); + it('should be able to configure the drag start delay based on the event type', fakeAsync(() => { + // We can't use Jasmine's `clock` because Zone.js interferes with it. + spyOn(Date, 'now').and.callFake(() => currentTime); + let currentTime = 0; + + const fixture = createComponent(StandaloneDraggable); + fixture.componentInstance.dragStartDelay = {touch: 500, mouse: 0}; + fixture.detectChanges(); + const dragElement = fixture.componentInstance.dragElement.nativeElement; + + expect(dragElement.style.transform).toBeFalsy('Expected element not to be moved by default.'); + + dragElementViaTouch(fixture, dragElement, 50, 100); + expect(dragElement.style.transform) + .toBeFalsy('Expected element not to be moved via touch because it has a delay.'); + + dragElementViaMouse(fixture, dragElement, 50, 100); + expect(dragElement.style.transform).toBe('translate3d(50px, 100px, 0px)', + 'Expected element to be moved via mouse because it has no delay.'); + })); + it('should be able to get the current position', fakeAsync(() => { const fixture = createComponent(StandaloneDraggable); fixture.detectChanges(); @@ -4293,7 +4314,7 @@ class StandaloneDraggable { endedSpy = jasmine.createSpy('ended spy'); releasedSpy = jasmine.createSpy('released spy'); boundary: string | HTMLElement; - dragStartDelay: number | string; + dragStartDelay: number | string | {touch: number, mouse: number}; constrainPosition: (point: Point) => Point; freeDragPosition?: {x: number, y: number}; } diff --git a/src/cdk/drag-drop/directives/drag.ts b/src/cdk/drag-drop/directives/drag.ts index 9c028f842868..7eb18c1d31f5 100644 --- a/src/cdk/drag-drop/directives/drag.ts +++ b/src/cdk/drag-drop/directives/drag.ts @@ -118,7 +118,7 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { * Amount of milliseconds to wait after the user has put their * pointer down before starting to drag the element. */ - @Input('cdkDragStartDelay') dragStartDelay: number = 0; + @Input('cdkDragStartDelay') dragStartDelay: number | {touch: number, mouse: number} = 0; /** * Sets the position of a `CdkDrag` that is outside of a drop container. @@ -326,6 +326,7 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { ref.beforeStarted.subscribe(() => { if (!ref.isDragging()) { const dir = this._dir; + const dragStartDelay = this.dragStartDelay; const placeholder = this._placeholderTemplate ? { template: this._placeholderTemplate.templateRef, context: this._placeholderTemplate.data, @@ -339,7 +340,8 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { ref.disabled = this.disabled; ref.lockAxis = this.lockAxis; - ref.dragStartDelay = coerceNumberProperty(this.dragStartDelay); + ref.dragStartDelay = (typeof dragStartDelay === 'object' && dragStartDelay) ? + dragStartDelay : coerceNumberProperty(dragStartDelay); ref.constrainPosition = this.constrainPosition; ref .withBoundaryElement(this._getBoundaryElement()) diff --git a/src/cdk/drag-drop/drag-ref.ts b/src/cdk/drag-drop/drag-ref.ts index de2477d7fdbe..89029e667b98 100644 --- a/src/cdk/drag-drop/drag-ref.ts +++ b/src/cdk/drag-drop/drag-ref.ts @@ -208,7 +208,7 @@ export class DragRef { * Amount of milliseconds to wait after the user has put their * pointer down before starting to drag the element. */ - dragStartDelay: number = 0; + dragStartDelay: number | {touch: number, mouse: number} = 0; /** Whether starting to drag this element is disabled. */ get disabled(): boolean { @@ -533,7 +533,7 @@ export class DragRef { // in the `pointerMove` subscription, because we're not guaranteed to have one move event // per pixel of movement (e.g. if the user moves their pointer quickly). if (isOverThreshold) { - const isDelayElapsed = Date.now() >= this._dragStartTime + (this.dragStartDelay || 0); + const isDelayElapsed = Date.now() >= this._dragStartTime + this._getDragStartDelay(event); if (!isDelayElapsed) { this._endDragSequence(event); return; @@ -1149,6 +1149,19 @@ export class DragRef { this.setFreeDragPosition({y, x}); } } + + /** Gets the drag start delay, based on the event type. */ + private _getDragStartDelay(event: MouseEvent | TouchEvent): number { + const value = this.dragStartDelay; + + if (typeof value === 'number') { + return value; + } else if (isTouchEvent(event)) { + return value.touch; + } + + return value ? value.mouse : 0; + } } /** Point on the page or within an element. */ diff --git a/tools/public_api_guard/cdk/drag-drop.d.ts b/tools/public_api_guard/cdk/drag-drop.d.ts index 4f10e3a23445..5aacd933b9fc 100644 --- a/tools/public_api_guard/cdk/drag-drop.d.ts +++ b/tools/public_api_guard/cdk/drag-drop.d.ts @@ -13,7 +13,10 @@ export declare class CdkDrag implements AfterViewInit, OnChanges, OnDes constrainPosition?: (point: Point, dragRef: DragRef) => Point; data: T; disabled: boolean; - dragStartDelay: number; + dragStartDelay: number | { + touch: number; + mouse: number; + }; dropContainer: CdkDropList; dropped: EventEmitter>; element: ElementRef; @@ -194,7 +197,10 @@ export declare class DragRef { constrainPosition?: (point: Point, dragRef: DragRef) => Point; data: T; disabled: boolean; - dragStartDelay: number; + dragStartDelay: number | { + touch: number; + mouse: number; + }; dropped: Subject<{ previousIndex: number; currentIndex: number;