diff --git a/packages/button/src/LionButton.js b/packages/button/src/LionButton.js index f55e12558..23f027799 100644 --- a/packages/button/src/LionButton.js +++ b/packages/button/src/LionButton.js @@ -10,6 +10,10 @@ export class LionButton extends DisabledWithTabIndexMixin( type: String, reflect: true, }, + active: { + type: Boolean, + reflect: true, + }, }; } @@ -83,8 +87,8 @@ export class LionButton extends DisabledWithTabIndexMixin( background: #f4f6f7; } - :host(:active) .btn, - .btn[active] { + :host(:active) .btn, /* keep native :active to render quickly where possible */ + :host([active]) .btn /* use custom [active] to fix IE11 */ { /* if you extend, please overwrite */ background: gray; } @@ -128,6 +132,7 @@ export class LionButton extends DisabledWithTabIndexMixin( constructor() { super(); this.role = 'button'; + this.active = false; this.__setupDelegationInConstructor(); } @@ -176,19 +181,31 @@ export class LionButton extends DisabledWithTabIndexMixin( } __setupDelegation() { + this.addEventListener('mousedown', this.__mousedownDelegationHandler); + this.addEventListener('mouseup', this.__mouseupDelegationHandler); this.addEventListener('keydown', this.__keydownDelegationHandler); this.addEventListener('keyup', this.__keyupDelegationHandler); } __teardownDelegation() { + this.removeEventListener('mousedown', this.__mousedownDelegationHandler); + this.removeEventListener('mouseup', this.__mouseupDelegationHandler); this.removeEventListener('keydown', this.__keydownDelegationHandler); this.removeEventListener('keyup', this.__keyupDelegationHandler); } + __mousedownDelegationHandler() { + this.active = true; + } + + __mouseupDelegationHandler() { + this.active = false; + } + __keydownDelegationHandler(e) { if (e.keyCode === 32 /* space */ || e.keyCode === 13 /* enter */) { e.preventDefault(); - this.shadowRoot.querySelector('.btn').setAttribute('active', ''); + this.active = true; } } @@ -197,7 +214,7 @@ export class LionButton extends DisabledWithTabIndexMixin( // and make click handlers on button work on space and enter if (e.keyCode === 32 /* space */ || e.keyCode === 13 /* enter */) { e.preventDefault(); - this.shadowRoot.querySelector('.btn').removeAttribute('active'); + this.active = false; this.shadowRoot.querySelector('.click-area').click(); } } diff --git a/packages/button/test/lion-button.test.js b/packages/button/test/lion-button.test.js index 1d94aaa46..cb2c15580 100644 --- a/packages/button/test/lion-button.test.js +++ b/packages/button/test/lion-button.test.js @@ -4,6 +4,10 @@ import { makeMouseEvent, pressEnter, pressSpace, + down, + up, + keyDownOn, + keyUpOn, } from '@polymer/iron-test-helpers/mock-interactions.js'; import '../lion-button.js'; @@ -57,6 +61,53 @@ describe('lion-button', () => { expect(el.hasAttribute('disabled')).to.equal(true); }); + describe('active', () => { + it('updates "active" attribute on host when mousedown/mouseup on button', async () => { + const el = await fixture(`foo`); + const topEl = getTopElement(el); + + down(topEl); + expect(el.active).to.be.true; + await el.updateComplete; + expect(el.hasAttribute('active')).to.be.true; + + up(topEl); + expect(el.active).to.be.false; + await el.updateComplete; + expect(el.hasAttribute('active')).to.be.false; + }); + + it('updates "active" attribute on host when space keydown/keyup on button', async () => { + const el = await fixture(`foo`); + const topEl = getTopElement(el); + + keyDownOn(topEl, 32); + expect(el.active).to.be.true; + await el.updateComplete; + expect(el.hasAttribute('active')).to.be.true; + + keyUpOn(topEl, 32); + expect(el.active).to.be.false; + await el.updateComplete; + expect(el.hasAttribute('active')).to.be.false; + }); + + it('updates "active" attribute on host when enter keydown/keyup on button', async () => { + const el = await fixture(`foo`); + const topEl = getTopElement(el); + + keyDownOn(topEl, 13); + expect(el.active).to.be.true; + await el.updateComplete; + expect(el.hasAttribute('active')).to.be.true; + + keyUpOn(topEl, 13); + expect(el.active).to.be.false; + await el.updateComplete; + expect(el.hasAttribute('active')).to.be.false; + }); + }); + describe('a11y', () => { it('has a role="button" by default', async () => { const el = await fixture(`foo`);