fix(button): do not override user provided tabindex

This commit is contained in:
Thomas Allmer 2019-05-16 08:19:49 +02:00 committed by Thomas Allmer
parent 92760e8ca3
commit 76ccb94435
2 changed files with 83 additions and 30 deletions

View file

@ -8,6 +8,14 @@ export class LionButton extends DelegateMixin(SlotMixin(LionLitElement)) {
type: Boolean, type: Boolean,
reflect: true, reflect: true,
}, },
role: {
type: String,
reflect: true,
},
tabindex: {
type: Number,
reflect: true,
},
}; };
} }
@ -93,10 +101,10 @@ export class LionButton extends DelegateMixin(SlotMixin(LionLitElement)) {
]; ];
} }
update(changedProperties) { _requestUpdate(name, oldValue) {
super.update(changedProperties); super._requestUpdate(name, oldValue);
if (changedProperties.has('disabled')) { if (name === 'disabled') {
this.__onDisabledChanged(); this.__onDisabledChanged(oldValue);
} }
} }
@ -125,12 +133,13 @@ export class LionButton extends DelegateMixin(SlotMixin(LionLitElement)) {
constructor() { constructor() {
super(); super();
this.disabled = false; this.disabled = false;
this.role = 'button';
this.tabindex = 0;
this.__keydownDelegationHandler = this.__keydownDelegationHandler.bind(this); this.__keydownDelegationHandler = this.__keydownDelegationHandler.bind(this);
} }
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.__setupA11y();
this.__setupKeydownDelegation(); this.__setupKeydownDelegation();
} }
@ -144,11 +153,6 @@ export class LionButton extends DelegateMixin(SlotMixin(LionLitElement)) {
this.$$slot('_button').click(); this.$$slot('_button').click();
} }
__setupA11y() {
this.setAttribute('role', 'button');
this.setAttribute('tabindex', this.disabled ? -1 : 0);
}
__setupKeydownDelegation() { __setupKeydownDelegation() {
this.addEventListener('keydown', this.__keydownDelegationHandler); this.addEventListener('keydown', this.__keydownDelegationHandler);
} }
@ -167,6 +171,11 @@ export class LionButton extends DelegateMixin(SlotMixin(LionLitElement)) {
} }
__onDisabledChanged() { __onDisabledChanged() {
this.setAttribute('tabindex', this.disabled ? -1 : 0); if (this.disabled) {
this.__originalTabIndex = this.tabindex;
this.tabindex = -1;
} else {
this.tabindex = this.__originalTabIndex;
}
} }
} }

View file

@ -6,43 +6,87 @@ import '../lion-button.js';
describe('lion-button', () => { describe('lion-button', () => {
it('behaves like native `button` in terms of a11y', async () => { it('behaves like native `button` in terms of a11y', async () => {
const lionButton = await fixture(`<lion-button>foo</lion-button>`); const el = await fixture(`<lion-button>foo</lion-button>`);
expect(lionButton.getAttribute('role')).to.equal('button'); expect(el.getAttribute('role')).to.equal('button');
expect(lionButton.getAttribute('tabindex')).to.equal('0'); expect(el.getAttribute('tabindex')).to.equal('0');
}); });
it('has no type by default on the native button', async () => { it('has no type by default on the native button', async () => {
const lionButton = await fixture(`<lion-button>foo</lion-button>`); const el = await fixture(`<lion-button>foo</lion-button>`);
const nativeButton = lionButton.$$slot('_button'); const nativeButton = el.$$slot('_button');
expect(nativeButton.getAttribute('type')).to.be.null; expect(nativeButton.getAttribute('type')).to.be.null;
}); });
it('has type="submit" on the native button when set', async () => { it('has type="submit" on the native button when set', async () => {
const lionButton = await fixture(`<lion-button type="submit">foo</lion-button>`); const el = await fixture(`<lion-button type="submit">foo</lion-button>`);
const nativeButton = lionButton.$$slot('_button'); const nativeButton = el.$$slot('_button');
expect(nativeButton.getAttribute('type')).to.equal('submit'); expect(nativeButton.getAttribute('type')).to.equal('submit');
}); });
it('hides the native button in the UI', async () => { it('hides the native button in the UI', async () => {
const lionButton = await fixture(`<lion-button>foo</lion-button>`); const el = await fixture(`<lion-button>foo</lion-button>`);
const nativeButton = lionButton.$$slot('_button'); const nativeButton = el.$$slot('_button');
expect(nativeButton.getAttribute('tabindex')).to.equal('-1'); expect(nativeButton.getAttribute('tabindex')).to.equal('-1');
expect(window.getComputedStyle(nativeButton).visibility).to.equal('hidden'); expect(window.getComputedStyle(nativeButton).visibility).to.equal('hidden');
}); });
it('can be disabled imperatively', async () => { it('can be disabled imperatively', async () => {
const lionButton = await fixture(`<lion-button disabled>foo</lion-button>`); const el = await fixture(`<lion-button disabled>foo</lion-button>`);
expect(lionButton.getAttribute('tabindex')).to.equal('-1'); expect(el.getAttribute('tabindex')).to.equal('-1');
lionButton.disabled = false; el.disabled = false;
await lionButton.updateComplete; await el.updateComplete;
expect(lionButton.getAttribute('tabindex')).to.equal('0'); expect(el.getAttribute('tabindex')).to.equal('0');
expect(lionButton.hasAttribute('disabled')).to.equal(false); expect(el.hasAttribute('disabled')).to.equal(false);
lionButton.disabled = true; el.disabled = true;
await lionButton.updateComplete; await el.updateComplete;
expect(lionButton.getAttribute('tabindex')).to.equal('-1'); expect(el.getAttribute('tabindex')).to.equal('-1');
expect(lionButton.hasAttribute('disabled')).to.equal(true); expect(el.hasAttribute('disabled')).to.equal(true);
});
describe('a11y', () => {
it('has a role="button" by default', async () => {
const el = await fixture(`<lion-button>foo</lion-button>`);
expect(el.getAttribute('role')).to.equal('button');
el.role = 'foo';
await el.updateComplete;
expect(el.getAttribute('role')).to.equal('foo');
});
it('does not override user provided role', async () => {
const el = await fixture(`<lion-button role="foo">foo</lion-button>`);
expect(el.getAttribute('role')).to.equal('foo');
});
it('has a tabindex="0" by default', async () => {
const el = await fixture(`<lion-button>foo</lion-button>`);
expect(el.getAttribute('tabindex')).to.equal('0');
});
it('has a tabindex="-1" when disabled', async () => {
const el = await fixture(`<lion-button disabled>foo</lion-button>`);
expect(el.getAttribute('tabindex')).to.equal('-1');
el.disabled = false;
await el.updateComplete;
expect(el.getAttribute('tabindex')).to.equal('0');
el.disabled = true;
await el.updateComplete;
expect(el.getAttribute('tabindex')).to.equal('-1');
});
it('does not override user provided tabindex', async () => {
const el = await fixture(`<lion-button tabindex="5">foo</lion-button>`);
expect(el.getAttribute('tabindex')).to.equal('5');
});
it('disabled does not override user provided tabindex', async () => {
const el = await fixture(`<lion-button tabindex="5" disabled>foo</lion-button>`);
expect(el.getAttribute('tabindex')).to.equal('-1');
el.disabled = false;
await el.updateComplete;
expect(el.getAttribute('tabindex')).to.equal('5');
});
}); });
describe('form integration', () => { describe('form integration', () => {