Skip to content

Commit f3303ae

Browse files
author
Mikhail Bashkirov
committed
fix(button): remove active when mouse/key up on other element (fix #210)
1 parent 471d662 commit f3303ae

File tree

2 files changed

+80
-27
lines changed

2 files changed

+80
-27
lines changed

packages/button/src/LionButton.js

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,12 @@ export class LionButton extends DisabledWithTabIndexMixin(
138138

139139
connectedCallback() {
140140
super.connectedCallback();
141-
this.__setupDelegation();
141+
this.__setupEvents();
142142
}
143143

144144
disconnectedCallback() {
145145
super.disconnectedCallback();
146-
this.__teardownDelegation();
146+
this.__teardownEvents();
147147
}
148148

149149
_redispatchClickEvent(oldEvent) {
@@ -180,42 +180,50 @@ export class LionButton extends DisabledWithTabIndexMixin(
180180
this.addEventListener('click', this.__clickDelegationHandler, true);
181181
}
182182

183-
__setupDelegation() {
184-
this.addEventListener('mousedown', this.__mousedownDelegationHandler);
185-
this.addEventListener('mouseup', this.__mouseupDelegationHandler);
186-
this.addEventListener('keydown', this.__keydownDelegationHandler);
187-
this.addEventListener('keyup', this.__keyupDelegationHandler);
183+
__setupEvents() {
184+
this.addEventListener('mousedown', this.__mousedownHandler);
185+
this.addEventListener('keydown', this.__keydownHandler);
186+
this.addEventListener('keyup', this.__keyupHandler);
188187
}
189188

190-
__teardownDelegation() {
191-
this.removeEventListener('mousedown', this.__mousedownDelegationHandler);
192-
this.removeEventListener('mouseup', this.__mouseupDelegationHandler);
193-
this.removeEventListener('keydown', this.__keydownDelegationHandler);
194-
this.removeEventListener('keyup', this.__keyupDelegationHandler);
189+
__teardownEvents() {
190+
this.removeEventListener('mousedown', this.__mousedownHandler);
191+
this.removeEventListener('keydown', this.__keydownHandler);
192+
this.removeEventListener('keyup', this.__keyupHandler);
195193
}
196194

197-
__mousedownDelegationHandler() {
195+
__mousedownHandler() {
198196
this.active = true;
197+
const mouseupHandler = () => {
198+
this.active = false;
199+
document.removeEventListener('mouseup', mouseupHandler);
200+
};
201+
document.addEventListener('mouseup', mouseupHandler);
199202
}
200203

201-
__mouseupDelegationHandler() {
202-
this.active = false;
203-
}
204-
205-
__keydownDelegationHandler(e) {
206-
if (e.keyCode === 32 /* space */ || e.keyCode === 13 /* enter */) {
207-
e.preventDefault();
208-
this.active = true;
204+
__keydownHandler(e) {
205+
if (!this.__isKeyboardClickEvent(e)) {
206+
return;
209207
}
208+
this.active = true;
209+
const keyupHandler = keyupEvent => {
210+
if (this.__isKeyboardClickEvent(keyupEvent)) {
211+
this.active = false;
212+
document.removeEventListener('keyup', keyupHandler, true);
213+
}
214+
};
215+
document.addEventListener('keyup', keyupHandler, true);
210216
}
211217

212-
__keyupDelegationHandler(e) {
213-
// Makes the real button the trigger in forms (will submit form, as opposed to paper-button)
214-
// and make click handlers on button work on space and enter
215-
if (e.keyCode === 32 /* space */ || e.keyCode === 13 /* enter */) {
216-
e.preventDefault();
217-
this.active = false;
218+
__keyupHandler(e) {
219+
if (this.__isKeyboardClickEvent(e)) {
220+
// redispatch click
218221
this.shadowRoot.querySelector('.click-area').click();
219222
}
220223
}
224+
225+
// eslint-disable-next-line class-methods-use-this
226+
__isKeyboardClickEvent(e) {
227+
return e.keyCode === 32 /* space */ || e.keyCode === 13 /* enter */;
228+
}
221229
}

packages/button/test/lion-button.test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,21 @@ describe('lion-button', () => {
7777
expect(el.hasAttribute('active')).to.be.false;
7878
});
7979

80+
it('updates "active" attribute on host when mousedown on button and mouseup anywhere else', async () => {
81+
const el = await fixture(`<lion-button>foo</lion-button>`);
82+
const topEl = getTopElement(el);
83+
84+
down(topEl);
85+
expect(el.active).to.be.true;
86+
await el.updateComplete;
87+
expect(el.hasAttribute('active')).to.be.true;
88+
89+
up(document.body);
90+
expect(el.active).to.be.false;
91+
await el.updateComplete;
92+
expect(el.hasAttribute('active')).to.be.false;
93+
});
94+
8095
it('updates "active" attribute on host when space keydown/keyup on button', async () => {
8196
const el = await fixture(`<lion-button>foo</lion-button>`);
8297
const topEl = getTopElement(el);
@@ -92,6 +107,21 @@ describe('lion-button', () => {
92107
expect(el.hasAttribute('active')).to.be.false;
93108
});
94109

110+
it('updates "active" attribute on host when space keydown on button and space keyup anywhere else', async () => {
111+
const el = await fixture(`<lion-button>foo</lion-button>`);
112+
const topEl = getTopElement(el);
113+
114+
keyDownOn(topEl, 32);
115+
expect(el.active).to.be.true;
116+
await el.updateComplete;
117+
expect(el.hasAttribute('active')).to.be.true;
118+
119+
keyUpOn(document.body, 32);
120+
expect(el.active).to.be.false;
121+
await el.updateComplete;
122+
expect(el.hasAttribute('active')).to.be.false;
123+
});
124+
95125
it('updates "active" attribute on host when enter keydown/keyup on button', async () => {
96126
const el = await fixture(`<lion-button>foo</lion-button>`);
97127
const topEl = getTopElement(el);
@@ -106,6 +136,21 @@ describe('lion-button', () => {
106136
await el.updateComplete;
107137
expect(el.hasAttribute('active')).to.be.false;
108138
});
139+
140+
it('updates "active" attribute on host when enter keydown on button and space keyup anywhere else', async () => {
141+
const el = await fixture(`<lion-button>foo</lion-button>`);
142+
const topEl = getTopElement(el);
143+
144+
keyDownOn(topEl, 13);
145+
expect(el.active).to.be.true;
146+
await el.updateComplete;
147+
expect(el.hasAttribute('active')).to.be.true;
148+
149+
keyUpOn(document.body, 13);
150+
expect(el.active).to.be.false;
151+
await el.updateComplete;
152+
expect(el.hasAttribute('active')).to.be.false;
153+
});
109154
});
110155

111156
describe('a11y', () => {

0 commit comments

Comments
 (0)