Skip to content

Commit 9b7b646

Browse files
committed
Merge branch 'feature-8.7' of github.com:ionic-team/ionic-framework into FW-6475
2 parents c10e821 + 70dbcc9 commit 9b7b646

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+717
-144
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
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.6.2](https://github.com/ionic-team/ionic-framework/compare/v8.6.1...v8.6.2) (2025-06-18)
7+
8+
9+
### Bug Fixes
10+
11+
* **picker-column:** fallback to elementFromPoint for iOS 16 Shadow DOM bug ([#30479](https://github.com/ionic-team/ionic-framework/issues/30479)) ([6ae2907](https://github.com/ionic-team/ionic-framework/commit/6ae29077424434f3523d75426f3328765a4797f4)), closes [#29672](https://github.com/ionic-team/ionic-framework/issues/29672)
12+
* **range:** improve focus and blur handling for dual knobs ([#30482](https://github.com/ionic-team/ionic-framework/issues/30482)) ([6811fe5](https://github.com/ionic-team/ionic-framework/commit/6811fe5cc88f132f998476a3f4b956ce21122631))
13+
14+
15+
16+
17+
618
## [8.6.1](https://github.com/ionic-team/ionic-framework/compare/v8.6.0...v8.6.1) (2025-06-11)
719

820

core/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
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.6.2](https://github.com/ionic-team/ionic-framework/compare/v8.6.1...v8.6.2) (2025-06-18)
7+
8+
9+
### Bug Fixes
10+
11+
* **picker-column:** fallback to elementFromPoint for iOS 16 Shadow DOM bug ([#30479](https://github.com/ionic-team/ionic-framework/issues/30479)) ([6ae2907](https://github.com/ionic-team/ionic-framework/commit/6ae29077424434f3523d75426f3328765a4797f4)), closes [#29672](https://github.com/ionic-team/ionic-framework/issues/29672)
12+
* **range:** improve focus and blur handling for dual knobs ([#30482](https://github.com/ionic-team/ionic-framework/issues/30482)) ([6811fe5](https://github.com/ionic-team/ionic-framework/commit/6811fe5cc88f132f998476a3f4b956ce21122631))
13+
14+
15+
16+
17+
618
## [8.6.1](https://github.com/ionic-team/ionic-framework/compare/v8.6.0...v8.6.1) (2025-06-11)
719

820

core/api.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,9 @@ ion-reorder-group,none
15081508
ion-reorder-group,prop,disabled,boolean,true,false,false
15091509
ion-reorder-group,method,complete,complete(listOrReorder?: boolean | any[]) => Promise<any>
15101510
ion-reorder-group,event,ionItemReorder,ItemReorderEventDetail,true
1511+
ion-reorder-group,event,ionReorderEnd,ReorderEndEventDetail,true
1512+
ion-reorder-group,event,ionReorderMove,ReorderMoveEventDetail,true
1513+
ion-reorder-group,event,ionReorderStart,void,true
15111514

15121515
ion-ripple-effect,shadow
15131516
ion-ripple-effect,prop,type,"bounded" | "unbounded",'bounded',false,false

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.6.1",
3+
"version": "8.6.2",
44
"description": "Base components for Ionic",
55
"keywords": [
66
"ionic",

core/src/components.d.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAct
3030
import { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
3131
import { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
3232
import { RefresherEventDetail } from "./components/refresher/refresher-interface";
33-
import { ItemReorderEventDetail } from "./components/reorder-group/reorder-group-interface";
33+
import { ItemReorderEventDetail, ReorderEndEventDetail, ReorderMoveEventDetail } from "./components/reorder-group/reorder-group-interface";
3434
import { NavigationHookCallback } from "./components/route/route-interface";
3535
import { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
3636
import { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
@@ -68,7 +68,7 @@ export { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAct
6868
export { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
6969
export { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
7070
export { RefresherEventDetail } from "./components/refresher/refresher-interface";
71-
export { ItemReorderEventDetail } from "./components/reorder-group/reorder-group-interface";
71+
export { ItemReorderEventDetail, ReorderEndEventDetail, ReorderMoveEventDetail } from "./components/reorder-group/reorder-group-interface";
7272
export { NavigationHookCallback } from "./components/route/route-interface";
7373
export { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
7474
export { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
@@ -2770,7 +2770,7 @@ export namespace Components {
27702770
}
27712771
interface IonReorderGroup {
27722772
/**
2773-
* Completes the reorder operation. Must be called by the `ionItemReorder` event. If a list of items is passed, the list will be reordered and returned in the proper order. If no parameters are passed or if `true` is passed in, the reorder will complete and the item will remain in the position it was dragged to. If `false` is passed, the reorder will complete and the item will bounce back to its original position.
2773+
* Completes the reorder operation. Must be called by the `ionReorderEnd` event. If a list of items is passed, the list will be reordered and returned in the proper order. If no parameters are passed or if `true` is passed in, the reorder will complete and the item will remain in the position it was dragged to. If `false` is passed, the reorder will complete and the item will bounce back to its original position.
27742774
* @param listOrReorder A list of items to be sorted and returned in the new order or a boolean of whether or not the reorder should reposition the item.
27752775
*/
27762776
"complete": (listOrReorder?: boolean | any[]) => Promise<any>;
@@ -4755,6 +4755,9 @@ declare global {
47554755
};
47564756
interface HTMLIonReorderGroupElementEventMap {
47574757
"ionItemReorder": ItemReorderEventDetail;
4758+
"ionReorderStart": void;
4759+
"ionReorderMove": ReorderMoveEventDetail;
4760+
"ionReorderEnd": ReorderEndEventDetail;
47584761
}
47594762
interface HTMLIonReorderGroupElement extends Components.IonReorderGroup, HTMLStencilElement {
47604763
addEventListener<K extends keyof HTMLIonReorderGroupElementEventMap>(type: K, listener: (this: HTMLIonReorderGroupElement, ev: IonReorderGroupCustomEvent<HTMLIonReorderGroupElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
@@ -8039,9 +8042,22 @@ declare namespace LocalJSX {
80398042
*/
80408043
"disabled"?: boolean;
80418044
/**
8042-
* Event that needs to be listened to in order to complete the reorder action. Once the event has been emitted, the `complete()` method then needs to be called in order to finalize the reorder action.
8045+
* Event that needs to be listened to in order to complete the reorder action.
8046+
* @deprecated Use `ionReorderEnd` instead. If you are accessing `event.detail.from` or `event.detail.to` and relying on them being different you should now add checks as they are always emitted in `ionReorderEnd`, even when they are the same.
80438047
*/
80448048
"onIonItemReorder"?: (event: IonReorderGroupCustomEvent<ItemReorderEventDetail>) => void;
8049+
/**
8050+
* Event that is emitted when the reorder gesture ends. The from and to properties are always available, regardless of if the reorder gesture moved the item. If the item did not change from its start position, the from and to properties will be the same. Once the event has been emitted, the `complete()` method then needs to be called in order to finalize the reorder action.
8051+
*/
8052+
"onIonReorderEnd"?: (event: IonReorderGroupCustomEvent<ReorderEndEventDetail>) => void;
8053+
/**
8054+
* Event that is emitted as the reorder gesture moves.
8055+
*/
8056+
"onIonReorderMove"?: (event: IonReorderGroupCustomEvent<ReorderMoveEventDetail>) => void;
8057+
/**
8058+
* Event that is emitted when the reorder gesture starts.
8059+
*/
8060+
"onIonReorderStart"?: (event: IonReorderGroupCustomEvent<void>) => void;
80458061
}
80468062
interface IonRippleEffect {
80478063
/**

core/src/components/item/test/reorder/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
}
8585
function initGroup(group) {
8686
var groupEl = document.getElementById(group.id);
87-
groupEl.addEventListener('ionItemReorder', function (ev) {
87+
groupEl.addEventListener('ionReorderEnd', function (ev) {
8888
ev.detail.complete();
8989
});
9090
var groupItems = [];

core/src/components/picker-column/picker-column.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,27 @@ export class PickerColumn implements ComponentInterface {
376376
* elementsFromPoint can returns multiple elements
377377
* so find the relevant picker column option if one exists.
378378
*/
379-
const newActiveElement = elementsAtPoint.find((el) => el.tagName === 'ION-PICKER-COLUMN-OPTION');
379+
let newActiveElement = elementsAtPoint.find((el) => el.tagName === 'ION-PICKER-COLUMN-OPTION');
380+
381+
/**
382+
* TODO(FW-6594): Remove this workaround when iOS 16 is no longer
383+
* supported.
384+
*
385+
* If `elementsFromPoint` failed to find the active element (a known
386+
* issue on iOS 16 when elements are in a Shadow DOM and the
387+
* referenceNode is the document), a fallback to `elementFromPoint`
388+
* is used. While `elementsFromPoint` returns all elements,
389+
* `elementFromPoint` returns only the top-most, which is sufficient
390+
* for this use case and appears to handle Shadow DOM retargeting
391+
* more reliably in this specific iOS bug.
392+
*/
393+
if (newActiveElement === undefined) {
394+
const fallbackActiveElement = referenceNode.elementFromPoint(centerX, centerY);
395+
396+
if (fallbackActiveElement?.tagName === 'ION-PICKER-COLUMN-OPTION') {
397+
newActiveElement = fallbackActiveElement as HTMLIonPickerColumnOptionElement;
398+
}
399+
}
380400

381401
if (activeEl !== undefined) {
382402
this.setPickerItemActiveState(activeEl, false);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
1+
// TODO(FW-6590): Remove this once the deprecated event is removed
12
export interface ItemReorderEventDetail {
23
from: number;
34
to: number;
45
complete: (data?: boolean | any[]) => any;
56
}
67

8+
// TODO(FW-6590): Remove this once the deprecated event is removed
79
export interface ItemReorderCustomEvent extends CustomEvent {
810
detail: ItemReorderEventDetail;
911
target: HTMLIonReorderGroupElement;
1012
}
13+
14+
export interface ReorderMoveEventDetail {
15+
from: number;
16+
to: number;
17+
}
18+
19+
export interface ReorderEndEventDetail {
20+
from: number;
21+
to: number;
22+
complete: (data?: boolean | any[]) => any;
23+
}
24+
25+
export interface ReorderMoveCustomEvent extends CustomEvent {
26+
detail: ReorderMoveEventDetail;
27+
target: HTMLIonReorderGroupElement;
28+
}
29+
30+
export interface ReorderEndCustomEvent extends CustomEvent {
31+
detail: ReorderEndEventDetail;
32+
target: HTMLIonReorderGroupElement;
33+
}

core/src/components/reorder-group/reorder-group.tsx

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from
77
import { getIonMode } from '../../global/ionic-global';
88
import type { Gesture, GestureDetail } from '../../interface';
99

10-
import type { ItemReorderEventDetail } from './reorder-group-interface';
10+
import type { ItemReorderEventDetail, ReorderMoveEventDetail, ReorderEndEventDetail } from './reorder-group-interface';
1111

1212
// TODO(FW-2832): types
1313

@@ -51,12 +51,35 @@ export class ReorderGroup implements ComponentInterface {
5151
}
5252
}
5353

54+
// TODO(FW-6590): Remove this in a major release.
5455
/**
5556
* Event that needs to be listened to in order to complete the reorder action.
57+
* @deprecated Use `ionReorderEnd` instead. If you are accessing
58+
* `event.detail.from` or `event.detail.to` and relying on them
59+
* being different you should now add checks as they are always emitted
60+
* in `ionReorderEnd`, even when they are the same.
61+
*/
62+
@Event() ionItemReorder!: EventEmitter<ItemReorderEventDetail>;
63+
64+
/**
65+
* Event that is emitted when the reorder gesture starts.
66+
*/
67+
@Event() ionReorderStart!: EventEmitter<void>;
68+
69+
/**
70+
* Event that is emitted as the reorder gesture moves.
71+
*/
72+
@Event() ionReorderMove!: EventEmitter<ReorderMoveEventDetail>;
73+
74+
/**
75+
* Event that is emitted when the reorder gesture ends.
76+
* The from and to properties are always available, regardless of
77+
* if the reorder gesture moved the item. If the item did not change
78+
* from its start position, the from and to properties will be the same.
5679
* Once the event has been emitted, the `complete()` method then needs
5780
* to be called in order to finalize the reorder action.
5881
*/
59-
@Event() ionItemReorder!: EventEmitter<ItemReorderEventDetail>;
82+
@Event() ionReorderEnd!: EventEmitter<ReorderEndEventDetail>;
6083

6184
async connectedCallback() {
6285
const contentEl = findClosestIonContent(this.el);
@@ -88,7 +111,7 @@ export class ReorderGroup implements ComponentInterface {
88111
}
89112

90113
/**
91-
* Completes the reorder operation. Must be called by the `ionItemReorder` event.
114+
* Completes the reorder operation. Must be called by the `ionReorderEnd` event.
92115
*
93116
* If a list of items is passed, the list will be reordered and returned in the
94117
* proper order.
@@ -164,6 +187,8 @@ export class ReorderGroup implements ComponentInterface {
164187
item.classList.add(ITEM_REORDER_SELECTED);
165188

166189
hapticSelectionStart();
190+
191+
this.ionReorderStart.emit();
167192
}
168193

169194
private onMove(ev: GestureDetail) {
@@ -180,6 +205,7 @@ export class ReorderGroup implements ComponentInterface {
180205
const currentY = Math.max(top, Math.min(ev.currentY, bottom));
181206
const deltaY = scroll + currentY - ev.startY;
182207
const normalizedY = currentY - top;
208+
const fromIndex = this.lastToIndex;
183209
const toIndex = this.itemIndexForTop(normalizedY);
184210
if (toIndex !== this.lastToIndex) {
185211
const fromIndex = indexForItem(selectedItem);
@@ -191,6 +217,11 @@ export class ReorderGroup implements ComponentInterface {
191217

192218
// Update selected item position
193219
selectedItem.style.transform = `translateY(${deltaY}px)`;
220+
221+
this.ionReorderMove.emit({
222+
from: fromIndex,
223+
to: toIndex,
224+
});
194225
}
195226

196227
private onEnd() {
@@ -207,6 +238,7 @@ export class ReorderGroup implements ComponentInterface {
207238
if (toIndex === fromIndex) {
208239
this.completeReorder();
209240
} else {
241+
// TODO(FW-6590): Remove this once the deprecated event is removed
210242
this.ionItemReorder.emit({
211243
from: fromIndex,
212244
to: toIndex,
@@ -215,6 +247,12 @@ export class ReorderGroup implements ComponentInterface {
215247
}
216248

217249
hapticSelectionEnd();
250+
251+
this.ionReorderEnd.emit({
252+
from: fromIndex,
253+
to: toIndex,
254+
complete: this.completeReorder.bind(this),
255+
});
218256
}
219257

220258
private completeReorder(listOrReorder?: boolean | any[]): any {

0 commit comments

Comments
 (0)