Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
7b21bd4
feat(picker-column): add styles, disabled and active states
liamdebeasi Dec 1, 2023
9d0834b
chore(): add updated snapshots
Ionitron Dec 1, 2023
1aeb194
chore: run build
liamdebeasi Dec 1, 2023
eace642
refactor: add slot to integrate basic options
liamdebeasi Dec 1, 2023
b68c93d
refactor: scrolling column sets value
liamdebeasi Dec 1, 2023
2f3f9dc
refactor: clicking option sets value
liamdebeasi Dec 1, 2023
75ee951
chore: lint
liamdebeasi Dec 1, 2023
b1fc672
fix: column scrolls into view when option is ready
liamdebeasi Dec 1, 2023
2c773ed
fix: do not emit ionChange if value did not change
liamdebeasi Dec 1, 2023
3470c64
build and lint
liamdebeasi Dec 1, 2023
8d5a043
add api
liamdebeasi Dec 1, 2023
34ec94f
test: picker-column tests pass
liamdebeasi Dec 1, 2023
e933833
test: picker tests pass
liamdebeasi Dec 1, 2023
fc36cc5
add TODOs
liamdebeasi Dec 1, 2023
58a89b3
fix disabled test
liamdebeasi Dec 1, 2023
948c8d8
refactor: cache picker column el
liamdebeasi Dec 1, 2023
7473d64
lint
liamdebeasi Dec 1, 2023
313285d
skip test
liamdebeasi Dec 1, 2023
5a9a7d1
refactor: integrate datetime with picker-column-option
liamdebeasi Dec 4, 2023
8693fd6
refactor: remove default slotted content
liamdebeasi Dec 4, 2023
84c3c52
fix: datetime passes disabled state correctly
liamdebeasi Dec 4, 2023
edb7bad
typo
liamdebeasi Dec 4, 2023
ed8cfa0
chore: remove unused var
liamdebeasi Dec 4, 2023
506f42b
fix: picker-column emits correct payload
liamdebeasi Dec 4, 2023
892a269
test: migrate some datetime tests
liamdebeasi Dec 4, 2023
dc93b8a
test: migrate locale datetime tests
liamdebeasi Dec 4, 2023
656ac5b
test: migrate minmax datetime test
liamdebeasi Dec 4, 2023
cab5646
fix: datetime use keys for stable identity
liamdebeasi Dec 4, 2023
59113bb
test: migrate prefer-wheel tests
liamdebeasi Dec 4, 2023
9562875
fix: picker column option notifies picker column when ready
liamdebeasi Dec 4, 2023
cfcbcd9
fix: picker column selects correct element on scroll
liamdebeasi Dec 4, 2023
3b67bd3
build and lint
liamdebeasi Dec 4, 2023
4b564ee
test: remove .only
liamdebeasi Dec 4, 2023
3da0590
fix(datetime): expose shadow parts
liamdebeasi Dec 4, 2023
514b3b6
fix(picker-column-option): color can be overridden
liamdebeasi Dec 4, 2023
6ddc15f
test(datetime): migrate custom tests
liamdebeasi Dec 4, 2023
6d2f998
chore: lint
liamdebeasi Dec 4, 2023
a524131
add todo
liamdebeasi Dec 4, 2023
90e2d2c
remove outdated comment
liamdebeasi Dec 4, 2023
c1d5401
test(datetime): migrate one more test file
liamdebeasi Dec 4, 2023
e8d5599
Update core/src/components/picker-column/picker-column.tsx
liamdebeasi Dec 5, 2023
d48c41d
use generic for query selector
liamdebeasi Dec 5, 2023
e4797f7
remove explicit type since it can be inferred
liamdebeasi Dec 5, 2023
a98e85d
remove explicit type case
liamdebeasi Dec 5, 2023
33a21d3
remove typecast in favor of generic
liamdebeasi Dec 5, 2023
0ef015b
remove unneeded typecast
liamdebeasi Dec 5, 2023
f9d01b9
remove explicit types
liamdebeasi Dec 5, 2023
cf3d028
active part no longer includes base part
liamdebeasi Dec 5, 2023
d36d645
lint
liamdebeasi Dec 5, 2023
59bd18a
chore: sync
liamdebeasi Dec 5, 2023
fdfc5fc
chore: resolve merge conflicts
liamdebeasi Dec 5, 2023
ca1b519
fix bad merge on api.txt
liamdebeasi Dec 5, 2023
f88b74d
fix(picker): keyboard entry works with options
liamdebeasi Dec 6, 2023
2552147
clean up interfaces
liamdebeasi Dec 6, 2023
a00f563
Update picker.tsx
liamdebeasi Dec 6, 2023
56c9575
lint
liamdebeasi Dec 6, 2023
cbb7d65
chore: sync
liamdebeasi Dec 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>
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<never, never> | undefined,'primary',false,true
Expand Down
10 changes: 5 additions & 5 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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<void>;
"setValue": (value: PickerColumnValue) => Promise<void>;
/**
* The selected option in the picker.
*/
Expand Down Expand Up @@ -4055,7 +4055,7 @@ declare global {
new (): HTMLIonPickerElement;
};
interface HTMLIonPickerColumnElementEventMap {
"ionChange": { value: string | number | undefined };
"ionChange": PickerColumnChangeEventDetail;
}
interface HTMLIonPickerColumnElement extends Components.IonPickerColumn, HTMLStencilElement {
addEventListener<K extends keyof HTMLIonPickerColumnElementEventMap>(type: K, listener: (this: HTMLIonPickerColumnElement, ev: IonPickerColumnCustomEvent<HTMLIonPickerColumnElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
Expand Down Expand Up @@ -6635,7 +6635,7 @@ declare namespace LocalJSX {
/**
* Emitted when the value has changed.
*/
"onIonChange"?: (event: IonPickerColumnCustomEvent<{ value: string | number | undefined }>) => void;
"onIonChange"?: (event: IonPickerColumnCustomEvent<PickerColumnChangeEventDetail>) => void;
/**
* The selected option in the picker.
*/
Expand Down
6 changes: 6 additions & 0 deletions core/src/components/picker-column/picker-column-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ export interface PickerColumnItem {
value: string | number;
disabled?: boolean;
}

export interface PickerColumnChangeEventDetail {
value: PickerColumnValue;
}

export type PickerColumnValue = string | number | undefined;
6 changes: 3 additions & 3 deletions core/src/components/picker-column/picker-column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<PickerColumnChangeEventDetail>;

@Watch('value')
valueChange() {
Expand Down Expand Up @@ -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;
}
Expand Down
21 changes: 15 additions & 6 deletions core/src/components/picker/picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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$)/, '');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this to a comment directly in the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in a00f563

return parsedText === inputEl.value;
});

