fix(tabs): do not focus tabs when selectedIndex is set (#729)
This commit is contained in:
parent
eabab4b78b
commit
e4ec227566
2 changed files with 41 additions and 23 deletions
|
|
@ -34,9 +34,8 @@ const cleanButton = ({ element, clickHandler, keydownHandler, keyupHandler }) =>
|
||||||
element.removeEventListener('keydown', keydownHandler);
|
element.removeEventListener('keydown', keydownHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectButton = (element, firstUpdate = false) => {
|
const selectButton = (element, withFocus = false) => {
|
||||||
// Don't focus on first update, as the component might be lower on the page
|
if (withFocus) {
|
||||||
if (!firstUpdate) {
|
|
||||||
element.focus();
|
element.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,7 +122,6 @@ export class LionTabs extends LitElement {
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
super.firstUpdated();
|
super.firstUpdated();
|
||||||
this.__firstUpdate = true;
|
|
||||||
this.__setupSlots();
|
this.__setupSlots();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,7 +130,7 @@ export class LionTabs extends LitElement {
|
||||||
const handleSlotChange = () => {
|
const handleSlotChange = () => {
|
||||||
this.__cleanStore();
|
this.__cleanStore();
|
||||||
this.__setupStore();
|
this.__setupStore();
|
||||||
this.__updateSelected();
|
this.__updateSelected(false);
|
||||||
};
|
};
|
||||||
tabSlot.addEventListener('slotchange', handleSlotChange);
|
tabSlot.addEventListener('slotchange', handleSlotChange);
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +176,7 @@ export class LionTabs extends LitElement {
|
||||||
|
|
||||||
__createButtonClickHandler(index) {
|
__createButtonClickHandler(index) {
|
||||||
return () => {
|
return () => {
|
||||||
this.selectedIndex = index;
|
this._setSelectedIndexWithFocus(index);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,34 +185,41 @@ export class LionTabs extends LitElement {
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
case 'ArrowRight':
|
case 'ArrowRight':
|
||||||
if (this.selectedIndex + 1 >= this._pairCount) {
|
if (this.selectedIndex + 1 >= this._pairCount) {
|
||||||
this.selectedIndex = 0;
|
this._setSelectedIndexWithFocus(0);
|
||||||
} else {
|
} else {
|
||||||
this.selectedIndex += 1;
|
this._setSelectedIndexWithFocus(this.selectedIndex + 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
if (this.selectedIndex <= 0) {
|
if (this.selectedIndex <= 0) {
|
||||||
this.selectedIndex = this._pairCount - 1;
|
this._setSelectedIndexWithFocus(this._pairCount - 1);
|
||||||
} else {
|
} else {
|
||||||
this.selectedIndex -= 1;
|
this._setSelectedIndexWithFocus(this.selectedIndex - 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Home':
|
case 'Home':
|
||||||
this.selectedIndex = 0;
|
this._setSelectedIndexWithFocus(0);
|
||||||
break;
|
break;
|
||||||
case 'End':
|
case 'End':
|
||||||
this.selectedIndex = this._pairCount - 1;
|
this._setSelectedIndexWithFocus(this._pairCount - 1);
|
||||||
break;
|
break;
|
||||||
/* no default */
|
/* no default */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set selectedIndex(value) {
|
set selectedIndex(value) {
|
||||||
this.__firstUpdate = false;
|
|
||||||
const stale = this.__selectedIndex;
|
const stale = this.__selectedIndex;
|
||||||
this.__selectedIndex = value;
|
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.dispatchEvent(new Event('selected-changed'));
|
||||||
this.requestUpdate('selectedIndex', stale);
|
this.requestUpdate('selectedIndex', stale);
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +232,7 @@ export class LionTabs extends LitElement {
|
||||||
return this.__store.length;
|
return this.__store.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
__updateSelected() {
|
__updateSelected(withFocus = false) {
|
||||||
if (!(this.__store && this.__store[this.selectedIndex])) {
|
if (!(this.__store && this.__store[this.selectedIndex])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +250,7 @@ export class LionTabs extends LitElement {
|
||||||
}
|
}
|
||||||
const { button: currentButton, panel: currentPanel } = this.__store[this.selectedIndex];
|
const { button: currentButton, panel: currentPanel } = this.__store[this.selectedIndex];
|
||||||
if (currentButton) {
|
if (currentButton) {
|
||||||
selectButton(currentButton, this.__firstUpdate);
|
selectButton(currentButton, withFocus);
|
||||||
}
|
}
|
||||||
if (currentPanel) {
|
if (currentPanel) {
|
||||||
selectPanel(currentPanel);
|
selectPanel(currentPanel);
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,7 @@ describe('<lion-tabs>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Initializing without Focus', () => {
|
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`
|
const el = await fixture(html`
|
||||||
<lion-tabs>
|
<lion-tabs>
|
||||||
<button slot="tab">tab 1</button>
|
<button slot="tab">tab 1</button>
|
||||||
|
|
@ -254,9 +254,9 @@ describe('<lion-tabs>', () => {
|
||||||
</lion-tabs>
|
</lion-tabs>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(el.__firstUpdate).to.be.true;
|
|
||||||
el.selectedIndex = 1;
|
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 () => {
|
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;
|
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`
|
const el = await fixture(html`
|
||||||
<lion-tabs>
|
<lion-tabs>
|
||||||
<button slot="tab">tab 1</button>
|
<button slot="tab">tab 1</button>
|
||||||
|
|
@ -281,12 +281,25 @@ describe('<lion-tabs>', () => {
|
||||||
<div slot="panel">panel 2</div>
|
<div slot="panel">panel 2</div>
|
||||||
</lion-tabs>
|
</lion-tabs>
|
||||||
`);
|
`);
|
||||||
el.selectedIndex = 1;
|
el._setSelectedIndexWithFocus(1);
|
||||||
const tab = Array.from(el.children).filter(child => child.slot === 'tab')[1];
|
expect(el.querySelector('[slot="tab"]:nth-of-type(2)') === document.activeElement).to.be.true;
|
||||||
expect(tab).to.equal(document.activeElement);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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', () => {
|
describe('Accessibility', () => {
|
||||||
it('does not make panels focusable', async () => {
|
it('does not make panels focusable', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue