diff --git a/core/api.txt b/core/api.txt index 34e875c3bb5..96ef50a7e82 100644 --- a/core/api.txt +++ b/core/api.txt @@ -917,7 +917,7 @@ ion-picker-column,prop,items,PickerColumnItem[],[],false,false ion-picker-column,prop,mode,"ios" | "md",undefined,false,false ion-picker-column,prop,value,number | string | undefined,undefined,false,false ion-picker-column,method,setFocus,setFocus() => Promise -ion-picker-column,event,ionChange,{ value: string | number | undefined; },true +ion-picker-column,event,ionChange,PickerColumnChangeEventDetail,true ion-picker-column-option,shadow ion-picker-column-option,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record | undefined,'primary',false,true diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 7a97463128e..88e8653b708 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -24,7 +24,7 @@ import { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./compone import { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface"; import { ViewController } from "./components/nav/view-controller"; import { PickerChangeEventDetail } from "./components/picker/picker-interfaces"; -import { PickerColumnItem } from "./components/picker-column/picker-column-interfaces"; +import { PickerColumnChangeEventDetail, PickerColumnItem, 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 } from "./components/radio-group/radio-group-interface"; @@ -60,7 +60,7 @@ export { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./compone export { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface"; export { ViewController } from "./components/nav/view-controller"; export { PickerChangeEventDetail } from "./components/picker/picker-interfaces"; -export { PickerColumnItem } from "./components/picker-column/picker-column-interfaces"; +export { PickerColumnChangeEventDetail, PickerColumnItem, 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 } from "./components/radio-group/radio-group-interface"; @@ -1984,7 +1984,7 @@ export namespace Components { /** * Sets the value prop and fires the ionChange event. This is used when we need to fire ionChange from user-generated events that cannot be caught with normal input/change event listeners. */ - "setValue": (value?: string | number) => Promise; + "setValue": (value: PickerColumnValue) => Promise; /** * The selected option in the picker. */ @@ -4055,7 +4055,7 @@ declare global { new (): HTMLIonPickerElement; }; interface HTMLIonPickerColumnElementEventMap { - "ionChange": { value: string | number | undefined }; + "ionChange": PickerColumnChangeEventDetail; } interface HTMLIonPickerColumnElement extends Components.IonPickerColumn, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLIonPickerColumnElement, ev: IonPickerColumnCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -6635,7 +6635,7 @@ declare namespace LocalJSX { /** * Emitted when the value has changed. */ - "onIonChange"?: (event: IonPickerColumnCustomEvent<{ value: string | number | undefined }>) => void; + "onIonChange"?: (event: IonPickerColumnCustomEvent) => void; /** * The selected option in the picker. */ diff --git a/core/src/components/picker-column/picker-column-interfaces.ts b/core/src/components/picker-column/picker-column-interfaces.ts index a37d9b97f6e..15352dbeeba 100644 --- a/core/src/components/picker-column/picker-column-interfaces.ts +++ b/core/src/components/picker-column/picker-column-interfaces.ts @@ -4,3 +4,9 @@ export interface PickerColumnItem { value: string | number; disabled?: boolean; } + +export interface PickerColumnChangeEventDetail { + value: PickerColumnValue; +} + +export type PickerColumnValue = string | number | undefined; diff --git a/core/src/components/picker-column/picker-column.tsx b/core/src/components/picker-column/picker-column.tsx index 1914e4e6792..9d9aaa8d93d 100644 --- a/core/src/components/picker-column/picker-column.tsx +++ b/core/src/components/picker-column/picker-column.tsx @@ -10,7 +10,7 @@ import { getIonMode } from '../../global/ionic-global'; import type { Color } from '../../interface'; import type { PickerCustomEvent } from '../picker/picker-interfaces'; -import type { PickerColumnItem } from './picker-column-interfaces'; +import type { PickerColumnItem, PickerColumnChangeEventDetail, PickerColumnValue } from './picker-column-interfaces'; /** * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use. @@ -77,7 +77,7 @@ export class PickerColumn implements ComponentInterface { /** * Emitted when the value has changed. */ - @Event() ionChange!: EventEmitter<{ value: string | number | undefined }>; + @Event() ionChange!: EventEmitter; @Watch('value') valueChange() { @@ -175,7 +175,7 @@ export class PickerColumn implements ComponentInterface { * @internal */ @Method() - async setValue(value?: string | number) { + async setValue(value: PickerColumnValue) { if (this.value === value) { return; } diff --git a/core/src/components/picker/picker.tsx b/core/src/components/picker/picker.tsx index 94e079704e5..76f7ac10896 100644 --- a/core/src/components/picker/picker.tsx +++ b/core/src/components/picker/picker.tsx @@ -323,7 +323,9 @@ export class Picker implements ComponentInterface { return; } - const values = inputModeColumn.items.filter((item) => item.disabled !== true); + const options = Array.from(inputModeColumn.querySelectorAll('ion-picker-column-option')).filter( + (el) => el.disabled !== true + ); /** * If users pause for a bit, the search @@ -368,8 +370,13 @@ export class Picker implements ComponentInterface { * 0+(?=[1-9]) --> Match 1 or more zeros that are followed by 1-9 * 0+(?=0$) --> Match 1 or more zeros that must be followed by one 0 and end. */ - const findItemFromCompleteValue = values.find(({ text }) => { - const parsedText = text.replace(/^0+(?=[1-9])|0+(?=0$)/, ''); + const findItemFromCompleteValue = options.find(({ textContent }) => { + /** + * Keyboard entry is currently only used inside of Datetime + * where we guarantee textContent is set. + * If we end up exposing this feature publicly we should revisit this assumption. + */ + const parsedText = textContent!.replace(/^0+(?=[1-9])|0+(?=0$)/, ''); return parsedText === inputEl.value; }); @@ -401,10 +408,12 @@ export class Picker implements ComponentInterface { zeroBehavior: 'start' | 'end' = 'start' ) => { const behavior = zeroBehavior === 'start' ? /^0+/ : /0$/; - const item = colEl.items.find(({ text, disabled }) => disabled !== true && text.replace(behavior, '') === value); + const option = Array.from(colEl.querySelectorAll('ion-picker-column-option')).find((el) => { + return el.disabled !== true && el.textContent!.replace(behavior, '') === value; + }); - if (item) { - colEl.setValue(item.value); + if (option) { + colEl.setValue(option.value); } }; diff --git a/core/src/components/picker/test/keyboard-entry/picker.e2e.ts b/core/src/components/picker/test/keyboard-entry/picker.e2e.ts index e1059c2c0c4..2f0646b5537 100644 --- a/core/src/components/picker/test/keyboard-entry/picker.e2e.ts +++ b/core/src/components/picker/test/keyboard-entry/picker.e2e.ts @@ -17,15 +17,22 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => `, config @@ -37,7 +44,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => await page.keyboard.press('Digit2'); - await expect(ionChange).toHaveReceivedEventDetail({ text: '02', value: 2 }); + await expect(ionChange).toHaveReceivedEventDetail({ value: 2 }); await expect(column).toHaveJSProperty('value', 2); }); @@ -51,7 +58,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => `, config ); - const firstColumn = page.locator('ion-picker-column#first'); const secondColumn = page.locator('ion-picker-column#second'); const highlight = page.locator('ion-picker .picker-highlight'); @@ -92,12 +114,12 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => await page.keyboard.press('Digit2'); - await expect(firstIonChange).toHaveReceivedEventDetail({ text: '02', value: 2 }); + await expect(firstIonChange).toHaveReceivedEventDetail({ value: 2 }); await expect(firstColumn).toHaveJSProperty('value', 2); await page.keyboard.press('Digit2+Digit4'); - await expect(secondIonChange).toHaveReceivedEventDetail({ text: '24', value: 24 }); + await expect(secondIonChange).toHaveReceivedEventDetail({ value: 24 }); await expect(secondColumn).toHaveJSProperty('value', 24); }); @@ -110,7 +132,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => `, config @@ -131,7 +161,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => await page.keyboard.press('Digit0'); - await expect(ionChange).toHaveReceivedEventDetail({ text: '00', value: 12 }); + await expect(ionChange).toHaveReceivedEventDetail({ value: 12 }); await expect(column).toHaveJSProperty('value', 12); }); }); diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index 9c93facac52..947aaaea336 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -1466,11 +1466,13 @@ export class IonPickerColumn { } +import type { PickerColumnChangeEventDetail as IIonPickerColumnPickerColumnChangeEventDetail } from '@ionic/core'; + export declare interface IonPickerColumn extends Components.IonPickerColumn { /** * Emitted when the value has changed. */ - ionChange: EventEmitter>; + ionChange: EventEmitter>; } diff --git a/packages/angular/standalone/src/directives/proxies.ts b/packages/angular/standalone/src/directives/proxies.ts index 9e725f2e82d..400cb21b121 100644 --- a/packages/angular/standalone/src/directives/proxies.ts +++ b/packages/angular/standalone/src/directives/proxies.ts @@ -1462,11 +1462,13 @@ export class IonPickerColumn { } +import type { PickerColumnChangeEventDetail as IIonPickerColumnPickerColumnChangeEventDetail } from '@ionic/core/components'; + export declare interface IonPickerColumn extends Components.IonPickerColumn { /** * Emitted when the value has changed. */ - ionChange: EventEmitter>; + ionChange: EventEmitter>; }