Skip to content

Commit 6db225e

Browse files
authored
fix(cdk/drag-drop): auto-scroll to the left not starting in rtl layout (#28334)
The drop list has some logic that prevents auto-scrolling when the container isn't scrollable. It didn't account for RTL which meant that, even though the rest of the logic works in RTL, auto-scrolling was being disabled incorrectly. Fixes #28326.
1 parent 1c2d1b7 commit 6db225e

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4352,7 +4352,7 @@ describe('CdkDrag', () => {
43524352
expect(list.scrollTop).toBeLessThan(initialScrollDistance);
43534353
}));
43544354

4355-
it('should auto-scroll right if the user holds their pointer at right edge', fakeAsync(() => {
4355+
it('should auto-scroll right if the user holds their pointer at right edge in ltr', fakeAsync(() => {
43564356
const fixture = createComponent(DraggableInScrollableHorizontalDropZone);
43574357
fixture.detectChanges();
43584358
const item = fixture.componentInstance.dragItems.first.element.nativeElement;
@@ -4374,7 +4374,7 @@ describe('CdkDrag', () => {
43744374
expect(list.scrollLeft).toBeGreaterThan(0);
43754375
}));
43764376

4377-
it('should auto-scroll left if the user holds their pointer at left edge', fakeAsync(() => {
4377+
it('should auto-scroll left if the user holds their pointer at left edge in ltr', fakeAsync(() => {
43784378
const fixture = createComponent(DraggableInScrollableHorizontalDropZone);
43794379
fixture.detectChanges();
43804380
const item = fixture.componentInstance.dragItems.first.element.nativeElement;
@@ -4390,6 +4390,56 @@ describe('CdkDrag', () => {
43904390
expect(list.scrollLeft).toBeLessThan(initialScrollDistance);
43914391
}));
43924392

4393+
it('should auto-scroll right if the user holds their pointer at right edge in rtl', fakeAsync(() => {
4394+
const fixture = createComponent(DraggableInScrollableHorizontalDropZone, [
4395+
{
4396+
provide: Directionality,
4397+
useValue: {value: 'rtl', change: observableOf()},
4398+
},
4399+
]);
4400+
fixture.nativeElement.setAttribute('dir', 'rtl');
4401+
fixture.detectChanges();
4402+
const item = fixture.componentInstance.dragItems.first.element.nativeElement;
4403+
const list = fixture.componentInstance.dropInstance.element.nativeElement;
4404+
const listRect = list.getBoundingClientRect();
4405+
const initialScrollDistance = (list.scrollLeft = -list.scrollWidth);
4406+
4407+
startDraggingViaMouse(fixture, item);
4408+
dispatchMouseEvent(
4409+
document,
4410+
'mousemove',
4411+
listRect.left + listRect.width,
4412+
listRect.top + listRect.height / 2,
4413+
);
4414+
fixture.detectChanges();
4415+
tickAnimationFrames(20);
4416+
4417+
expect(list.scrollLeft).toBeGreaterThan(initialScrollDistance);
4418+
}));
4419+
4420+
it('should auto-scroll left if the user holds their pointer at left edge in rtl', fakeAsync(() => {
4421+
const fixture = createComponent(DraggableInScrollableHorizontalDropZone, [
4422+
{
4423+
provide: Directionality,
4424+
useValue: {value: 'rtl', change: observableOf()},
4425+
},
4426+
]);
4427+
fixture.nativeElement.setAttribute('dir', 'rtl');
4428+
fixture.detectChanges();
4429+
const item = fixture.componentInstance.dragItems.first.element.nativeElement;
4430+
const list = fixture.componentInstance.dropInstance.element.nativeElement;
4431+
const listRect = list.getBoundingClientRect();
4432+
4433+
expect(list.scrollLeft).toBe(0);
4434+
4435+
startDraggingViaMouse(fixture, item);
4436+
dispatchMouseEvent(document, 'mousemove', listRect.left, listRect.top + listRect.height / 2);
4437+
fixture.detectChanges();
4438+
tickAnimationFrames(20);
4439+
4440+
expect(list.scrollLeft).toBeLessThan(0);
4441+
}));
4442+
43934443
it('should be able to start auto scrolling with a drag boundary', fakeAsync(() => {
43944444
const fixture = createComponent(DraggableInScrollableHorizontalDropZone);
43954445
fixture.componentInstance.boundarySelector = '.drop-list';

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ export class DropListRef<T = any> {
455455
[verticalScrollDirection, horizontalScrollDirection] = getElementScrollDirections(
456456
element as HTMLElement,
457457
position.clientRect,
458+
this._sortStrategy.direction,
458459
pointerX,
459460
pointerY,
460461
);
@@ -746,12 +747,14 @@ function getHorizontalScrollDirection(clientRect: DOMRect, pointerX: number) {
746747
* assuming that the user's pointer is already within it scrollable region.
747748
* @param element Element for which we should calculate the scroll direction.
748749
* @param clientRect Bounding client rectangle of the element.
750+
* @param direction Layout direction of the drop list.
749751
* @param pointerX Position of the user's pointer along the x axis.
750752
* @param pointerY Position of the user's pointer along the y axis.
751753
*/
752754
function getElementScrollDirections(
753755
element: HTMLElement,
754756
clientRect: DOMRect,
757+
direction: Direction,
755758
pointerX: number,
756759
pointerY: number,
757760
): [AutoScrollVerticalDirection, AutoScrollHorizontalDirection] {
@@ -779,12 +782,23 @@ function getElementScrollDirections(
779782
if (computedHorizontal) {
780783
const scrollLeft = element.scrollLeft;
781784

782-
if (computedHorizontal === AutoScrollHorizontalDirection.LEFT) {
783-
if (scrollLeft > 0) {
785+
if (direction === 'rtl') {
786+
if (computedHorizontal === AutoScrollHorizontalDirection.RIGHT) {
787+
// In RTL `scrollLeft` will be negative when scrolled.
788+
if (scrollLeft < 0) {
789+
horizontalScrollDirection = AutoScrollHorizontalDirection.RIGHT;
790+
}
791+
} else if (element.scrollWidth + scrollLeft > element.clientWidth) {
784792
horizontalScrollDirection = AutoScrollHorizontalDirection.LEFT;
785793
}
786-
} else if (element.scrollWidth - scrollLeft > element.clientWidth) {
787-
horizontalScrollDirection = AutoScrollHorizontalDirection.RIGHT;
794+
} else {
795+
if (computedHorizontal === AutoScrollHorizontalDirection.LEFT) {
796+
if (scrollLeft > 0) {
797+
horizontalScrollDirection = AutoScrollHorizontalDirection.LEFT;
798+
}
799+
} else if (element.scrollWidth - scrollLeft > element.clientWidth) {
800+
horizontalScrollDirection = AutoScrollHorizontalDirection.RIGHT;
801+
}
788802
}
789803
}
790804

0 commit comments

Comments
 (0)