Skip to content

Commit 6c374c9

Browse files
committed
Merge branch 'main' of github.com:ionic-team/ionic-framework into FW-6498
2 parents 4f5cd5e + bf396c9 commit 6c374c9

38 files changed

+604
-153
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
All notable changes to this project will be documented in this file.
44
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
55

6+
## [8.5.6](https://github.com/ionic-team/ionic-framework/compare/v8.5.5...v8.5.6) (2025-04-30)
7+
8+
9+
### Bug Fixes
10+
11+
* **item:** emit click event once when clicking padded space on item and emit correct element ([#30373](https://github.com/ionic-team/ionic-framework/issues/30373)) ([7a9d138](https://github.com/ionic-team/ionic-framework/commit/7a9d138e3d5ecde55c12ff337ca29052a9194d69)), closes [#29758](https://github.com/ionic-team/ionic-framework/issues/29758) [#29761](https://github.com/ionic-team/ionic-framework/issues/29761)
12+
13+
14+
15+
16+
617
## [8.5.5](https://github.com/ionic-team/ionic-framework/compare/v8.5.4...v8.5.5) (2025-04-16)
718

819

core/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
All notable changes to this project will be documented in this file.
44
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
55

6+
## [8.5.6](https://github.com/ionic-team/ionic-framework/compare/v8.5.5...v8.5.6) (2025-04-30)
7+
8+
9+
### Bug Fixes
10+
11+
* **item:** emit click event once when clicking padded space on item and emit correct element ([#30373](https://github.com/ionic-team/ionic-framework/issues/30373)) ([7a9d138](https://github.com/ionic-team/ionic-framework/commit/7a9d138e3d5ecde55c12ff337ca29052a9194d69)), closes [#29758](https://github.com/ionic-team/ionic-framework/issues/29758) [#29761](https://github.com/ionic-team/ionic-framework/issues/29761)
12+
13+
14+
15+
16+
617
## [8.5.5](https://github.com/ionic-team/ionic-framework/compare/v8.5.4...v8.5.5) (2025-04-16)
718

819

core/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@ionic/core",
3-
"version": "8.5.5",
3+
"version": "8.5.6",
44
"description": "Base components for Ionic",
55
"keywords": [
66
"ionic",

core/src/components/checkbox/test/basic/checkbox.e2e.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -98,29 +98,6 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
9898
await checkbox.evaluate((el: HTMLIonCheckboxElement) => (el.checked = true));
9999
expect(ionChange).not.toHaveReceivedEvent();
100100
});
101-
102-
test('clicking padded space within item should click the checkbox', async ({ page }) => {
103-
await page.setContent(
104-
`
105-
<ion-item>
106-
<ion-checkbox>Size</ion-checkbox>
107-
</ion-item>
108-
`,
109-
config
110-
);
111-
const itemNative = page.locator('.item-native');
112-
const ionChange = await page.spyOnEvent('ionChange');
113-
114-
// Clicks the padded space within the item
115-
await itemNative.click({
116-
position: {
117-
x: 5,
118-
y: 5,
119-
},
120-
});
121-
122-
expect(ionChange).toHaveReceivedEvent();
123-
});
124101
});
125102

126103
test.describe(title('checkbox: click'), () => {

core/src/components/checkbox/test/item/checkbox.e2e.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,70 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
127127
});
128128
});
129129
});
130+
131+
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
132+
test.describe(title('checkbox: item functionality'), () => {
133+
test('clicking padded space within item should click the checkbox', async ({ page }) => {
134+
test.info().annotations.push({
135+
type: 'issue',
136+
description: 'https://github.com/ionic-team/ionic-framework/issues/27169',
137+
});
138+
139+
await page.setContent(
140+
`
141+
<ion-item>
142+
<ion-checkbox>Size</ion-checkbox>
143+
</ion-item>
144+
`,
145+
config
146+
);
147+
const item = page.locator('ion-item');
148+
const ionChange = await page.spyOnEvent('ionChange');
149+
150+
// Clicks the padded space within the item
151+
await item.click({
152+
position: {
153+
x: 5,
154+
y: 5,
155+
},
156+
});
157+
158+
expect(ionChange).toHaveReceivedEvent();
159+
});
160+
161+
test('clicking padded space within item should fire one click event', async ({ page }) => {
162+
test.info().annotations.push({
163+
type: 'issue',
164+
description: 'https://github.com/ionic-team/ionic-framework/issues/29758',
165+
});
166+
167+
await page.setContent(
168+
`
169+
<ion-item>
170+
<ion-checkbox>
171+
Checkbox
172+
</ion-checkbox>
173+
</ion-item>
174+
`,
175+
config
176+
);
177+
178+
const item = page.locator('ion-item');
179+
const onClick = await page.spyOnEvent('click');
180+
181+
// Click the padding area (5px from left edge)
182+
await item.click({
183+
position: {
184+
x: 5,
185+
y: 5,
186+
},
187+
});
188+
189+
expect(onClick).toHaveReceivedEventTimes(1);
190+
191+
// Verify that the event target is the checkbox and not the item
192+
const event = onClick.events[0];
193+
expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-checkbox');
194+
});
195+
});
196+
});

core/src/components/input/input.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@
107107

108108
width: 100%;
109109
max-width: 100%;
110+
111+
// Ensure the input fills the full height of the native wrapper.
112+
// This prevents the wrapper from being the click event target.
113+
height: 100%;
110114
max-height: 100%;
111115

112116
border: 0;

