Skip to content

Commit

Permalink
fix: restore focused element reference on size change (#3329)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomivirkki committed Jan 24, 2022
1 parent fb594c3 commit 09f2c94
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
33 changes: 33 additions & 0 deletions packages/grid/src/vaadin-grid-keyboard-navigation-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,37 @@ export const KeyboardNavigationMixin = (superClass) =>
this._updateGridSectionFocusTarget(this._footerFocusable);
}

/**
* Since the focused cell/row state is stored as an element reference, the reference may get
* out of sync when the virtual indexes for elements update due to effective size change.
* This function updates the reference to the correct element after a possible index change.
* @private
*/
__updateItemsFocusable() {
if (!this._itemsFocusable) {
return;
}

const wasFocused = this.shadowRoot.activeElement === this._itemsFocusable;

this._getVisibleRows().forEach((row) => {
if (row.index === this._focusedItemIndex) {
if (this.__rowFocusMode) {
// Row focus mode
this._itemsFocusable = row;
} else if (this._itemsFocusable.parentElement) {
// Cell focus mode
const cellIndex = [...this._itemsFocusable.parentElement.children].indexOf(this._itemsFocusable);
this._itemsFocusable = row.children[cellIndex];
}
}
});

if (wasFocused) {
this._itemsFocusable.focus();
}
}

/**
* @param {!KeyboardEvent} e
* @protected
Expand Down Expand Up @@ -805,6 +836,8 @@ export const KeyboardNavigationMixin = (superClass) =>
delete this._focusedColumnOrder;
this._itemsFocusable = this.__rowFocusMode ? firstVisibleRow : firstVisibleCell;
}
} else {
this.__updateItemsFocusable();
}
}

Expand Down
54 changes: 54 additions & 0 deletions packages/grid/test/keyboard-navigation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { sendKeys } from '@web/test-runner-commands';
import sinon from 'sinon';
import '@vaadin/polymer-legacy-adapter/template-renderer.js';
import '../vaadin-grid.js';
import '../vaadin-grid-tree-column.js';
import '../vaadin-grid-column-group.js';
import '../vaadin-grid-selection-column.js';
import {
Expand Down Expand Up @@ -2097,3 +2098,56 @@ describe('empty grid', () => {
expect(grid.shadowRoot.activeElement).to.equal(grid.$.focusexit);
});
});

describe('hierarchical data', () => {
// Let's use a count that equals the pageSize so we can ignore page + pageSize in the data provider
const itemsOnEachLevel = 50;

function hierarchicalDataProvider({ parentItem }, callback) {
const items = [...Array(itemsOnEachLevel).keys()].map((i) => {
return {
name: `${parentItem ? parentItem.name + '-' : ''}${i}`,
children: true
};
});

callback(items, itemsOnEachLevel);
}

beforeEach(() => {
grid = fixtureSync(`
<vaadin-grid>
<vaadin-grid-tree-column path="name"></vaadin-grid-tree-column>
</vaadin-grid>
`);

grid.dataProvider = hierarchicalDataProvider;
flushGrid(grid);
});

it('should not change focused cell on expand', async () => {
// Focus the first cell/row
focusItem(0);
// Press ctrl+end to move the focus to the last cell/row
ctrlEnd();
expect(grid.shadowRoot.activeElement.parentNode.index).to.equal(itemsOnEachLevel - 1);
// Press space to expand the row
await sendKeys({ press: 'Space' });
// Expect the focus to not have changed
expect(grid.shadowRoot.activeElement.parentNode.index).to.equal(itemsOnEachLevel - 1);
});

it('should not change focused cell on expand - row focus mode', async () => {
// Focus the first cell/row
focusItem(0);
// Press ctrl+end to move the focus to the last cell/row
ctrlEnd();
// Enter row focus mode
left();
expect(grid.shadowRoot.activeElement.index).to.equal(itemsOnEachLevel - 1);
// Press ArrowRight to expand the row
await sendKeys({ press: 'ArrowRight' });
// Expect the focus to not have changed
expect(grid.shadowRoot.activeElement.index).to.equal(itemsOnEachLevel - 1);
});
});

0 comments on commit 09f2c94

Please sign in to comment.