Skip to content

feat(cdk/drag-drop): support configurable scroll speed #21400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/cdk/drag-drop/directives/drag.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3987,6 +3987,25 @@ describe('CdkDrag', () => {
expect(container.scrollTop).toBeGreaterThan(0);
}));

it('should be able to configure the auto-scroll speed', fakeAsync(() => {
const fixture = createComponent(DraggableInScrollableVerticalDropZone);
fixture.detectChanges();
fixture.componentInstance.dropInstance.autoScrollStep = 20;
const item = fixture.componentInstance.dragItems.first.element.nativeElement;
const list = fixture.componentInstance.dropInstance.element.nativeElement;
const listRect = list.getBoundingClientRect();

expect(list.scrollTop).toBe(0);

startDraggingViaMouse(fixture, item);
dispatchMouseEvent(document, 'mousemove',
listRect.left + listRect.width / 2, listRect.top + listRect.height);
fixture.detectChanges();
tickAnimationFrames(10);

expect(list.scrollTop).toBeGreaterThan(100);
}));

it('should pick up descendants inside of containers', fakeAsync(() => {
const fixture = createComponent(DraggableInDropZoneWithContainer);
fixture.detectChanges();
Expand Down
14 changes: 13 additions & 1 deletion src/cdk/drag-drop/directives/drop-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/

import {BooleanInput, coerceArray, coerceBooleanProperty} from '@angular/cdk/coercion';
import {
BooleanInput,
coerceArray,
coerceNumberProperty,
coerceBooleanProperty,
NumberInput,
} from '@angular/cdk/coercion';
import {
ElementRef,
EventEmitter,
Expand Down Expand Up @@ -136,6 +142,10 @@ export class CdkDropList<T = any> implements OnDestroy {
@Input('cdkDropListAutoScrollDisabled')
autoScrollDisabled: boolean;

/** Number of pixels to scroll for each frame when auto-scrolling an element. */
@Input('cdkDropListAutoScrollStep')
autoScrollStep: number;

/** Emits when the user drops an item inside the container. */
@Output('cdkDropListDropped')
dropped: EventEmitter<CdkDragDrop<T, any>> = new EventEmitter<CdkDragDrop<T, any>>();
Expand Down Expand Up @@ -301,6 +311,7 @@ export class CdkDropList<T = any> implements OnDestroy {
ref.lockAxis = this.lockAxis;
ref.sortingDisabled = coerceBooleanProperty(this.sortingDisabled);
ref.autoScrollDisabled = coerceBooleanProperty(this.autoScrollDisabled);
ref.autoScrollStep = coerceNumberProperty(this.autoScrollStep, 2);
ref
.connectedTo(siblings.filter(drop => drop && drop !== this).map(list => list._dropListRef))
.withOrientation(this.orientation);
Expand Down Expand Up @@ -380,4 +391,5 @@ export class CdkDropList<T = any> implements OnDestroy {
static ngAcceptInputType_disabled: BooleanInput;
static ngAcceptInputType_sortingDisabled: BooleanInput;
static ngAcceptInputType_autoScrollDisabled: BooleanInput;
static ngAcceptInputType_autoScrollStep: NumberInput;
}
18 changes: 8 additions & 10 deletions src/cdk/drag-drop/drop-list-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ const DROP_PROXIMITY_THRESHOLD = 0.05;
*/
const SCROLL_PROXIMITY_THRESHOLD = 0.05;

/**
* Number of pixels to scroll for each frame when auto-scrolling an element.
* The value comes from trying it out manually until it feels right.
*/
const AUTO_SCROLL_STEP = 2;

/**
* Entry in the position cache for draggable items.
* @docs-private
Expand Down Expand Up @@ -91,6 +85,9 @@ export class DropListRef<T = any> {
*/
autoScrollDisabled: boolean = false;

/** Number of pixels to scroll for each frame when auto-scrolling an element. */
autoScrollStep: number = 2;

/**
* Function that is used to determine whether an item
* is allowed to be moved into a drop container.
Expand Down Expand Up @@ -788,17 +785,18 @@ export class DropListRef<T = any> {
.pipe(takeUntil(this._stopScrollTimers))
.subscribe(() => {
const node = this._scrollNode;
const scrollStep = this.autoScrollStep;

if (this._verticalScrollDirection === AutoScrollVerticalDirection.UP) {
incrementVerticalScroll(node, -AUTO_SCROLL_STEP);
incrementVerticalScroll(node, -scrollStep);
} else if (this._verticalScrollDirection === AutoScrollVerticalDirection.DOWN) {
incrementVerticalScroll(node, AUTO_SCROLL_STEP);
incrementVerticalScroll(node, scrollStep);
}

if (this._horizontalScrollDirection === AutoScrollHorizontalDirection.LEFT) {
incrementHorizontalScroll(node, -AUTO_SCROLL_STEP);
incrementHorizontalScroll(node, -scrollStep);
} else if (this._horizontalScrollDirection === AutoScrollHorizontalDirection.RIGHT) {
incrementHorizontalScroll(node, AUTO_SCROLL_STEP);
incrementHorizontalScroll(node, scrollStep);
}
});
}
Expand Down
5 changes: 4 additions & 1 deletion tools/public_api_guard/cdk/drag-drop.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export interface CdkDragStart<T = any> {
export declare class CdkDropList<T = any> implements OnDestroy {
_dropListRef: DropListRef<CdkDropList<T>>;
autoScrollDisabled: boolean;
autoScrollStep: number;
connectedTo: (CdkDropList | string)[] | CdkDropList | string;
data: T;
get disabled(): boolean;
Expand All @@ -179,9 +180,10 @@ export declare class CdkDropList<T = any> implements OnDestroy {
ngOnDestroy(): void;
removeItem(item: CdkDrag): void;
static ngAcceptInputType_autoScrollDisabled: BooleanInput;
static ngAcceptInputType_autoScrollStep: NumberInput;
static ngAcceptInputType_disabled: BooleanInput;
static ngAcceptInputType_sortingDisabled: BooleanInput;
static ɵdir: i0.ɵɵDirectiveDefWithMeta<CdkDropList<any>, "[cdkDropList], cdk-drop-list", ["cdkDropList"], { "connectedTo": "cdkDropListConnectedTo"; "data": "cdkDropListData"; "orientation": "cdkDropListOrientation"; "id": "id"; "lockAxis": "cdkDropListLockAxis"; "disabled": "cdkDropListDisabled"; "sortingDisabled": "cdkDropListSortingDisabled"; "enterPredicate": "cdkDropListEnterPredicate"; "sortPredicate": "cdkDropListSortPredicate"; "autoScrollDisabled": "cdkDropListAutoScrollDisabled"; }, { "dropped": "cdkDropListDropped"; "entered": "cdkDropListEntered"; "exited": "cdkDropListExited"; "sorted": "cdkDropListSorted"; }, never>;
static ɵdir: i0.ɵɵDirectiveDefWithMeta<CdkDropList<any>, "[cdkDropList], cdk-drop-list", ["cdkDropList"], { "connectedTo": "cdkDropListConnectedTo"; "data": "cdkDropListData"; "orientation": "cdkDropListOrientation"; "id": "id"; "lockAxis": "cdkDropListLockAxis"; "disabled": "cdkDropListDisabled"; "sortingDisabled": "cdkDropListSortingDisabled"; "enterPredicate": "cdkDropListEnterPredicate"; "sortPredicate": "cdkDropListSortPredicate"; "autoScrollDisabled": "cdkDropListAutoScrollDisabled"; "autoScrollStep": "cdkDropListAutoScrollStep"; }, { "dropped": "cdkDropListDropped"; "entered": "cdkDropListEntered"; "exited": "cdkDropListExited"; "sorted": "cdkDropListSorted"; }, never>;
static ɵfac: i0.ɵɵFactoryDef<CdkDropList<any>, [null, null, null, null, { optional: true; }, { optional: true; skipSelf: true; }, { optional: true; }]>;
}

Expand Down Expand Up @@ -334,6 +336,7 @@ export declare type DropListOrientation = 'horizontal' | 'vertical';

export declare class DropListRef<T = any> {
autoScrollDisabled: boolean;
autoScrollStep: number;
beforeStarted: Subject<void>;
data: T;
disabled: boolean;
Expand Down