core/src/components/input/input.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import type { ComponentInterface, EventEmitter } from '@stencil/core';
2-
import { Build, Component, Element, Event, Host, Method, Prop, State, Watch, forceUpdate, h } from '@stencil/core';
2+
import {
3+
Build,
4+
Component,
5+
Element,
6+
Event,
7+
Host,
8+
Listen,
9+
Method,
10+
Prop,
11+
State,
12+
Watch,
13+
forceUpdate,
14+
h,
15+
} from '@stencil/core';
316
import type { NotchController } from '@utils/forms';
417
import { createNotchController } from '@utils/forms';
518
import type { Attributes } from '@utils/helpers';
@@ -363,6 +376,19 @@ export class Input implements ComponentInterface {
363376
forceUpdate(this);
364377
}
365378

379+
/**
380+
* This prevents the native input from emitting the click event.
381+
* Instead, the click event from the ion-input is emitted.
382+
*/
383+
@Listen('click', { capture: true })
384+
onClickCapture(ev: Event) {
385+
const nativeInput = this.nativeInput;
386+
if (nativeInput && ev.target === nativeInput) {
387+
ev.stopPropagation();
388+
this.el.click();
389+
}
390+
}
391+
366392
componentWillLoad() {
367393
this.inheritedAttributes = {
368394
...inheritAriaAttributes(this.el),

core/src/components/input/test/item/input.e2e.ts

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ configs().forEach(({ title, screenshot, config }) => {
4949
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
5050
test.describe(title('input: item functionality'), () => {
5151
test('clicking padded space within item should focus the input', async ({ page }) => {
52+
test.info().annotations.push({
53+
type: 'issue',
54+
description: 'https://github.com/ionic-team/ionic-framework/issues/21982',
55+
});
56+
5257
await page.setContent(
5358
`
5459
<ion-item>
@@ -57,11 +62,12 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
5762
`,
5863
config
5964
);
60-
const itemNative = page.locator('.item-native');
65+
66+
const item = page.locator('ion-item');
6167
const input = page.locator('ion-input input');
6268

6369
// Clicks the padded space within the item
64-
await itemNative.click({
70+
await item.click({
6571
position: {
6672
x: 5,
6773
y: 5,
@@ -70,5 +76,86 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
7076

7177
await expect(input).toBeFocused();
7278
});
79+
80+
test('clicking padded space within item should fire one click event', async ({ page }) => {
81+
test.info().annotations.push({
82+
type: 'issue',
83+
description: 'https://github.com/ionic-team/ionic-framework/issues/29761',
84+
});
85+
86+
await page.setContent(
87+
`
88+
<ion-item>
89+
<ion-input label="Input"></ion-input>
90+
</ion-item>
91+
`,
92+
config
93+
);
94+
95+
const item = page.locator('ion-item');
96+
const onClick = await page.spyOnEvent('click');
97+
98+
// Click the padding area (5px from left edge)
99+
await item.click({
100+
position: {
101+
x: 5,
102+
y: 5,
103+
},
104+
});
105+
106+
expect(onClick).toHaveReceivedEventTimes(1);
107+
108+
// Verify that the event target is the input and not the item
109+
const event = onClick.events[0];
110+
expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-input');
111+
});
112+
113+
test('clicking native wrapper should fire one click event', async ({ page }) => {
114+
await page.setContent(
115+
`
116+
<ion-item>
117+
<ion-input label="Input"></ion-input>
118+
</ion-item>
119+
`,
120+
config
121+
);
122+
123+
const nativeWrapper = page.locator('.native-wrapper');
124+
const onClick = await page.spyOnEvent('click');
125+
126+
await nativeWrapper.click({
127+
position: {
128+
x: 5,
129+
y: 5,
130+
},
131+
});
132+
133+
expect(onClick).toHaveReceivedEventTimes(1);
134+
135+
// Verify that the event target is the input and not the native wrapper
136+
const event = onClick.events[0];
137+
expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-input');
138+
});
139+
140+
test('clicking native input within item should fire click event with target as ion-input', async ({ page }) => {
141+
await page.setContent(
142+
`
143+
<ion-item>
144+
<ion-input label="Input"></ion-input>
145+
</ion-item>
146+
`,
147+
config
148+
);
149+
150+
const nativeInput = page.locator('.native-input');
151+
const onClick = await page.spyOnEvent('click');
152+
153+
await nativeInput.click();
154+
expect(onClick).toHaveReceivedEventTimes(1);
155+
156+
// Verify that the event target is the ion-input and not the native input
157+
const event = onClick.events[0];
158+
expect((event.target as HTMLElement).tagName.toLowerCase()).toBe('ion-input');
159+
});
73160
});
74161
});

core/src/components/item/item.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
286286
if (firstInteractive !== undefined && !multipleInputs) {
287287
const path = ev.composedPath();
288288
const target = path[0] as HTMLElement;
289+
289290
if (ev.isTrusted) {
290291
/**
291292
* Dispatches a click event to the first interactive element,
@@ -304,9 +305,14 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
304305
*/
305306
if (firstInteractive.tagName === 'ION-INPUT' || firstInteractive.tagName === 'ION-TEXTAREA') {
306307
(firstInteractive as HTMLIonInputElement | HTMLIonTextareaElement).setFocus();
307-
} else {
308-
firstInteractive.click();
309308
}
309+
firstInteractive.click();
310+
/**
311+
* Stop the item event from being triggered
312+
* as the firstInteractive click event will also
313+
* trigger the item click event.
314+
*/
315+
ev.stopImmediatePropagation();
310316
}
311317
}
312318
}

0 commit comments

Comments
 (0)