From 4f5cd5ec58146ee657894dd9703e39ca2de7932f Mon Sep 17 00:00:00 2001 From: ShaneK Date: Tue, 29 Apr 2025 13:14:56 -0700 Subject: [PATCH 01/12] fix(inputs): fixing issue on several input types (checkbox, select, textarea, toggle, input) where clicking on a label would trigger onclick twice --- core/src/components/checkbox/checkbox.tsx | 9 +++++ .../checkbox/test/basic/checkbox.e2e.ts | 29 +++++++++++++++ core/src/components/input/input.tsx | 14 ++++++- .../components/input/test/basic/input.e2e.ts | 35 ++++++++++++++++++ core/src/components/select/select.tsx | 14 ++++++- .../select/test/basic/select.e2e.ts | 37 ++++++++++++++++++- .../textarea/test/basic/textarea.e2e.ts | 31 ++++++++++++++++ core/src/components/textarea/textarea.tsx | 14 ++++++- .../toggle/test/basic/toggle.e2e.ts | 33 +++++++++++++++++ core/src/components/toggle/toggle.tsx | 9 +++++ 10 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 core/src/components/textarea/test/basic/textarea.e2e.ts create mode 100644 core/src/components/toggle/test/basic/toggle.e2e.ts diff --git a/core/src/components/checkbox/checkbox.tsx b/core/src/components/checkbox/checkbox.tsx index 3b9c3e6724a..9a363f7df0b 100644 --- a/core/src/components/checkbox/checkbox.tsx +++ b/core/src/components/checkbox/checkbox.tsx @@ -199,6 +199,14 @@ export class Checkbox implements ComponentInterface { this.toggleChecked(ev); }; + /** + * Stops propagation when the display label is clicked, + * otherwise, two clicks will be triggered. + */ + private onDivLabelClick = (ev: MouseEvent) => { + ev.stopPropagation(); + } + private getHintTextID(): string | undefined { const { el, helperText, errorText, helperTextId, errorTextId } = this; @@ -314,6 +322,7 @@ export class Checkbox implements ComponentInterface { }} part="label" id={this.inputLabelId} + onClick={this.onDivLabelClick} > {this.renderHintText()} diff --git a/core/src/components/checkbox/test/basic/checkbox.e2e.ts b/core/src/components/checkbox/test/basic/checkbox.e2e.ts index 957c6da31b8..e9e2e00f2f2 100644 --- a/core/src/components/checkbox/test/basic/checkbox.e2e.ts +++ b/core/src/components/checkbox/test/basic/checkbox.e2e.ts @@ -122,4 +122,33 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => expect(ionChange).toHaveReceivedEvent(); }); }); + + test.describe(title('checkbox: click'), () => { + test('clicking a checkbox label should only trigger onclick once', async ({ page }) => { + // Create a spy function in page context + await page.setContent(`Test Checkbox`, config); + + // Track calls to the exposed function + let clickCount = 0; + page.on('console', (msg) => { + if (msg.text().includes('click called')) { + clickCount++; + } + }); + + const input = page.locator('div.label-text-wrapper'); + + // Use position to make sure we click into the label enough to trigger + // what would be the double click + await input.click({ + position: { + x: 5, + y: 5, + }, + }); + + // Verify the click was triggered exactly once + expect(clickCount).toBe(1); + }); + }); }); diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index 42bee8e005e..6c929440fee 100644 --- a/core/src/components/input/input.tsx +++ b/core/src/components/input/input.tsx @@ -694,6 +694,18 @@ export class Input implements ComponentInterface { return this.label !== undefined || this.labelSlot !== null; } + /** + * Stops propagation when the label is clicked, + * otherwise, two clicks will be triggered. + */ + private onLabelClick = (ev: MouseEvent) => { + // Only stop propagation if the click was directly on the label + // and not on the input or other child elements + if (ev.target === ev.currentTarget) { + ev.stopPropagation(); + } + } + /** * Renders the border container * when fill="outline". @@ -789,7 +801,7 @@ export class Input implements ComponentInterface { * interactable, clicking the label would focus that instead * since it comes before the input in the DOM. */} -