Skip to content

Commit bc6d867

Browse files
authored
fix: ensure last cell is fully scrolled into view when focused (#10468)
1 parent 78c1bd8 commit bc6d867

File tree

7 files changed

+60
-41
lines changed

7 files changed

+60
-41
lines changed

packages/grid/src/vaadin-grid-keyboard-navigation-mixin.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ export const KeyboardNavigationMixin = (superClass) =>
603603
this._scrollHorizontallyToCell(dstCell);
604604
}
605605

606-
dstCell.focus();
606+
dstCell.focus({ preventScroll: true });
607607
}
608608
}
609609

@@ -1016,8 +1016,9 @@ export const KeyboardNavigationMixin = (superClass) =>
10161016
const dstRow = dstCell.parentNode;
10171017
const dstCellIndex = Array.from(dstRow.children).indexOf(dstCell);
10181018
const tableRect = this.$.table.getBoundingClientRect();
1019-
let leftBoundary = tableRect.left,
1020-
rightBoundary = tableRect.right;
1019+
const scrollbarWidth = this.$.table.clientWidth - this.$.table.offsetWidth;
1020+
let leftBoundary = tableRect.left - (this.__isRTL ? scrollbarWidth : 0);
1021+
let rightBoundary = tableRect.right + (this.__isRTL ? 0 : scrollbarWidth);
10211022
for (let i = dstCellIndex - 1; i >= 0; i--) {
10221023
const cell = dstRow.children[i];
10231024
if (cell.hasAttribute('hidden') || isDetailsCell(cell)) {
@@ -1040,10 +1041,10 @@ export const KeyboardNavigationMixin = (superClass) =>
10401041
}
10411042

10421043
if (dstCellRect.left < leftBoundary) {
1043-
this.$.table.scrollLeft += Math.round(dstCellRect.left - leftBoundary);
1044+
this.$.table.scrollLeft += dstCellRect.left - leftBoundary;
10441045
}
10451046
if (dstCellRect.right > rightBoundary) {
1046-
this.$.table.scrollLeft += Math.round(dstCellRect.right - rightBoundary);
1047+
this.$.table.scrollLeft += dstCellRect.right - rightBoundary;
10471048
}
10481049
}
10491050

packages/grid/test/keyboard-navigation.test.js

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,9 +1008,59 @@ describe('keyboard navigation', () => {
10081008
expect(grid.shadowRoot.activeElement.parentNode.index).to.equal(grid.size - 1);
10091009
});
10101010

1011+
['ltr', 'rtl'].forEach((direction) => {
1012+
describe(`horizontal scrolling (${direction})`, () => {
1013+
before(() => {
1014+
document.documentElement.setAttribute('dir', direction);
1015+
});
1016+
1017+
after(() => {
1018+
document.documentElement.removeAttribute('dir');
1019+
});
1020+
1021+
beforeEach(() => {
1022+
grid.style.width = '100px'; // Column default min width is 100px
1023+
grid.$.table.style.overflow = 'scroll'; // Force scrollbars to be visible
1024+
});
1025+
1026+
it('should scroll cells visible with home', async () => {
1027+
focusItem(0);
1028+
grid.$.table.scrollLeft = (direction === 'ltr' ? 1 : -1) * 999999999;
1029+
1030+
flushGrid(grid);
1031+
home();
1032+
await nextFrame();
1033+
1034+
expect(grid.$.table.scrollLeft).to.equal(0);
1035+
});
1036+
1037+
it(`should scroll cells visible with end`, async () => {
1038+
await nextFrame();
1039+
1040+
focusItem(0);
1041+
await nextFrame();
1042+
1043+
end();
1044+
await nextFrame();
1045+
1046+
flushGrid(grid);
1047+
1048+
// Force reflow to workaround a Safari rendering issue
1049+
if (isDesktopSafari) {
1050+
grid.style.display = 'flex';
1051+
await nextFrame();
1052+
grid.style.display = '';
1053+
}
1054+
1055+
expect(Math.abs(grid.$.table.scrollLeft)).to.equal(grid.$.table.scrollWidth - grid.$.table.clientWidth);
1056+
});
1057+
});
1058+
});
1059+
10111060
describe('horizontal scrolling', () => {
10121061
beforeEach(() => {
10131062
grid.style.width = '100px'; // Column default min width is 100px
1063+
grid.$.table.style.overflow = 'scroll'; // Force scrollbars to be visible
10141064
});
10151065

10161066
it('should scroll cells visible with right arrow on header', () => {
@@ -1062,40 +1112,8 @@ describe('keyboard navigation', () => {
10621112
expect(grid.$.table.scrollLeft).to.equal(0);
10631113
});
10641114

1065-
it('should scroll cells visible with home', () => {
1066-
focusItem(0);
1067-
grid.$.table.scrollLeft = 999999999;
1068-
1069-
flushGrid(grid);
1070-
home();
1071-
1072-
expect(grid.$.table.scrollLeft).to.equal(0);
1073-
});
1074-
1075-
it('should scroll cells visible with end', async () => {
1076-
await nextFrame();
1077-
1078-
focusItem(0);
1079-
await nextFrame();
1080-
1081-
end();
1082-
await nextFrame();
1083-
1084-
flushGrid(grid);
1085-
1086-
// Force reflow to workaround a Safari rendering issue
1087-
if (isDesktopSafari) {
1088-
grid.style.display = 'flex';
1089-
await nextFrame();
1090-
grid.style.display = '';
1091-
}
1092-
1093-
expect(grid.$.table.scrollLeft).to.equal(grid.$.table.scrollWidth - grid.$.table.offsetWidth);
1094-
});
1095-
10961115
it('should scroll cell visible under from frozen cells with left arrow', async () => {
1097-
const scrollbarWidth = grid.$.table.offsetWidth - grid.$.table.clientWidth;
1098-
grid.style.width = `${200 + scrollbarWidth}px`; // Column default min width is 100px
1116+
grid.style.width = '200px'; // Column default min width is 100px
10991117
grid.style.border = 'none';
11001118
grid._columnTree[0][0].frozen = true;
11011119

@@ -1108,8 +1126,7 @@ describe('keyboard navigation', () => {
11081126
});
11091127

11101128
it('should scroll cell visible under from frozen to end cells with right arrow', async () => {
1111-
const scrollbarWidth = grid.$.table.offsetWidth - grid.$.table.clientWidth;
1112-
grid.style.width = `${200 + scrollbarWidth}px`; // Column default min width is 100px
1129+
grid.style.width = '200px'; // Column default min width is 100px
11131130
grid.style.border = 'none';
11141131
grid._columnTree[0][2].frozenToEnd = true;
11151132
await aTimeout(0);
@@ -1119,7 +1136,7 @@ describe('keyboard navigation', () => {
11191136
left();
11201137
await aTimeout(0);
11211138
right();
1122-
expect(grid.$.table.scrollLeft).to.equal(grid.$.table.scrollWidth - grid.$.table.offsetWidth);
1139+
expect(grid.$.table.scrollLeft).to.equal(grid.$.table.scrollWidth - grid.$.table.clientWidth);
11231140
});
11241141

11251142
it('should scroll cells visible with left arrow on footer', async () => {
-6 Bytes
Loading
-18 Bytes
Loading
-7 Bytes
Loading
-13 Bytes
Loading

web-test-runner.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const unitTestsConfig = createUnitTestsConfig({
99
launchOptions: {
1010
channel: 'chrome',
1111
headless: true,
12+
ignoreDefaultArgs: ['--hide-scrollbars'],
1213
},
1314
}),
1415
],

0 commit comments

Comments
 (0)