fix(tabs): do not focus tabs when selectedIndex is set (#729)

This commit is contained in:
Mathieu Puech 2020-05-27 10:44:39 -04:00 committed by GitHub
parent eabab4b78b
commit e4ec227566
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 23 deletions

View file

@ -34,9 +34,8 @@ const cleanButton = ({ element, clickHandler, keydownHandler, keyupHandler }) =>
element.removeEventListener('keydown', keydownHandler);
};
const selectButton = (element, firstUpdate = false) => {
// Don't focus on first update, as the component might be lower on the page
if (!firstUpdate) {
const selectButton = (element, withFocus = false) => {
if (withFocus) {
element.focus();
}
@ -123,7 +122,6 @@ export class LionTabs extends LitElement {
firstUpdated() {
super.firstUpdated();
this.__firstUpdate = true;
this.__setupSlots();
}
@ -132,7 +130,7 @@ export class LionTabs extends LitElement {
const handleSlotChange = () => {
this.__cleanStore();
this.__setupStore();
this.__updateSelected();
this.__updateSelected(false);
};
tabSlot.addEventListener('slotchange', handleSlotChange);
}
@ -178,7 +176,7 @@ export class LionTabs extends LitElement {
__createButtonClickHandler(index) {
return () => {
this.selectedIndex = index;
this._setSelectedIndexWithFocus(index);
};
}
@ -187,34 +185,41 @@ export class LionTabs extends LitElement {
case 'ArrowDown':
case 'ArrowRight':
if (this.selectedIndex + 1 >= this._pairCount) {
this.selectedIndex = 0;
this._setSelectedIndexWithFocus(0);
} else {
this.selectedIndex += 1;
this._setSelectedIndexWithFocus(this.selectedIndex + 1);
}
break;
case 'ArrowUp':
case 'ArrowLeft':
if (this.selectedIndex <= 0) {
this.selectedIndex = this._pairCount - 1;
this._setSelectedIndexWithFocus(this._pairCount - 1);
} else {
this.selectedIndex -= 1;
this._setSelectedIndexWithFocus(this.selectedIndex - 1);
}
break;
case 'Home':
this.selectedIndex = 0;
this._setSelectedIndexWithFocus(0);
break;
case 'End':
this.selectedIndex = this._pairCount - 1;
this._setSelectedIndexWithFocus(this._pairCount - 1);
break;
/* no default */
}
}
set selectedIndex(value) {
this.__firstUpdate = false;
const stale = this.__selectedIndex;
this.__selectedIndex = value;
this.__updateSelected();
this.__updateSelected(false);
this.dispatchEvent(new Event('selected-changed'));
this.requestUpdate('selectedIndex', stale);
}
_setSelectedIndexWithFocus(value) {
const stale = this.__selectedIndex;
this.__selectedIndex = value;
this.__updateSelected(true);
this.dispatchEvent(new Event('selected-changed'));
this.requestUpdate('selectedIndex', stale);
}
@ -227,7 +232,7 @@ export class LionTabs extends LitElement {
return this.__store.length;
}
__updateSelected() {
__updateSelected(withFocus = false) {
if (!(this.__store && this.__store[this.selectedIndex])) {
return;
}
@ -245,7 +250,7 @@ export class LionTabs extends LitElement {
}
const { button: currentButton, panel: currentPanel } = this.__store[this.selectedIndex];
if (currentButton) {
selectButton(currentButton, this.__firstUpdate);
selectButton(currentButton, withFocus);
}
if (currentPanel) {
selectPanel(currentPanel);

View file

@ -244,7 +244,7 @@ describe('<lion-tabs>', () => {
});
describe('Initializing without Focus', () => {
it('keeps track of when the component is updated', async () => {
it('does not focus a tab when setting selectedIndex property', async () => {
const el = await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
@ -254,9 +254,9 @@ describe('<lion-tabs>', () => {
</lion-tabs>
`);
expect(el.__firstUpdate).to.be.true;
el.selectedIndex = 1;
expect(el.__firstUpdate).to.be.false;
expect(el.querySelector('[slot="tab"]:nth-of-type(2)') === document.activeElement).to.be
.false;
});
it('does not focus a tab on firstUpdate', async () => {
@ -272,7 +272,7 @@ describe('<lion-tabs>', () => {
expect(tabs.some(tab => tab === document.activeElement)).to.be.false;
});
it('focuses on a tab when switching the selectedIndex', async () => {
it('focuses on a tab when setting with _setSelectedIndexWithFocus method', async () => {
const el = await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
@ -281,12 +281,25 @@ describe('<lion-tabs>', () => {
<div slot="panel">panel 2</div>
</lion-tabs>
`);
el.selectedIndex = 1;
const tab = Array.from(el.children).filter(child => child.slot === 'tab')[1];
expect(tab).to.equal(document.activeElement);
el._setSelectedIndexWithFocus(1);
expect(el.querySelector('[slot="tab"]:nth-of-type(2)') === document.activeElement).to.be.true;
});
});
it('focuses on a tab when the selected tab is changed by user interaction', async () => {
const el = await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
<div slot="panel">panel 1</div>
<button slot="tab">tab 2</button>
<div slot="panel">panel 2</div>
</lion-tabs>
`);
const secondTab = el.querySelector('[slot="tab"]:nth-of-type(2)');
secondTab.dispatchEvent(new MouseEvent('click'));
expect(secondTab === document.activeElement).to.be.true;
});
describe('Accessibility', () => {
it('does not make panels focusable', async () => {
const el = await fixture(html`