From 2d71266f118b64acff3df7ccb445fcee048ab063 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 14:53:19 -0400 Subject: [PATCH 01/11] fix(item): only trigger one click event when clicking on the padding of item --- core/src/components/item/item.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/components/item/item.tsx b/core/src/components/item/item.tsx index 6091e8b1cf8..d9adfdda2ea 100644 --- a/core/src/components/item/item.tsx +++ b/core/src/components/item/item.tsx @@ -286,6 +286,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac if (firstInteractive !== undefined && !multipleInputs) { const path = ev.composedPath(); const target = path[0] as HTMLElement; + if (ev.isTrusted) { /** * Dispatches a click event to the first interactive element, @@ -306,6 +307,12 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac (firstInteractive as HTMLIonInputElement | HTMLIonTextareaElement).setFocus(); } else { firstInteractive.click(); + /** + * Stop the item event from being triggered + * as the firstInteractive click event will also + * trigger the item click event. + */ + ev.stopImmediatePropagation(); } } } From 015bff92bef1f8c8ef8b6ce1c0e38507d6e11167 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 15:32:17 -0400 Subject: [PATCH 02/11] test(many): add tests for firing click event on item padding --- .../checkbox/test/basic/checkbox.e2e.ts | 23 ------ .../checkbox/test/item/checkbox.e2e.ts | 67 +++++++++++++++++ .../components/radio/test/item/radio.e2e.ts | 48 +++++++++++- .../select/test/basic/select.e2e.ts | 28 ------- .../components/select/test/item/select.e2e.ts | 75 +++++++++++++++++++ .../components/toggle/test/item/toggle.e2e.ts | 48 +++++++++++- 6 files changed, 232 insertions(+), 57 deletions(-) diff --git a/core/src/components/checkbox/test/basic/checkbox.e2e.ts b/core/src/components/checkbox/test/basic/checkbox.e2e.ts index 957c6da31b8..1a41b339599 100644 --- a/core/src/components/checkbox/test/basic/checkbox.e2e.ts +++ b/core/src/components/checkbox/test/basic/checkbox.e2e.ts @@ -98,28 +98,5 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => await checkbox.evaluate((el: HTMLIonCheckboxElement) => (el.checked = true)); expect(ionChange).not.toHaveReceivedEvent(); }); - - test('clicking padded space within item should click the checkbox', async ({ page }) => { - await page.setContent( - ` - - Size - - `, - config - ); - const itemNative = page.locator('.item-native'); - const ionChange = await page.spyOnEvent('ionChange'); - - // Clicks the padded space within the item - await itemNative.click({ - position: { - x: 5, - y: 5, - }, - }); - - expect(ionChange).toHaveReceivedEvent(); - }); }); }); diff --git a/core/src/components/checkbox/test/item/checkbox.e2e.ts b/core/src/components/checkbox/test/item/checkbox.e2e.ts index bdcf1892da2..341839739b1 100644 --- a/core/src/components/checkbox/test/item/checkbox.e2e.ts +++ b/core/src/components/checkbox/test/item/checkbox.e2e.ts @@ -127,3 +127,70 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { }); }); }); + +configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { + test.describe(title('checkbox: item functionality'), () => { + test('clicking padded space within item should click the checkbox', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/27169', + }); + + await page.setContent( + ` + + Size + + `, + config + ); + const item = page.locator('ion-item'); + const ionChange = await page.spyOnEvent('ionChange'); + + // Clicks the padded space within the item + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(ionChange).toHaveReceivedEvent(); + }); + + test('clicking padded space within item should fire one click event', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/29758', + }); + + await page.setContent( + ` + + + Checkbox + + + `, + config + ); + + const item = page.locator('ion-item'); + const onClick = await page.spyOnEvent('click'); + + // Click the padding area (5px from left edge) + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the checkbox and not the item + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-checkbox'); + }); + }); +}); diff --git a/core/src/components/radio/test/item/radio.e2e.ts b/core/src/components/radio/test/item/radio.e2e.ts index 4fdf34bd4e1..8c9fd4be951 100644 --- a/core/src/components/radio/test/item/radio.e2e.ts +++ b/core/src/components/radio/test/item/radio.e2e.ts @@ -78,9 +78,16 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, co await expect(list).toHaveScreenshot(screenshot(`radio-stacked-label-in-item`)); }); }); +}); - test.describe(title('radio: ionChange'), () => { +configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { + test.describe(title('radio: item functionality'), () => { test('clicking padded space within item should click the radio', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/27169', + }); + await page.setContent( ` @@ -93,11 +100,11 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, co `, config ); - const itemNative = page.locator('.item-native'); + const item = page.locator('ion-item'); const ionChange = await page.spyOnEvent('ionChange'); // Clicks the padded space within the item - await itemNative.click({ + await item.click({ position: { x: 5, y: 5, @@ -106,5 +113,40 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, co expect(ionChange).toHaveReceivedEvent(); }); + + test('clicking padded space within item should fire one click event', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/29758', + }); + + await page.setContent( + ` + + + Radio + + + `, + config + ); + + const item = page.locator('ion-item'); + const onClick = await page.spyOnEvent('click'); + + // Click the padding area (5px from left edge) + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the radio and not the item + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-radio'); + }); }); }); diff --git a/core/src/components/select/test/basic/select.e2e.ts b/core/src/components/select/test/basic/select.e2e.ts index d5a9c3d220f..63f1c8ca10a 100644 --- a/core/src/components/select/test/basic/select.e2e.ts +++ b/core/src/components/select/test/basic/select.e2e.ts @@ -294,34 +294,6 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => { await select.evaluate((el: HTMLIonSelectElement) => (el.value = 'banana')); await expect(ionChange).not.toHaveReceivedEvent(); }); - - test('clicking padded space within item should click the select', async ({ page }) => { - await page.setContent( - ` - - - Apple - Banana - - - `, - config - ); - const itemNative = page.locator('.item-native'); - const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent'); - - // Clicks the padded space within the item - await itemNative.click({ - position: { - x: 5, - y: 5, - }, - }); - - await ionActionSheetDidPresent.next(); - - expect(ionActionSheetDidPresent).toHaveReceivedEvent(); - }); }); }); diff --git a/core/src/components/select/test/item/select.e2e.ts b/core/src/components/select/test/item/select.e2e.ts index 05ca3e4abb3..d0ad1d616d0 100644 --- a/core/src/components/select/test/item/select.e2e.ts +++ b/core/src/components/select/test/item/select.e2e.ts @@ -61,3 +61,78 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { }); }); }); + +configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { + test.describe(title('select: item functionality'), () => { + test('clicking padded space within item should click the select', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/27169', + }); + + await page.setContent( + ` + + + Apple + Banana + + + `, + config + ); + const item = page.locator('ion-item'); + const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent'); + + // Clicks the padded space within the item + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + await ionActionSheetDidPresent.next(); + + expect(ionActionSheetDidPresent).toHaveReceivedEvent(); + }); + + test('clicking padded space within item should fire one click event', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/29758', + }); + + await page.setContent( + ` + + + Apple + + + `, + config + ); + + const item = page.locator('ion-item'); + const onClick = await page.spyOnEvent('click'); + + // Click the padding area (5px from left edge) + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the select and not the item + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-select'); + }); + }); +}); diff --git a/core/src/components/toggle/test/item/toggle.e2e.ts b/core/src/components/toggle/test/item/toggle.e2e.ts index f5db0dab8ab..866a382494f 100644 --- a/core/src/components/toggle/test/item/toggle.e2e.ts +++ b/core/src/components/toggle/test/item/toggle.e2e.ts @@ -108,9 +108,16 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, co await expect(list).toHaveScreenshot(screenshot(`toggle-stacked-label-in-item`)); }); }); +}); - test.describe(title('toggle: ionChange'), () => { +configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { + test.describe(title('toggle: item functionality'), () => { test('clicking padded space within item should click the toggle', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/27169', + }); + await page.setContent( ` @@ -119,7 +126,7 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, co `, config ); - const itemNative = page.locator('.item-native'); + const item = page.locator('ion-item'); const ionChange = await page.spyOnEvent('ionChange'); /** @@ -132,7 +139,7 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, co * 2. iOS is inconsistent in their implementation and other controls can be activated by clicking the label. * 3. MD is consistent in their implementation and activates controls by clicking the label. */ - await itemNative.click({ + await item.click({ position: { x: 5, y: 5, @@ -141,5 +148,40 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, co expect(ionChange).toHaveReceivedEvent(); }); + + test('clicking padded space within item should fire one click event', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/29758', + }); + + await page.setContent( + ` + + + Toggle + + + `, + config + ); + + const item = page.locator('ion-item'); + const onClick = await page.spyOnEvent('click'); + + // Click the padding area (5px from left edge) + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the toggle and not the item + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-toggle'); + }); }); }); From 3cfcf2a4d42d3ee3ad72245e6471af5f55a86d74 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 15:34:04 -0400 Subject: [PATCH 03/11] test(many): add click listener to tests --- core/src/components/checkbox/test/item/index.html | 10 ++++++++++ core/src/components/input/test/item/index.html | 10 ++++++++++ core/src/components/radio/test/item/index.html | 10 ++++++++++ core/src/components/select/test/item/index.html | 10 ++++++++++ core/src/components/textarea/test/item/index.html | 10 ++++++++++ core/src/components/toggle/test/item/index.html | 10 ++++++++++ 6 files changed, 60 insertions(+) diff --git a/core/src/components/checkbox/test/item/index.html b/core/src/components/checkbox/test/item/index.html index b2fa0bdccd1..8692c4a022e 100644 --- a/core/src/components/checkbox/test/item/index.html +++ b/core/src/components/checkbox/test/item/index.html @@ -246,6 +246,16 @@

Multiline Label

+ + diff --git a/core/src/components/input/test/item/index.html b/core/src/components/input/test/item/index.html index eb1b981246c..3290a1f5187 100644 --- a/core/src/components/input/test/item/index.html +++ b/core/src/components/input/test/item/index.html @@ -69,5 +69,15 @@

Inset List

+ + diff --git a/core/src/components/radio/test/item/index.html b/core/src/components/radio/test/item/index.html index 36e46779fd2..4e0bfbdc01e 100644 --- a/core/src/components/radio/test/item/index.html +++ b/core/src/components/radio/test/item/index.html @@ -207,5 +207,15 @@

Multiline Label

+ + diff --git a/core/src/components/select/test/item/index.html b/core/src/components/select/test/item/index.html index 826ff976992..06d32380405 100644 --- a/core/src/components/select/test/item/index.html +++ b/core/src/components/select/test/item/index.html @@ -83,5 +83,15 @@

Disabled

+ + diff --git a/core/src/components/textarea/test/item/index.html b/core/src/components/textarea/test/item/index.html index f22bc480247..3e6cf7827eb 100644 --- a/core/src/components/textarea/test/item/index.html +++ b/core/src/components/textarea/test/item/index.html @@ -69,5 +69,15 @@

Inset List

+ + diff --git a/core/src/components/toggle/test/item/index.html b/core/src/components/toggle/test/item/index.html index caeda79d077..86357208a45 100644 --- a/core/src/components/toggle/test/item/index.html +++ b/core/src/components/toggle/test/item/index.html @@ -224,5 +224,15 @@

Multiline Label

+ + From 102ed9463ea8c42982a9a3f19eb9d1501c050f79 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:17:26 -0400 Subject: [PATCH 04/11] fix(input): emit ion-input instead of native input with click event --- core/src/components/input/input.scss | 1 + core/src/components/input/input.tsx | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/src/components/input/input.scss b/core/src/components/input/input.scss index cc648e6e2f0..08a95d505cd 100644 --- a/core/src/components/input/input.scss +++ b/core/src/components/input/input.scss @@ -106,6 +106,7 @@ flex: 1; width: 100%; + height: 100%; max-width: 100%; max-height: 100%; diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index 42bee8e005e..890ff94d307 100644 --- a/core/src/components/input/input.tsx +++ b/core/src/components/input/input.tsx @@ -1,5 +1,5 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; -import { Build, Component, Element, Event, Host, Method, Prop, State, Watch, forceUpdate, h } from '@stencil/core'; +import { Build, Component, Element, Event, Host, Listen, Method, Prop, State, Watch, forceUpdate, h } from '@stencil/core'; import type { NotchController } from '@utils/forms'; import { createNotchController } from '@utils/forms'; import type { Attributes } from '@utils/helpers'; @@ -363,6 +363,19 @@ export class Input implements ComponentInterface { forceUpdate(this); } + /** + * This is prevents the native input from emitting the click event. + * Instead, the click event from the ion-input is emitted. + */ + @Listen('click', { capture: true }) + onClickCapture(ev: Event) { + const nativeInput = this.nativeInput; + if (nativeInput && ev.target === nativeInput) { + ev.stopPropagation(); + this.el.click(); + } + } + componentWillLoad() { this.inheritedAttributes = { ...inheritAriaAttributes(this.el), From 50e0b029293f03491f595f42c4aaf78bda231f87 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:18:08 -0400 Subject: [PATCH 05/11] fix(textarea): emit ion-textarea instead of native textarea with click event --- core/src/components/textarea/textarea.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/src/components/textarea/textarea.tsx b/core/src/components/textarea/textarea.tsx index afb9e3bf6b6..f6633cc3bc5 100644 --- a/core/src/components/textarea/textarea.tsx +++ b/core/src/components/textarea/textarea.tsx @@ -5,6 +5,7 @@ import { Element, Event, Host, + Listen, Method, Prop, State, @@ -314,6 +315,19 @@ export class Textarea implements ComponentInterface { */ @Event() ionFocus!: EventEmitter; + /** + * This is prevents the native input from emitting the click event. + * Instead, the click event from the ion-textarea is emitted. + */ + @Listen('click', { capture: true }) + onClickCapture(ev: Event) { + const nativeInput = this.nativeInput; + if (nativeInput && ev.target === nativeInput) { + ev.stopPropagation(); + this.el.click(); + } + } + connectedCallback() { const { el } = this; this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate(this)); From bc63e19d02b48f0008260579becab2c1149774a1 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:20:10 -0400 Subject: [PATCH 06/11] test(many): check for click event firing once on input and textarea --- .../components/input/test/item/input.e2e.ts | 91 ++++++++++++++++++- .../textarea/test/item/textarea.e2e.ts | 63 ++++++++++++- 2 files changed, 150 insertions(+), 4 deletions(-) diff --git a/core/src/components/input/test/item/input.e2e.ts b/core/src/components/input/test/item/input.e2e.ts index 710e2f00b12..a4fd996c713 100644 --- a/core/src/components/input/test/item/input.e2e.ts +++ b/core/src/components/input/test/item/input.e2e.ts @@ -49,6 +49,11 @@ configs().forEach(({ title, screenshot, config }) => { configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { test.describe(title('input: item functionality'), () => { test('clicking padded space within item should focus the input', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/21982', + }); + await page.setContent( ` @@ -57,11 +62,12 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => `, config ); - const itemNative = page.locator('.item-native'); + + const item = page.locator('ion-item'); const input = page.locator('ion-input input'); // Clicks the padded space within the item - await itemNative.click({ + await item.click({ position: { x: 5, y: 5, @@ -70,5 +76,86 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => await expect(input).toBeFocused(); }); + + test('clicking padded space within item should fire one click event', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/29761', + }); + + await page.setContent( + ` + + + + `, + config + ); + + const item = page.locator('ion-item'); + const onClick = await page.spyOnEvent('click'); + + // Click the padding area (5px from left edge) + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the input and not the item + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-input'); + }); + + test('clicking native wrapper should fire one click event', async ({ page }) => { + await page.setContent( + ` + + + + `, + config + ); + + const nativeWrapper = page.locator('.native-wrapper'); + const onClick = await page.spyOnEvent('click'); + + await nativeWrapper.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the input and not the native wrapper + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-input'); + }); + + test('clicking native input within item should fire click event with target as ion-input', async ({ page }) => { + await page.setContent( + ` + + + + `, + config + ); + + const nativeInput = page.locator('.native-input'); + const onClick = await page.spyOnEvent('click'); + + await nativeInput.click(); + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the ion-input and not the native input + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-input'); + }); }); }); diff --git a/core/src/components/textarea/test/item/textarea.e2e.ts b/core/src/components/textarea/test/item/textarea.e2e.ts index ed5daeec449..54a43ba02fd 100644 --- a/core/src/components/textarea/test/item/textarea.e2e.ts +++ b/core/src/components/textarea/test/item/textarea.e2e.ts @@ -49,6 +49,11 @@ configs().forEach(({ title, screenshot, config }) => { configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { test.describe(title('textarea: item functionality'), () => { test('clicking padded space within item should focus the textarea', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/21982', + }); + await page.setContent( ` @@ -57,11 +62,11 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => `, config ); - const itemNative = page.locator('.item-native'); + const item = page.locator('ion-item'); const textarea = page.locator('ion-textarea textarea'); // Clicks the padded space within the item - await itemNative.click({ + await item.click({ position: { x: 5, y: 5, @@ -70,5 +75,59 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => await expect(textarea).toBeFocused(); }); + + test('clicking padded space within item should fire one click event', async ({ page }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/29761', + }); + + await page.setContent( + ` + + + + `, + config + ); + + const item = page.locator('ion-item'); + const onClick = await page.spyOnEvent('click'); + + // Click the padding area (5px from left edge) + await item.click({ + position: { + x: 5, + y: 5, + }, + }); + + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the input and not the item + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-textarea'); + }); + + test('clicking native textarea within item should fire click event with target as ion-textarea', async ({ page }) => { + await page.setContent( + ` + + + + `, + config + ); + + const nativeTextarea = page.locator('.native-textarea'); + const onClick = await page.spyOnEvent('click'); + + await nativeTextarea.click(); + expect(onClick).toHaveReceivedEventTimes(1); + + // Verify that the event target is the ion-textarea and not the native textarea + const event = onClick.events[0]; + expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-textarea'); + }); }); }); From e6a9a7894af391d86bc1fe126ee2b1186e9d522a Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:20:19 -0400 Subject: [PATCH 07/11] fix(item): fire click event for all interactives --- core/src/components/item/item.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/core/src/components/item/item.tsx b/core/src/components/item/item.tsx index d9adfdda2ea..6384927de80 100644 --- a/core/src/components/item/item.tsx +++ b/core/src/components/item/item.tsx @@ -305,15 +305,14 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac */ if (firstInteractive.tagName === 'ION-INPUT' || firstInteractive.tagName === 'ION-TEXTAREA') { (firstInteractive as HTMLIonInputElement | HTMLIonTextareaElement).setFocus(); - } else { - firstInteractive.click(); - /** - * Stop the item event from being triggered - * as the firstInteractive click event will also - * trigger the item click event. - */ - ev.stopImmediatePropagation(); } + firstInteractive.click(); + /** + * Stop the item event from being triggered + * as the firstInteractive click event will also + * trigger the item click event. + */ + ev.stopImmediatePropagation(); } } } From 6440384a9337b766c30a3e4ce7e8676ed49d3a7b Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:29:09 -0400 Subject: [PATCH 08/11] style: lint --- core/src/components/input/input.scss | 3 ++- core/src/components/input/input.tsx | 15 ++++++++++++++- .../components/textarea/test/item/textarea.e2e.ts | 4 +++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/core/src/components/input/input.scss b/core/src/components/input/input.scss index 08a95d505cd..ac79979577e 100644 --- a/core/src/components/input/input.scss +++ b/core/src/components/input/input.scss @@ -106,8 +106,9 @@ flex: 1; width: 100%; - height: 100%; max-width: 100%; + + height: 100%; max-height: 100%; border: 0; diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index 890ff94d307..31271a827c5 100644 --- a/core/src/components/input/input.tsx +++ b/core/src/components/input/input.tsx @@ -1,5 +1,18 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; -import { Build, Component, Element, Event, Host, Listen, Method, Prop, State, Watch, forceUpdate, h } from '@stencil/core'; +import { + Build, + Component, + Element, + Event, + Host, + Listen, + Method, + Prop, + State, + Watch, + forceUpdate, + h, +} from '@stencil/core'; import type { NotchController } from '@utils/forms'; import { createNotchController } from '@utils/forms'; import type { Attributes } from '@utils/helpers'; diff --git a/core/src/components/textarea/test/item/textarea.e2e.ts b/core/src/components/textarea/test/item/textarea.e2e.ts index 54a43ba02fd..9b3408733e7 100644 --- a/core/src/components/textarea/test/item/textarea.e2e.ts +++ b/core/src/components/textarea/test/item/textarea.e2e.ts @@ -109,7 +109,9 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-textarea'); }); - test('clicking native textarea within item should fire click event with target as ion-textarea', async ({ page }) => { + test('clicking native textarea within item should fire click event with target as ion-textarea', async ({ + page, + }) => { await page.setContent( ` From 7430e750824a2f42ba16dfdf81603863f088c9fb Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:46:05 -0400 Subject: [PATCH 09/11] style: typo --- core/src/components/input/input.tsx | 2 +- core/src/components/textarea/textarea.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index 31271a827c5..5f4b1257141 100644 --- a/core/src/components/input/input.tsx +++ b/core/src/components/input/input.tsx @@ -377,7 +377,7 @@ export class Input implements ComponentInterface { } /** - * This is prevents the native input from emitting the click event. + * This prevents the native input from emitting the click event. * Instead, the click event from the ion-input is emitted. */ @Listen('click', { capture: true }) diff --git a/core/src/components/textarea/textarea.tsx b/core/src/components/textarea/textarea.tsx index f6633cc3bc5..78541e9d66b 100644 --- a/core/src/components/textarea/textarea.tsx +++ b/core/src/components/textarea/textarea.tsx @@ -316,7 +316,7 @@ export class Textarea implements ComponentInterface { @Event() ionFocus!: EventEmitter; /** - * This is prevents the native input from emitting the click event. + * This prevents the native input from emitting the click event. * Instead, the click event from the ion-textarea is emitted. */ @Listen('click', { capture: true }) From 5938bbb937786434261655753b2333ed4c28a931 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:22:42 -0400 Subject: [PATCH 10/11] style: add comment for why we need height --- core/src/components/input/input.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/components/input/input.scss b/core/src/components/input/input.scss index ac79979577e..57d438eb2d9 100644 --- a/core/src/components/input/input.scss +++ b/core/src/components/input/input.scss @@ -108,6 +108,8 @@ width: 100%; max-width: 100%; + // Ensure the input fills the full height of the native wrapper. + // This prevents the wrapper from being the click event target. height: 100%; max-height: 100%; From a231a2258dac17fb96889a7a0750c6dfd4d14556 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Wed, 30 Apr 2025 12:56:58 -0400 Subject: [PATCH 11/11] test(item): remove debug logs --- core/src/components/checkbox/test/item/index.html | 10 ---------- core/src/components/input/test/item/index.html | 10 ---------- core/src/components/radio/test/item/index.html | 10 ---------- core/src/components/select/test/item/index.html | 10 ---------- core/src/components/textarea/test/item/index.html | 10 ---------- core/src/components/toggle/test/item/index.html | 10 ---------- 6 files changed, 60 deletions(-) diff --git a/core/src/components/checkbox/test/item/index.html b/core/src/components/checkbox/test/item/index.html index 8692c4a022e..b2fa0bdccd1 100644 --- a/core/src/components/checkbox/test/item/index.html +++ b/core/src/components/checkbox/test/item/index.html @@ -246,16 +246,6 @@

Multiline Label

- - diff --git a/core/src/components/input/test/item/index.html b/core/src/components/input/test/item/index.html index 3290a1f5187..eb1b981246c 100644 --- a/core/src/components/input/test/item/index.html +++ b/core/src/components/input/test/item/index.html @@ -69,15 +69,5 @@

Inset List

- - diff --git a/core/src/components/radio/test/item/index.html b/core/src/components/radio/test/item/index.html index 4e0bfbdc01e..36e46779fd2 100644 --- a/core/src/components/radio/test/item/index.html +++ b/core/src/components/radio/test/item/index.html @@ -207,15 +207,5 @@

Multiline Label

- - diff --git a/core/src/components/select/test/item/index.html b/core/src/components/select/test/item/index.html index 06d32380405..826ff976992 100644 --- a/core/src/components/select/test/item/index.html +++ b/core/src/components/select/test/item/index.html @@ -83,15 +83,5 @@

Disabled

- - diff --git a/core/src/components/textarea/test/item/index.html b/core/src/components/textarea/test/item/index.html index 3e6cf7827eb..f22bc480247 100644 --- a/core/src/components/textarea/test/item/index.html +++ b/core/src/components/textarea/test/item/index.html @@ -69,15 +69,5 @@

Inset List

- - diff --git a/core/src/components/toggle/test/item/index.html b/core/src/components/toggle/test/item/index.html index 86357208a45..caeda79d077 100644 --- a/core/src/components/toggle/test/item/index.html +++ b/core/src/components/toggle/test/item/index.html @@ -224,15 +224,5 @@

Multiline Label

- -