diff --git a/src/cdk/drag-drop/directives/drag.spec.ts b/src/cdk/drag-drop/directives/drag.spec.ts index c816ad9ff7ba..385567c4be5d 100644 --- a/src/cdk/drag-drop/directives/drag.spec.ts +++ b/src/cdk/drag-drop/directives/drag.spec.ts @@ -4352,7 +4352,7 @@ describe('CdkDrag', () => { expect(list.scrollTop).toBeLessThan(initialScrollDistance); })); - it('should auto-scroll right if the user holds their pointer at right edge', fakeAsync(() => { + it('should auto-scroll right if the user holds their pointer at right edge in ltr', fakeAsync(() => { const fixture = createComponent(DraggableInScrollableHorizontalDropZone); fixture.detectChanges(); const item = fixture.componentInstance.dragItems.first.element.nativeElement; @@ -4374,7 +4374,7 @@ describe('CdkDrag', () => { expect(list.scrollLeft).toBeGreaterThan(0); })); - it('should auto-scroll left if the user holds their pointer at left edge', fakeAsync(() => { + it('should auto-scroll left if the user holds their pointer at left edge in ltr', fakeAsync(() => { const fixture = createComponent(DraggableInScrollableHorizontalDropZone); fixture.detectChanges(); const item = fixture.componentInstance.dragItems.first.element.nativeElement; @@ -4390,6 +4390,56 @@ describe('CdkDrag', () => { expect(list.scrollLeft).toBeLessThan(initialScrollDistance); })); + it('should auto-scroll right if the user holds their pointer at right edge in rtl', fakeAsync(() => { + const fixture = createComponent(DraggableInScrollableHorizontalDropZone, [ + { + provide: Directionality, + useValue: {value: 'rtl', change: observableOf()}, + }, + ]); + fixture.nativeElement.setAttribute('dir', 'rtl'); + fixture.detectChanges(); + const item = fixture.componentInstance.dragItems.first.element.nativeElement; + const list = fixture.componentInstance.dropInstance.element.nativeElement; + const listRect = list.getBoundingClientRect(); + const initialScrollDistance = (list.scrollLeft = -list.scrollWidth); + + startDraggingViaMouse(fixture, item); + dispatchMouseEvent( + document, + 'mousemove', + listRect.left + listRect.width, + listRect.top + listRect.height / 2, + ); + fixture.detectChanges(); + tickAnimationFrames(20); + + expect(list.scrollLeft).toBeGreaterThan(initialScrollDistance); + })); + + it('should auto-scroll left if the user holds their pointer at left edge in rtl', fakeAsync(() => { + const fixture = createComponent(DraggableInScrollableHorizontalDropZone, [ + { + provide: Directionality, + useValue: {value: 'rtl', change: observableOf()}, + }, + ]); + fixture.nativeElement.setAttribute('dir', 'rtl'); + fixture.detectChanges(); + const item = fixture.componentInstance.dragItems.first.element.nativeElement; + const list = fixture.componentInstance.dropInstance.element.nativeElement; + const listRect = list.getBoundingClientRect(); + + expect(list.scrollLeft).toBe(0); + + startDraggingViaMouse(fixture, item); + dispatchMouseEvent(document, 'mousemove', listRect.left, listRect.top + listRect.height / 2); + fixture.detectChanges(); + tickAnimationFrames(20); + + expect(list.scrollLeft).toBeLessThan(0); + })); + it('should be able to start auto scrolling with a drag boundary', fakeAsync(() => { const fixture = createComponent(DraggableInScrollableHorizontalDropZone); fixture.componentInstance.boundarySelector = '.drop-list'; diff --git a/src/cdk/drag-drop/drop-list-ref.ts b/src/cdk/drag-drop/drop-list-ref.ts index f4cc9a9e1a5f..5ad492c6e715 100644 --- a/src/cdk/drag-drop/drop-list-ref.ts +++ b/src/cdk/drag-drop/drop-list-ref.ts @@ -455,6 +455,7 @@ export class DropListRef { [verticalScrollDirection, horizontalScrollDirection] = getElementScrollDirections( element as HTMLElement, position.clientRect, + this._sortStrategy.direction, pointerX, pointerY, ); @@ -746,12 +747,14 @@ function getHorizontalScrollDirection(clientRect: DOMRect, pointerX: number) { * assuming that the user's pointer is already within it scrollable region. * @param element Element for which we should calculate the scroll direction. * @param clientRect Bounding client rectangle of the element. + * @param direction Layout direction of the drop list. * @param pointerX Position of the user's pointer along the x axis. * @param pointerY Position of the user's pointer along the y axis. */ function getElementScrollDirections( element: HTMLElement, clientRect: DOMRect, + direction: Direction, pointerX: number, pointerY: number, ): [AutoScrollVerticalDirection, AutoScrollHorizontalDirection] { @@ -779,12 +782,23 @@ function getElementScrollDirections( if (computedHorizontal) { const scrollLeft = element.scrollLeft; - if (computedHorizontal === AutoScrollHorizontalDirection.LEFT) { - if (scrollLeft > 0) { + if (direction === 'rtl') { + if (computedHorizontal === AutoScrollHorizontalDirection.RIGHT) { + // In RTL `scrollLeft` will be negative when scrolled. + if (scrollLeft < 0) { + horizontalScrollDirection = AutoScrollHorizontalDirection.RIGHT; + } + } else if (element.scrollWidth + scrollLeft > element.clientWidth) { horizontalScrollDirection = AutoScrollHorizontalDirection.LEFT; } - } else if (element.scrollWidth - scrollLeft > element.clientWidth) { - horizontalScrollDirection = AutoScrollHorizontalDirection.RIGHT; + } else { + if (computedHorizontal === AutoScrollHorizontalDirection.LEFT) { + if (scrollLeft > 0) { + horizontalScrollDirection = AutoScrollHorizontalDirection.LEFT; + } + } else if (element.scrollWidth - scrollLeft > element.clientWidth) { + horizontalScrollDirection = AutoScrollHorizontalDirection.RIGHT; + } } }