diff --git a/BREAKING.md b/BREAKING.md
index 3794dbdda4b..60eebb67804 100644
--- a/BREAKING.md
+++ b/BREAKING.md
@@ -15,10 +15,16 @@ This is a comprehensive list of the breaking changes introduced in the major ver
## Version 9.x
- [Components](#version-9x-components)
+ - [Legacy Picker](#version-9x-legacy-picker)
- [Router Outlet](#version-9x-router-outlet)
Components
+
Legacy Picker
+
+- `ion-picker-legacy` and `ion-picker-legacy-column` have been removed. The legacy picker component has been replaced with a inline picker component.
+ - Usages such as `ion-picker-legacy` or `IonPickerLegacy` should be changed to `ion-picker` and `IonPicker`, respectively.
+
Router Outlet
`ion-router-outlet` now exposes a `swipeGesture` property that controls the swipe-to-go-back gesture per outlet. This property defaults to `true` in `"ios"` mode and `false` in `"md"` mode.
diff --git a/core/api.txt b/core/api.txt
index be1cde11f2e..a19f20c5818 100644
--- a/core/api.txt
+++ b/core/api.txt
@@ -1281,61 +1281,6 @@ ion-picker-column-option,prop,color,"danger" | "dark" | "light" | "medium" | "pr
ion-picker-column-option,prop,disabled,boolean,false,false,false
ion-picker-column-option,prop,value,any,undefined,false,false
-ion-picker-legacy,scoped
-ion-picker-legacy,prop,animated,boolean,true,false,false
-ion-picker-legacy,prop,backdropDismiss,boolean,true,false,false
-ion-picker-legacy,prop,buttons,PickerButton[],[],false,false
-ion-picker-legacy,prop,columns,PickerColumn[],[],false,false
-ion-picker-legacy,prop,cssClass,string | string[] | undefined,undefined,false,false
-ion-picker-legacy,prop,duration,number,0,false,false
-ion-picker-legacy,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
-ion-picker-legacy,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false
-ion-picker-legacy,prop,isOpen,boolean,false,false,false
-ion-picker-legacy,prop,keyboardClose,boolean,true,false,false
-ion-picker-legacy,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
-ion-picker-legacy,prop,mode,"ios" | "md",undefined,false,false
-ion-picker-legacy,prop,showBackdrop,boolean,true,false,false
-ion-picker-legacy,prop,trigger,string | undefined,undefined,false,false
-ion-picker-legacy,method,dismiss,dismiss(data?: any, role?: string) => Promise
-ion-picker-legacy,method,getColumn,getColumn(name: string) => Promise
-ion-picker-legacy,method,onDidDismiss,onDidDismiss() => Promise>
-ion-picker-legacy,method,onWillDismiss,onWillDismiss() => Promise>
-ion-picker-legacy,method,present,present() => Promise
-ion-picker-legacy,event,didDismiss,OverlayEventDetail,true
-ion-picker-legacy,event,didPresent,void,true
-ion-picker-legacy,event,ionPickerDidDismiss,OverlayEventDetail,true
-ion-picker-legacy,event,ionPickerDidPresent,void,true
-ion-picker-legacy,event,ionPickerWillDismiss,OverlayEventDetail,true
-ion-picker-legacy,event,ionPickerWillPresent,void,true
-ion-picker-legacy,event,willDismiss,OverlayEventDetail,true
-ion-picker-legacy,event,willPresent,void,true
-ion-picker-legacy,css-prop,--backdrop-opacity,ios
-ion-picker-legacy,css-prop,--backdrop-opacity,md
-ion-picker-legacy,css-prop,--background,ios
-ion-picker-legacy,css-prop,--background,md
-ion-picker-legacy,css-prop,--background-rgb,ios
-ion-picker-legacy,css-prop,--background-rgb,md
-ion-picker-legacy,css-prop,--border-color,ios
-ion-picker-legacy,css-prop,--border-color,md
-ion-picker-legacy,css-prop,--border-radius,ios
-ion-picker-legacy,css-prop,--border-radius,md
-ion-picker-legacy,css-prop,--border-style,ios
-ion-picker-legacy,css-prop,--border-style,md
-ion-picker-legacy,css-prop,--border-width,ios
-ion-picker-legacy,css-prop,--border-width,md
-ion-picker-legacy,css-prop,--height,ios
-ion-picker-legacy,css-prop,--height,md
-ion-picker-legacy,css-prop,--max-height,ios
-ion-picker-legacy,css-prop,--max-height,md
-ion-picker-legacy,css-prop,--max-width,ios
-ion-picker-legacy,css-prop,--max-width,md
-ion-picker-legacy,css-prop,--min-height,ios
-ion-picker-legacy,css-prop,--min-height,md
-ion-picker-legacy,css-prop,--min-width,ios
-ion-picker-legacy,css-prop,--min-width,md
-ion-picker-legacy,css-prop,--width,ios
-ion-picker-legacy,css-prop,--width,md
-
ion-popover,shadow
ion-popover,prop,alignment,"center" | "end" | "start" | undefined,undefined,false,false
ion-popover,prop,animated,boolean,true,false,false
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index 04b2b9fd8ea..6e15bcbec2f 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -25,7 +25,6 @@ import { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, S
import { ViewController } from "./components/nav/view-controller";
import { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
import { PickerColumnChangeEventDetail, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
-import { PickerButton, PickerColumn } from "./components/picker-legacy/picker-interface";
import { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
import { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
import { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
@@ -63,7 +62,6 @@ export { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, S
export { ViewController } from "./components/nav/view-controller";
export { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
export { PickerColumnChangeEventDetail, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
-export { PickerButton, PickerColumn } from "./components/picker-legacy/picker-interface";
export { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
export { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
export { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
@@ -2289,107 +2287,6 @@ export namespace Components {
*/
"value"?: any | null;
}
- interface IonPickerLegacy {
- /**
- * If `true`, the picker will animate.
- * @default true
- */
- "animated": boolean;
- /**
- * If `true`, the picker will be dismissed when the backdrop is clicked.
- * @default true
- */
- "backdropDismiss": boolean;
- /**
- * Array of buttons to be displayed at the top of the picker.
- * @default []
- */
- "buttons": PickerButton[];
- /**
- * Array of columns to be displayed in the picker.
- * @default []
- */
- "columns": PickerColumn[];
- /**
- * Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces.
- */
- "cssClass"?: string | string[];
- "delegate"?: FrameworkDelegate;
- /**
- * Dismiss the picker overlay after it has been presented.
- * @param data Any data to emit in the dismiss events.
- * @param role The role of the element that is dismissing the picker. This can be useful in a button handler for determining which button was clicked to dismiss the picker. Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
- */
- "dismiss": (data?: any, role?: string) => Promise;
- /**
- * Number of milliseconds to wait before dismissing the picker.
- * @default 0
- */
- "duration": number;
- /**
- * Animation to use when the picker is presented.
- */
- "enterAnimation"?: AnimationBuilder;
- /**
- * Get the column that matches the specified name.
- * @param name The name of the column.
- */
- "getColumn": (name: string) => Promise;
- /**
- * @default false
- */
- "hasController": boolean;
- /**
- * Additional attributes to pass to the picker.
- */
- "htmlAttributes"?: { [key: string]: any };
- /**
- * If `true`, the picker will open. If `false`, the picker will close. Use this if you need finer grained control over presentation, otherwise just use the pickerController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the picker dismisses. You will need to do that in your code.
- * @default false
- */
- "isOpen": boolean;
- /**
- * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
- * @default true
- */
- "keyboardClose": boolean;
- /**
- * Animation to use when the picker is dismissed.
- */
- "leaveAnimation"?: AnimationBuilder;
- /**
- * The mode determines which platform styles to use.
- */
- "mode"?: "ios" | "md";
- /**
- * Returns a promise that resolves when the picker did dismiss.
- */
- "onDidDismiss": () => Promise>;
- /**
- * Returns a promise that resolves when the picker will dismiss.
- */
- "onWillDismiss": () => Promise>;
- "overlayIndex": number;
- /**
- * Present the picker overlay after it has been created.
- */
- "present": () => Promise;
- /**
- * If `true`, a backdrop will be displayed behind the picker.
- * @default true
- */
- "showBackdrop": boolean;
- /**
- * An ID corresponding to the trigger element that causes the picker to open when clicked.
- */
- "trigger": string | undefined;
- }
- interface IonPickerLegacyColumn {
- /**
- * Picker column data
- */
- "col": PickerColumn;
- }
interface IonPopover {
/**
* Describes how to align the popover content with the `reference` point. Defaults to `"center"` for `ios` mode, and `"start"` for `md` mode.
@@ -3862,14 +3759,6 @@ export interface IonPickerColumnCustomEvent extends CustomEvent {
detail: T;
target: HTMLIonPickerColumnElement;
}
-export interface IonPickerLegacyCustomEvent extends CustomEvent {
- detail: T;
- target: HTMLIonPickerLegacyElement;
-}
-export interface IonPickerLegacyColumnCustomEvent extends CustomEvent {
- detail: T;
- target: HTMLIonPickerLegacyColumnElement;
-}
export interface IonPopoverCustomEvent extends CustomEvent {
detail: T;
target: HTMLIonPopoverElement;
@@ -4627,47 +4516,6 @@ declare global {
prototype: HTMLIonPickerColumnOptionElement;
new (): HTMLIonPickerColumnOptionElement;
};
- interface HTMLIonPickerLegacyElementEventMap {
- "ionPickerDidPresent": void;
- "ionPickerWillPresent": void;
- "ionPickerWillDismiss": OverlayEventDetail;
- "ionPickerDidDismiss": OverlayEventDetail;
- "didPresent": void;
- "willPresent": void;
- "willDismiss": OverlayEventDetail;
- "didDismiss": OverlayEventDetail;
- }
- interface HTMLIonPickerLegacyElement extends Components.IonPickerLegacy, HTMLStencilElement {
- addEventListener(type: K, listener: (this: HTMLIonPickerLegacyElement, ev: IonPickerLegacyCustomEvent) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLIonPickerLegacyElement, ev: IonPickerLegacyCustomEvent) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
- }
- var HTMLIonPickerLegacyElement: {
- prototype: HTMLIonPickerLegacyElement;
- new (): HTMLIonPickerLegacyElement;
- };
- interface HTMLIonPickerLegacyColumnElementEventMap {
- "ionPickerColChange": PickerColumn;
- }
- interface HTMLIonPickerLegacyColumnElement extends Components.IonPickerLegacyColumn, HTMLStencilElement {
- addEventListener(type: K, listener: (this: HTMLIonPickerLegacyColumnElement, ev: IonPickerLegacyColumnCustomEvent) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLIonPickerLegacyColumnElement, ev: IonPickerLegacyColumnCustomEvent) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
- }
- var HTMLIonPickerLegacyColumnElement: {
- prototype: HTMLIonPickerLegacyColumnElement;
- new (): HTMLIonPickerLegacyColumnElement;
- };
interface HTMLIonPopoverElementEventMap {
"ionPopoverDidPresent": void;
"ionPopoverWillPresent": void;
@@ -5265,8 +5113,6 @@ declare global {
"ion-picker": HTMLIonPickerElement;
"ion-picker-column": HTMLIonPickerColumnElement;
"ion-picker-column-option": HTMLIonPickerColumnOptionElement;
- "ion-picker-legacy": HTMLIonPickerLegacyElement;
- "ion-picker-legacy-column": HTMLIonPickerLegacyColumnElement;
"ion-popover": HTMLIonPopoverElement;
"ion-progress-bar": HTMLIonProgressBarElement;
"ion-radio": HTMLIonRadioElement;
@@ -7529,120 +7375,6 @@ declare namespace LocalJSX {
*/
"value"?: any | null;
}
- interface IonPickerLegacy {
- /**
- * If `true`, the picker will animate.
- * @default true
- */
- "animated"?: boolean;
- /**
- * If `true`, the picker will be dismissed when the backdrop is clicked.
- * @default true
- */
- "backdropDismiss"?: boolean;
- /**
- * Array of buttons to be displayed at the top of the picker.
- * @default []
- */
- "buttons"?: PickerButton[];
- /**
- * Array of columns to be displayed in the picker.
- * @default []
- */
- "columns"?: PickerColumn[];
- /**
- * Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces.
- */
- "cssClass"?: string | string[];
- "delegate"?: FrameworkDelegate;
- /**
- * Number of milliseconds to wait before dismissing the picker.
- * @default 0
- */
- "duration"?: number;
- /**
- * Animation to use when the picker is presented.
- */
- "enterAnimation"?: AnimationBuilder;
- /**
- * @default false
- */
- "hasController"?: boolean;
- /**
- * Additional attributes to pass to the picker.
- */
- "htmlAttributes"?: { [key: string]: any };
- /**
- * If `true`, the picker will open. If `false`, the picker will close. Use this if you need finer grained control over presentation, otherwise just use the pickerController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the picker dismisses. You will need to do that in your code.
- * @default false
- */
- "isOpen"?: boolean;
- /**
- * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
- * @default true
- */
- "keyboardClose"?: boolean;
- /**
- * Animation to use when the picker is dismissed.
- */
- "leaveAnimation"?: AnimationBuilder;
- /**
- * The mode determines which platform styles to use.
- */
- "mode"?: "ios" | "md";
- /**
- * Emitted after the picker has dismissed. Shorthand for ionPickerDidDismiss.
- */
- "onDidDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted after the picker has presented. Shorthand for ionPickerWillDismiss.
- */
- "onDidPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted after the picker has dismissed.
- */
- "onIonPickerDidDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted after the picker has presented.
- */
- "onIonPickerDidPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has dismissed.
- */
- "onIonPickerWillDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has presented.
- */
- "onIonPickerWillPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has dismissed. Shorthand for ionPickerWillDismiss.
- */
- "onWillDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has presented. Shorthand for ionPickerWillPresent.
- */
- "onWillPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- "overlayIndex": number;
- /**
- * If `true`, a backdrop will be displayed behind the picker.
- * @default true
- */
- "showBackdrop"?: boolean;
- /**
- * An ID corresponding to the trigger element that causes the picker to open when clicked.
- */
- "trigger"?: string | undefined;
- }
- interface IonPickerLegacyColumn {
- /**
- * Picker column data
- */
- "col": PickerColumn;
- /**
- * Emitted when the selected value has changed
- */
- "onIonPickerColChange"?: (event: IonPickerLegacyColumnCustomEvent) => void;
- }
interface IonPopover {
/**
* Describes how to align the popover content with the `reference` point. Defaults to `"center"` for `ios` mode, and `"start"` for `md` mode.
@@ -9612,18 +9344,6 @@ declare namespace LocalJSX {
"value": string;
"color": Color;
}
- interface IonPickerLegacyAttributes {
- "overlayIndex": number;
- "hasController": boolean;
- "keyboardClose": boolean;
- "cssClass": string | string[];
- "duration": number;
- "showBackdrop": boolean;
- "backdropDismiss": boolean;
- "animated": boolean;
- "isOpen": boolean;
- "trigger": string | undefined;
- }
interface IonPopoverAttributes {
"hasController": boolean;
"overlayIndex": number;
@@ -9982,8 +9702,6 @@ declare namespace LocalJSX {
"ion-picker": IonPicker;
"ion-picker-column": Omit & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes]?: IonPickerColumn[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `attr:${K}`]?: IonPickerColumnAttributes[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `prop:${K}`]?: IonPickerColumn[K] };
"ion-picker-column-option": Omit & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes]?: IonPickerColumnOption[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `attr:${K}`]?: IonPickerColumnOptionAttributes[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `prop:${K}`]?: IonPickerColumnOption[K] };
- "ion-picker-legacy": Omit & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes]?: IonPickerLegacy[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `attr:${K}`]?: IonPickerLegacyAttributes[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `prop:${K}`]?: IonPickerLegacy[K] } & OneOf<"overlayIndex", IonPickerLegacy["overlayIndex"], IonPickerLegacyAttributes["overlayIndex"]>;
- "ion-picker-legacy-column": IonPickerLegacyColumn;
"ion-popover": Omit & { [K in keyof IonPopover & keyof IonPopoverAttributes]?: IonPopover[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `attr:${K}`]?: IonPopoverAttributes[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `prop:${K}`]?: IonPopover[K] } & OneOf<"overlayIndex", IonPopover["overlayIndex"], IonPopoverAttributes["overlayIndex"]>;
"ion-progress-bar": Omit & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes]?: IonProgressBar[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `attr:${K}`]?: IonProgressBarAttributes[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `prop:${K}`]?: IonProgressBar[K] };
"ion-radio": Omit & { [K in keyof IonRadio & keyof IonRadioAttributes]?: IonRadio[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `attr:${K}`]?: IonRadioAttributes[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `prop:${K}`]?: IonRadio[K] };
@@ -10085,8 +9803,6 @@ declare module "@stencil/core" {
"ion-picker": LocalJSX.IntrinsicElements["ion-picker"] & JSXBase.HTMLAttributes;
"ion-picker-column": LocalJSX.IntrinsicElements["ion-picker-column"] & JSXBase.HTMLAttributes;
"ion-picker-column-option": LocalJSX.IntrinsicElements["ion-picker-column-option"] & JSXBase.HTMLAttributes;
- "ion-picker-legacy": LocalJSX.IntrinsicElements["ion-picker-legacy"] & JSXBase.HTMLAttributes;
- "ion-picker-legacy-column": LocalJSX.IntrinsicElements["ion-picker-legacy-column"] & JSXBase.HTMLAttributes;
"ion-popover": LocalJSX.IntrinsicElements["ion-popover"] & JSXBase.HTMLAttributes;
"ion-progress-bar": LocalJSX.IntrinsicElements["ion-progress-bar"] & JSXBase.HTMLAttributes;
"ion-radio": LocalJSX.IntrinsicElements["ion-radio"] & JSXBase.HTMLAttributes;
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts b/core/src/components/app/test/safe-area/app.e2e.ts
index 336cdffcc45..9741499a736 100644
--- a/core/src/components/app/test/safe-area/app.e2e.ts
+++ b/core/src/components/app/test/safe-area/app.e2e.ts
@@ -37,9 +37,6 @@ configs({ directions: ['ltr'] }).forEach(({ config, title, screenshot }) => {
test('should not have visual regressions with menu', async ({ page }) => {
await testOverlay(page, '#show-menu', 'ionDidOpen', 'menu');
});
- test('should not have visual regressions with picker', async ({ page }) => {
- await testOverlay(page, '#show-picker', 'ionPickerDidPresent', 'picker');
- });
test('should not have visual regressions with toast', async ({ page }) => {
await testOverlay(page, '#show-toast', 'ionToastDidPresent', 'toast');
});
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png
index 236e564c681..fd0723f0b10 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png
index d6978bd6ab2..836fa89e6ee 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png
index 7b6912a77b6..adfac749f03 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png
index 1faef728a96..de9f1f5938c 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png
index 2160bf71c71..7c35e90f7f6 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png
index e18e09840ac..e6d505459d0 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png
index 2925d01cc40..27cfb472784 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png
index 625d61957f4..fb99cd5c8a8 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png
index 636bbd74326..75d7c9c8737 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png
index 6bf467070f7..b9acad9f993 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png
index 31175c53c52..14dd0e52a46 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png
index d1e17793401..0a28f3a24ed 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Chrome-linux.png
deleted file mode 100644
index 23e78ac278d..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Chrome-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Firefox-linux.png
deleted file mode 100644
index 6796d9a484f..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Firefox-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Safari-linux.png
deleted file mode 100644
index 2d747790320..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Safari-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Chrome-linux.png
deleted file mode 100644
index 3185d3f27f4..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Chrome-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Firefox-linux.png
deleted file mode 100644
index eaa50d6e5fb..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Firefox-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Safari-linux.png
deleted file mode 100644
index a291fe4c078..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-md-ltr-Mobile-Safari-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png
index 67e9728bdc4..287ecf3e58d 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png
index 6d49226ac1d..3547ba868e2 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png
index 3619f94220f..9a4043a80d6 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png
index 52c2532ebcd..0f4d355207c 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png
index e8afb2df67d..69d433da0cf 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png
index fd6120b1681..75b8379f4b7 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/index.html b/core/src/components/app/test/safe-area/index.html
index 4ad7e6beed4..6c2974100fb 100644
--- a/core/src/components/app/test/safe-area/index.html
+++ b/core/src/components/app/test/safe-area/index.html
@@ -55,7 +55,6 @@
-
@@ -115,26 +114,6 @@
await menu.open();
}
- async function showPicker() {
- const picker = Object.assign(document.createElement('ion-picker-legacy'), {
- columns: [
- {
- name: 'Picker',
- selectedIndex: 2,
- options: [
- { text: 'First' },
- { text: 'Second' },
- { text: 'Third' },
- { text: 'Fourth' },
- { text: 'Fifth' },
- ],
- },
- ],
- });
- document.body.appendChild(picker);
- await picker.present();
- }
-
async function showToast() {
const toast = Object.assign(document.createElement('ion-toast'), {
message: 'Hello world!',
diff --git a/core/src/components/picker-legacy-column/picker-column.ios.scss b/core/src/components/picker-legacy-column/picker-column.ios.scss
deleted file mode 100644
index 16c9e511571..00000000000
--- a/core/src/components/picker-legacy-column/picker-column.ios.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-@import "./picker-column";
-@import "../picker-legacy/picker.ios.vars";
-
-// iOS Picker Column
-// --------------------------------------------------
-
-.picker-col {
- @include padding($picker-ios-column-padding-top, $picker-ios-column-padding-end, $picker-ios-column-padding-bottom, $picker-ios-column-padding-start);
-
- transform-style: preserve-3d;
-}
-
-.picker-prefix,
-.picker-suffix,
-.picker-opts {
- top: $picker-ios-option-offset-y;
-
- transform-style: preserve-3d;
-
- color: inherit;
-
- font-size: $picker-ios-option-font-size;
-
- line-height: $picker-ios-option-height;
- pointer-events: none;
-}
-
-.picker-opt {
- @include padding($picker-ios-option-padding-top, $picker-ios-option-padding-end, $picker-ios-option-padding-bottom, $picker-ios-option-padding-start);
- @include margin(0);
- @include transform-origin(center, center);
-
- height: 46px;
-
- transform-style: preserve-3d;
-
- transition-timing-function: ease-out;
-
- background: transparent;
- color: inherit;
-
- font-size: $picker-ios-option-font-size;
-
- line-height: $picker-ios-option-height;
- backface-visibility: hidden;
- pointer-events: auto;
-}
diff --git a/core/src/components/picker-legacy-column/picker-column.md.scss b/core/src/components/picker-legacy-column/picker-column.md.scss
deleted file mode 100644
index 841f30b4b8f..00000000000
--- a/core/src/components/picker-legacy-column/picker-column.md.scss
+++ /dev/null
@@ -1,51 +0,0 @@
-@import "./picker-column";
-@import "../picker-legacy/picker.md.vars";
-
-// Material Design Picker Column
-// --------------------------------------------------
-
-.picker-col {
- @include padding($picker-md-column-padding-top, $picker-md-column-padding-end, $picker-md-column-padding-bottom, $picker-md-column-padding-start);
-
- transform-style: preserve-3d;
-}
-
-.picker-prefix,
-.picker-suffix,
-.picker-opts {
- top: $picker-md-option-offset-y;
-
- transform-style: preserve-3d;
-
- color: inherit;
-
- font-size: $picker-md-option-font-size;
-
- line-height: $picker-md-option-height;
- pointer-events: none;
-}
-
-
-.picker-opt {
- @include margin(0);
- @include padding($picker-md-option-padding-top, $picker-md-option-padding-end, $picker-md-option-padding-bottom, $picker-md-option-padding-start);
-
- height: 43px;
-
- transition-timing-function: ease-out;
-
- background: transparent;
- color: inherit;
-
- font-size: $picker-md-option-font-size;
-
- line-height: $picker-md-option-height;
- backface-visibility: hidden;
- pointer-events: auto;
-}
-
-.picker-prefix,
-.picker-suffix,
-.picker-opt.picker-opt-selected {
- color: $picker-md-option-selected-color;
-}
diff --git a/core/src/components/picker-legacy-column/picker-column.scss b/core/src/components/picker-legacy-column/picker-column.scss
deleted file mode 100644
index 9fe984c4e46..00000000000
--- a/core/src/components/picker-legacy-column/picker-column.scss
+++ /dev/null
@@ -1,89 +0,0 @@
-@import "../../themes/ionic.globals";
-
-// Picker Column
-// --------------------------------------------------
-
-.picker-col {
- display: flex;
- position: relative;
-
- flex: 1;
- justify-content: center;
-
- height: 100%;
- box-sizing: content-box;
-
- contain: content;
-}
-
-.picker-opts {
- position: relative;
-
- flex: 1;
-
- max-width: 100%;
-}
-
-// contain property is supported by Chrome
-.picker-opt {
- @include position(0, null, null, 0);
-
- display: block;
- position: absolute;
-
- width: 100%;
-
- border: 0;
-
- text-align: center;
- text-overflow: ellipsis;
-
- white-space: nowrap;
-
- contain: strict;
- overflow: hidden;
- will-change: transform;
-}
-
-.picker-opt.picker-opt-disabled {
- pointer-events: none;
-}
-
-.picker-opt-disabled {
- opacity: 0;
-}
-
-.picker-opts-left {
- justify-content: flex-start;
-}
-
-.picker-opts-right {
- justify-content: flex-end;
-}
-
-.picker-opt {
- &:active,
- &:focus {
- outline: none;
- }
-}
-
-.picker-prefix {
- position: relative;
-
- flex: 1;
-
- text-align: end;
-
- white-space: nowrap;
-}
-
-.picker-suffix {
- position: relative;
-
- flex: 1;
-
- text-align: start;
-
- white-space: nowrap;
-}
diff --git a/core/src/components/picker-legacy-column/picker-column.tsx b/core/src/components/picker-legacy-column/picker-column.tsx
deleted file mode 100644
index 93bb7544895..00000000000
--- a/core/src/components/picker-legacy-column/picker-column.tsx
+++ /dev/null
@@ -1,440 +0,0 @@
-import type { ComponentInterface, EventEmitter } from '@stencil/core';
-import { Component, Element, Event, Host, Prop, Watch, h } from '@stencil/core';
-import { clamp } from '@utils/helpers';
-import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from '@utils/native/haptic';
-import { getClassMap } from '@utils/theme';
-
-import { getIonMode } from '../../global/ionic-global';
-import type { Gesture, GestureDetail } from '../../interface';
-import type { PickerColumn } from '../picker-legacy/picker-interface';
-
-/**
- * @internal
- */
-@Component({
- tag: 'ion-picker-legacy-column',
- styleUrls: {
- ios: 'picker-column.ios.scss',
- md: 'picker-column.md.scss',
- },
-})
-export class PickerColumnCmp implements ComponentInterface {
- private bounceFrom!: number;
- private lastIndex?: number;
- private minY!: number;
- private maxY!: number;
- private optHeight = 0;
- private rotateFactor = 0;
- private scaleFactor = 1;
- private velocity = 0;
- private y = 0;
- private optsEl?: HTMLElement;
- private gesture?: Gesture;
- private rafId?: ReturnType;
- private tmrId?: ReturnType;
- private noAnimate = true;
- // `colDidChange` is a flag that gets set when the column is changed
- // dynamically. When this flag is set, the column will refresh
- // after the component re-renders to incorporate the new column data.
- // This is necessary because `this.refresh` queries for the option elements,
- // so it needs to wait for the latest elements to be available in the DOM.
- // Ex: column is created with 3 options. User updates the column data
- // to have 5 options. The column will still think it only has 3 options.
- private colDidChange = false;
-
- @Element() el!: HTMLElement;
-
- /**
- * Emitted when the selected value has changed
- * @internal
- */
- @Event() ionPickerColChange!: EventEmitter;
-
- /** Picker column data */
- @Prop() col!: PickerColumn;
- @Watch('col')
- protected colChanged() {
- this.colDidChange = true;
- }
-
- async connectedCallback() {
- let pickerRotateFactor = 0;
- let pickerScaleFactor = 0.81;
-
- const mode = getIonMode(this);
-
- if (mode === 'ios') {
- pickerRotateFactor = -0.46;
- pickerScaleFactor = 1;
- }
-
- this.rotateFactor = pickerRotateFactor;
- this.scaleFactor = pickerScaleFactor;
-
- this.gesture = (await import('../../utils/gesture')).createGesture({
- el: this.el,
- gestureName: 'picker-swipe',
- gesturePriority: 100,
- threshold: 0,
- passive: false,
- onStart: (ev) => this.onStart(ev),
- onMove: (ev) => this.onMove(ev),
- onEnd: (ev) => this.onEnd(ev),
- });
- this.gesture.enable();
- // Options have not been initialized yet
- // Animation must be disabled through the `noAnimate` flag
- // Otherwise, the options will render
- // at the top of the column and transition down
- this.tmrId = setTimeout(() => {
- this.noAnimate = false;
- // After initialization, `refresh()` will be called
- // At this point, animation will be enabled. The options will
- // animate as they are being selected.
- this.refresh(true);
- }, 250);
- }
-
- componentDidLoad() {
- this.onDomChange();
- }
-
- componentDidUpdate() {
- // Options may have changed since last update.
- if (this.colDidChange) {
- // Animation must be disabled through the `onDomChange` parameter.
- // Otherwise, the recently added options will render
- // at the top of the column and transition down
- this.onDomChange(true, false);
- this.colDidChange = false;
- }
- }
-
- disconnectedCallback() {
- if (this.rafId !== undefined) cancelAnimationFrame(this.rafId);
- if (this.tmrId) clearTimeout(this.tmrId);
- if (this.gesture) {
- this.gesture.destroy();
- this.gesture = undefined;
- }
- }
-
- private emitColChange() {
- this.ionPickerColChange.emit(this.col);
- }
-
- private setSelected(selectedIndex: number, duration: number) {
- // if there is a selected index, then figure out it's y position
- // if there isn't a selected index, then just use the top y position
- const y = selectedIndex > -1 ? -(selectedIndex * this.optHeight) : 0;
-
- this.velocity = 0;
-
- // set what y position we're at
- if (this.rafId !== undefined) cancelAnimationFrame(this.rafId);
- this.update(y, duration, true);
-
- this.emitColChange();
- }
-
- private update(y: number, duration: number, saveY: boolean) {
- if (!this.optsEl) {
- return;
- }
-
- // ensure we've got a good round number :)
- let translateY = 0;
- let translateZ = 0;
- const { col, rotateFactor } = this;
- const prevSelected = col.selectedIndex;
- const selectedIndex = (col.selectedIndex = this.indexForY(-y));
- const durationStr = duration === 0 ? '' : duration + 'ms';
- const scaleStr = `scale(${this.scaleFactor})`;
-
- const children = this.optsEl.children;
- for (let i = 0; i < children.length; i++) {
- const button = children[i] as HTMLElement;
- const opt = col.options[i];
- const optOffset = i * this.optHeight + y;
- let transform = '';
-
- if (rotateFactor !== 0) {
- const rotateX = optOffset * rotateFactor;
- if (Math.abs(rotateX) <= 90) {
- translateY = 0;
- translateZ = 90;
- transform = `rotateX(${rotateX}deg) `;
- } else {
- translateY = -9999;
- }
- } else {
- translateZ = 0;
- translateY = optOffset;
- }
-
- const selected = selectedIndex === i;
- transform += `translate3d(0px,${translateY}px,${translateZ}px) `;
- if (this.scaleFactor !== 1 && !selected) {
- transform += scaleStr;
- }
-
- // Update transition duration
- if (this.noAnimate) {
- opt.duration = 0;
- button.style.transitionDuration = '';
- } else if (duration !== opt.duration) {
- opt.duration = duration;
- button.style.transitionDuration = durationStr;
- }
-
- // Update transform
- if (transform !== opt.transform) {
- opt.transform = transform;
- }
- button.style.transform = transform;
-
- /**
- * Ensure that the select column
- * item has the selected class
- */
- opt.selected = selected;
-
- if (selected) {
- button.classList.add(PICKER_OPT_SELECTED);
- } else {
- button.classList.remove(PICKER_OPT_SELECTED);
- }
- }
- this.col.prevSelected = prevSelected;
-
- if (saveY) {
- this.y = y;
- }
-
- if (this.lastIndex !== selectedIndex) {
- // have not set a last index yet
- hapticSelectionChanged();
- this.lastIndex = selectedIndex;
- }
- }
-
- private decelerate() {
- if (this.velocity !== 0) {
- // still decelerating
- this.velocity *= DECELERATION_FRICTION;
-
- // do not let it go slower than a velocity of 1
- this.velocity = this.velocity > 0 ? Math.max(this.velocity, 1) : Math.min(this.velocity, -1);
-
- let y = this.y + this.velocity;
-
- if (y > this.minY) {
- // whoops, it's trying to scroll up farther than the options we have!
- y = this.minY;
- this.velocity = 0;
- } else if (y < this.maxY) {
- // gahh, it's trying to scroll down farther than we can!
- y = this.maxY;
- this.velocity = 0;
- }
-
- this.update(y, 0, true);
- const notLockedIn = Math.round(y) % this.optHeight !== 0 || Math.abs(this.velocity) > 1;
- if (notLockedIn) {
- // isn't locked in yet, keep decelerating until it is
- this.rafId = requestAnimationFrame(() => this.decelerate());
- } else {
- this.velocity = 0;
- this.emitColChange();
- hapticSelectionEnd();
- }
- } else if (this.y % this.optHeight !== 0) {
- // needs to still get locked into a position so options line up
- const currentPos = Math.abs(this.y % this.optHeight);
-
- // create a velocity in the direction it needs to scroll
- this.velocity = currentPos > this.optHeight / 2 ? 1 : -1;
-
- this.decelerate();
- }
- }
-
- private indexForY(y: number) {
- return Math.min(Math.max(Math.abs(Math.round(y / this.optHeight)), 0), this.col.options.length - 1);
- }
-
- private onStart(detail: GestureDetail) {
- // We have to prevent default in order to block scrolling under the picker
- // but we DO NOT have to stop propagation, since we still want
- // some "click" events to capture
- if (detail.event.cancelable) {
- detail.event.preventDefault();
- }
- detail.event.stopPropagation();
-
- hapticSelectionStart();
-
- // reset everything
- if (this.rafId !== undefined) cancelAnimationFrame(this.rafId);
- const options = this.col.options;
- let minY = options.length - 1;
- let maxY = 0;
- for (let i = 0; i < options.length; i++) {
- if (!options[i].disabled) {
- minY = Math.min(minY, i);
- maxY = Math.max(maxY, i);
- }
- }
-
- this.minY = -(minY * this.optHeight);
- this.maxY = -(maxY * this.optHeight);
- }
-
- private onMove(detail: GestureDetail) {
- if (detail.event.cancelable) {
- detail.event.preventDefault();
- }
- detail.event.stopPropagation();
-
- // update the scroll position relative to pointer start position
- let y = this.y + detail.deltaY;
-
- if (y > this.minY) {
- // scrolling up higher than scroll area
- y = Math.pow(y, 0.8);
- this.bounceFrom = y;
- } else if (y < this.maxY) {
- // scrolling down below scroll area
- y += Math.pow(this.maxY - y, 0.9);
- this.bounceFrom = y;
- } else {
- this.bounceFrom = 0;
- }
-
- this.update(y, 0, false);
- }
-
- private onEnd(detail: GestureDetail) {
- if (this.bounceFrom > 0) {
- // bounce back up
- this.update(this.minY, 100, true);
- this.emitColChange();
- return;
- } else if (this.bounceFrom < 0) {
- // bounce back down
- this.update(this.maxY, 100, true);
- this.emitColChange();
- return;
- }
-
- this.velocity = clamp(-MAX_PICKER_SPEED, detail.velocityY * 23, MAX_PICKER_SPEED);
- if (this.velocity === 0 && detail.deltaY === 0) {
- const opt = (detail.event.target as Element).closest('.picker-opt');
- if (opt?.hasAttribute('opt-index')) {
- this.setSelected(parseInt(opt.getAttribute('opt-index')!, 10), TRANSITION_DURATION);
- }
- } else {
- this.y += detail.deltaY;
-
- if (Math.abs(detail.velocityY) < 0.05) {
- const isScrollingUp = detail.deltaY > 0;
- const optHeightFraction = (Math.abs(this.y) % this.optHeight) / this.optHeight;
-
- if (isScrollingUp && optHeightFraction > 0.5) {
- this.velocity = Math.abs(this.velocity) * -1;
- } else if (!isScrollingUp && optHeightFraction <= 0.5) {
- this.velocity = Math.abs(this.velocity);
- }
- }
-
- this.decelerate();
- }
- }
-
- private refresh(forceRefresh?: boolean, animated?: boolean) {
- let min = this.col.options.length - 1;
- let max = 0;
- const options = this.col.options;
- for (let i = 0; i < options.length; i++) {
- if (!options[i].disabled) {
- min = Math.min(min, i);
- max = Math.max(max, i);
- }
- }
-
- /**
- * Only update selected value if column has a
- * velocity of 0. If it does not, then the
- * column is animating might land on
- * a value different than the value at
- * selectedIndex
- */
- if (this.velocity !== 0) {
- return;
- }
-
- const selectedIndex = clamp(min, this.col.selectedIndex ?? 0, max);
- if (this.col.prevSelected !== selectedIndex || forceRefresh) {
- const y = selectedIndex * this.optHeight * -1;
- const duration = animated ? TRANSITION_DURATION : 0;
- this.velocity = 0;
- this.update(y, duration, true);
- }
- }
-
- private onDomChange(forceRefresh?: boolean, animated?: boolean) {
- const colEl = this.optsEl;
- if (colEl) {
- // DOM READ
- // We perfom a DOM read over a rendered item, this needs to happen after the first render or after the column has changed
- this.optHeight = colEl.firstElementChild ? colEl.firstElementChild.clientHeight : 0;
- }
- this.refresh(forceRefresh, animated);
- }
-
- render() {
- const col = this.col;
- const mode = getIonMode(this);
- return (
-
- {col.prefix && (
-