Expand Down Expand Up @@ -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);
}
};

Expand Down
52 changes: 41 additions & 11 deletions core/src/components/picker/test/keyboard-entry/picker.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,22 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>

<script>
const column = document.querySelector('ion-picker-column');
column.items = [
column.numericInput = true;
const items = [
{ text: '01', value: 1 },
{ text: '02', value: 2 },
{ text: '03', value: 3 },
{ text: '04', value: 4 },
{ text: '05', value: 5 }
];
column.value = 5;
column.numericInput = true;

items.forEach((item) => {
const option = document.createElement('ion-picker-column-option');
option.value = item.value;
option.textContent = item.text;

column.appendChild(option);
});
</script>
`,
config
Expand All @@ -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);
});

Expand All @@ -51,7 +58,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>

<script>
const firstColumn = document.querySelector('ion-picker-column#first');
firstColumn.items = [
const firstItems = [
{ text: '01', value: 1 },
{ text: '02', value: 2 },
{ text: '03', value: 3 },
Expand All @@ -61,8 +68,16 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
firstColumn.value = 5;
firstColumn.numericInput = true;

firstItems.forEach((item) => {
const option = document.createElement('ion-picker-column-option');
option.value = item.value;
option.textContent = item.text;

firstColumn.appendChild(option);
});

const secondColumn = document.querySelector('ion-picker-column#second');
secondColumn.items = [
const secondItems = [
{ text: '20', value: 20 },
{ text: '21', value: 21 },
{ text: '22', value: 22 },
Expand All @@ -71,11 +86,18 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
];
secondColumn.value = 22;
secondColumn.numericInput = true;

secondItems.forEach((item) => {
const option = document.createElement('ion-picker-column-option');
option.value = item.value;
option.textContent = item.text;

secondColumn.appendChild(option);
});
</script>
`,
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');
Expand All @@ -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);
});

Expand All @@ -110,7 +132,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>

<script>
const column = document.querySelector('ion-picker-column');
column.items = [
const items = [
{ text: '00', value: 12 },
{ text: '01', value: 1 },
{ text: '02', value: 2 },
Expand All @@ -120,6 +142,14 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
];
column.value = 5;
column.numericInput = true;

items.forEach((item) => {
const option = document.createElement('ion-picker-column-option');
option.value = item.value;
option.textContent = item.text;

column.appendChild(option);
});
</script>
`,
config
Expand All @@ -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);
});
});
Expand Down
4 changes: 3 additions & 1 deletion packages/angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<CustomEvent<{ value: string | number | undefined }>>;
ionChange: EventEmitter<CustomEvent<IIonPickerColumnPickerColumnChangeEventDetail>>;
}


Expand Down
4 changes: 3 additions & 1 deletion packages/angular/standalone/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<CustomEvent<{ value: string | number | undefined }>>;
ionChange: EventEmitter<CustomEvent<IIonPickerColumnPickerColumnChangeEventDetail>>;
}


Expand Down