fix(form-core): dedupe click event label choice inputs
This commit is contained in:
parent
9aaf8959d5
commit
771147537a
4 changed files with 51 additions and 0 deletions
5
.changeset/eleven-pans-shave.md
Normal file
5
.changeset/eleven-pans-shave.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/form-core': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Stop propagation of label click event in choice inputs to deduplicate the click event on the choice input.
|
||||||
|
|
@ -128,6 +128,7 @@ const ChoiceInputMixinImplementation = superclass =>
|
||||||
super();
|
super();
|
||||||
this.modelValue = { value: '', checked: false };
|
this.modelValue = { value: '', checked: false };
|
||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
|
this._preventDuplicateLabelClick = this._preventDuplicateLabelClick.bind(this);
|
||||||
this.__toggleChecked = this.__toggleChecked.bind(this);
|
this.__toggleChecked = this.__toggleChecked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,14 +190,37 @@ const ChoiceInputMixinImplementation = superclass =>
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
if (this._labelNode) {
|
||||||
|
this._labelNode.addEventListener('click', this._preventDuplicateLabelClick);
|
||||||
|
}
|
||||||
this.addEventListener('user-input-changed', this.__toggleChecked);
|
this.addEventListener('user-input-changed', this.__toggleChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
|
if (this._labelNode) {
|
||||||
|
this._labelNode.removeEventListener('click', this._preventDuplicateLabelClick);
|
||||||
|
}
|
||||||
this.removeEventListener('user-input-changed', this.__toggleChecked);
|
this.removeEventListener('user-input-changed', this.__toggleChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The native platform fires an event for both the click on the label, and also
|
||||||
|
* the redispatched click on the native input element.
|
||||||
|
* This results in two click events arriving at the host, but we only want one.
|
||||||
|
* This method prevents the duplicate click and ensures the correct isTrusted event
|
||||||
|
* with the correct event.target arrives at the host.
|
||||||
|
* @param {Event} ev
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
_preventDuplicateLabelClick(ev) {
|
||||||
|
const __inputClickHandler = /** @param {Event} _ev */ _ev => {
|
||||||
|
_ev.stopImmediatePropagation();
|
||||||
|
this._inputNode.removeEventListener('click', __inputClickHandler);
|
||||||
|
};
|
||||||
|
this._inputNode.addEventListener('click', __inputClickHandler);
|
||||||
|
}
|
||||||
|
|
||||||
__toggleChecked() {
|
__toggleChecked() {
|
||||||
if (this.disabled) {
|
if (this.disabled) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,26 @@ export function runChoiceInputMixinSuite({ tagString } = {}) {
|
||||||
expect(counter).to.equal(1);
|
expect(counter).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fires one "click" event when clicking label or input, using the right target', async () => {
|
||||||
|
const spy = sinon.spy();
|
||||||
|
const el = /** @type {ChoiceInput} */ (await fixture(html`
|
||||||
|
<${tag}
|
||||||
|
@click="${spy}"
|
||||||
|
>
|
||||||
|
<input slot="input" />
|
||||||
|
</${tag}>
|
||||||
|
`));
|
||||||
|
el.click();
|
||||||
|
expect(spy.args[0][0].target).to.equal(el);
|
||||||
|
expect(spy.callCount).to.equal(1);
|
||||||
|
el._labelNode.click();
|
||||||
|
expect(spy.args[1][0].target).to.equal(el._labelNode);
|
||||||
|
expect(spy.callCount).to.equal(2);
|
||||||
|
el._inputNode.click();
|
||||||
|
expect(spy.args[2][0].target).to.equal(el._inputNode);
|
||||||
|
expect(spy.callCount).to.equal(3);
|
||||||
|
});
|
||||||
|
|
||||||
it('adds "isTriggerByUser" flag on model-value-changed', async () => {
|
it('adds "isTriggerByUser" flag on model-value-changed', async () => {
|
||||||
let isTriggeredByUser;
|
let isTriggeredByUser;
|
||||||
const el = /** @type {ChoiceInput} */ (await fixture(html`
|
const el = /** @type {ChoiceInput} */ (await fixture(html`
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ export declare class ChoiceInputHost {
|
||||||
connectedCallback(): void;
|
connectedCallback(): void;
|
||||||
disconnectedCallback(): void;
|
disconnectedCallback(): void;
|
||||||
|
|
||||||
|
_preventDuplicateLabelClick(ev: Event): void;
|
||||||
|
|
||||||
__toggleChecked(): void;
|
__toggleChecked(): void;
|
||||||
|
|
||||||
__syncModelCheckedToChecked(checked: boolean): void;
|
__syncModelCheckedToChecked(checked: boolean): void;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue