feat(picker-column): add prefix and suffix slots (#28603)
Issue number: Internal --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> The new picker component does not have a counterpart for the `prefix` and `suffix` properties on the old picker column. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - `prefix` and `suffix` slots added. - Picker items wrapped in a new `.picker-opts` element for positioning purposes, similar to the legacy picker column. This necessitated additional changes to functionality and styling, since previously the items were direct descendants of the host. - New `setFocus` method added. This gets around a browser bug in Firefox where calling `focus()` on the column doesn't correctly move focus, as the nearest focusable element (`.picker-opts`) is in the shadow DOM. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> While you can no longer call `focus()` on the column in Firefox and must use `setFocus()` instead, this isn't considered a breaking change because this component isn't public API yet. ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> --------- Co-authored-by: ionitron <hi@ionicframework.com>
@@ -916,6 +916,7 @@ ion-picker-column,prop,disabled,boolean,false,false,false
|
||||
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,PickerColumnItem,true
|
||||
|
||||
ion-picker-column-option,shadow
|
||||
|
||||
4
core/src/components.d.ts
vendored
@@ -1977,6 +1977,10 @@ export namespace Components {
|
||||
*/
|
||||
"numericInput": boolean;
|
||||
"scrollActiveItemIntoView": () => Promise<void>;
|
||||
/**
|
||||
* Sets focus on the scrollable container within the picker column. Use this method instead of the global `pickerColumn.focus()`.
|
||||
*/
|
||||
"setFocus": () => Promise<void>;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -25,19 +25,6 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* When using the wheel picker to switch
|
||||
* between months, sometimes the allowed
|
||||
* dates may be filtered. As a result, it
|
||||
* is possible to get a layout shift as
|
||||
* the picker column will shrink to fit the
|
||||
* widest item in the column. Setting a minimum
|
||||
* width avoids this layout shifting.
|
||||
*/
|
||||
ion-picker-column {
|
||||
min-width: 26px;
|
||||
}
|
||||
|
||||
:host(.datetime-size-fixed) {
|
||||
width: auto;
|
||||
height: auto;
|
||||
|
||||
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 25 KiB |
@@ -25,7 +25,7 @@
|
||||
<ion-content class="ion-padding">
|
||||
<ion-button id="open-datetime" onclick="presentPopover(defaultPopover, event)">Present Popover</ion-button>
|
||||
<ion-popover class="datetime-popover" id="default-popover">
|
||||
<ion-datetime value="2022-05-03"></ion-datetime>
|
||||
<ion-datetime value="2022-05-03T14:23:00.000Z"></ion-datetime>
|
||||
</ion-popover>
|
||||
</ion-content>
|
||||
|
||||
|
||||
@@ -447,6 +447,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateColumn = page.locator('.date-column');
|
||||
const dateColumnScrollEl = dateColumn.locator('.picker-opts');
|
||||
const dateValues = dateColumn.locator('.picker-item:not(.picker-item-empty)');
|
||||
|
||||
expect(await dateValues.count()).toBe(90);
|
||||
@@ -455,7 +456,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
* Select 1st item to change the dates rendered
|
||||
*/
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2022-1-1');
|
||||
await dateColumn.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await dateColumnScrollEl.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2021-12-1');
|
||||
@@ -632,6 +633,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateColumn = page.locator('.date-column');
|
||||
const dateColumnScrollEl = dateColumn.locator('.picker-opts');
|
||||
const dateValues = dateColumn.locator('.picker-item:not(.picker-item-empty)');
|
||||
|
||||
expect(await dateValues.count()).toBe(90);
|
||||
@@ -640,7 +642,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
* Select 1st item to change the dates rendered
|
||||
*/
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2022-1-1');
|
||||
await dateColumn.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await dateColumnScrollEl.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2021-12-1');
|
||||
|
||||
@@ -4,13 +4,53 @@
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
@include padding(0px, 16px, 0px, 16px);
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
justify-content: center;
|
||||
|
||||
max-width: 100%;
|
||||
|
||||
height: 200px;
|
||||
|
||||
font-size: 22px;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.picker-opts {
|
||||
/**
|
||||
* This padding must be set here and not on the
|
||||
* host to ensure that the focus highlight on the
|
||||
* column is not overly narrow.
|
||||
*/
|
||||
@include padding(0px, 16px, 0px, 16px);
|
||||
|
||||
/**
|
||||
* When using reactive data, such as in datetime's
|
||||
* wheel picker, there may be layout shifts between
|
||||
* individual columns in a picker as the columns
|
||||
* shrink to fit the widest item in the column.
|
||||
* Setting a minimum width avoids this layout shifting.
|
||||
*
|
||||
* Note that we need this min-width set on the same
|
||||
* element as the vertical padding (i.e. not on the
|
||||
* host).
|
||||
*/
|
||||
min-width: 26px;
|
||||
max-height: 200px;
|
||||
|
||||
outline: none;
|
||||
|
||||
font-size: 22px;
|
||||
/**
|
||||
* Added so that text-align can be set on the host
|
||||
* from external components. For example, datetime
|
||||
* changes the alignment of specific columns in its
|
||||
* wheel pickers.
|
||||
*/
|
||||
text-align: inherit;
|
||||
|
||||
scroll-snap-type: y mandatory;
|
||||
|
||||
/**
|
||||
@@ -22,17 +62,45 @@
|
||||
|
||||
// Hide scrollbars on Firefox
|
||||
scrollbar-width: none;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide scrollbars on Chrome and Safari
|
||||
*/
|
||||
:host::-webkit-scrollbar {
|
||||
.picker-opts::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::slotted([slot="prefix"]), ::slotted([slot="suffix"]) {
|
||||
max-width: 200px;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
::slotted([slot="prefix"]) {
|
||||
/**
|
||||
* This is added in addition to the column's own padding so that there is white
|
||||
* space between the slot and the column's focus highlight.
|
||||
*/
|
||||
@include padding(0, 16px);
|
||||
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
::slotted([slot="suffix"]) {
|
||||
/**
|
||||
* This is added in addition to the column's own padding so that there is white
|
||||
* space between the slot and the column's focus highlight.
|
||||
*/
|
||||
@include padding(0, 16px);
|
||||
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
:host .picker-item {
|
||||
@include padding(0);
|
||||
@include margin(0);
|
||||
@@ -93,7 +161,7 @@
|
||||
}
|
||||
|
||||
@media (any-hover: hover) {
|
||||
:host(:focus) {
|
||||
:host(:focus) .picker-opts {
|
||||
outline: none;
|
||||
|
||||
background: current-color(base, 0.2);
|
||||
|
||||
@@ -13,6 +13,9 @@ import type { PickerColumnItem } from './picker-column-interfaces';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
*
|
||||
* @slot prefix - Content to show on the left side of the picker options.
|
||||
* @slot suffix - Content to show on the right side of the picker options.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-picker-column',
|
||||
@@ -23,6 +26,7 @@ import type { PickerColumnItem } from './picker-column-interfaces';
|
||||
shadow: true,
|
||||
})
|
||||
export class PickerColumn implements ComponentInterface {
|
||||
private scrollEl?: HTMLDivElement | null;
|
||||
private destroyScrollListener?: () => void;
|
||||
private isScrolling = false;
|
||||
private scrollEndCallback?: () => void;
|
||||
@@ -175,13 +179,25 @@ export class PickerColumn implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets focus on the scrollable container within the picker column.
|
||||
* Use this method instead of the global `pickerColumn.focus()`.
|
||||
*/
|
||||
@Method()
|
||||
async setFocus() {
|
||||
if (this.scrollEl) {
|
||||
this.scrollEl.focus();
|
||||
}
|
||||
}
|
||||
|
||||
private centerPickerItemInView = (target: HTMLElement, smooth = true, canExitInputMode = true) => {
|
||||
const { el, isColumnVisible } = this;
|
||||
if (isColumnVisible) {
|
||||
const { isColumnVisible, scrollEl } = this;
|
||||
|
||||
if (isColumnVisible && scrollEl) {
|
||||
// (Vertical offset from parent) - (three empty picker rows) + (half the height of the target to ensure the scroll triggers)
|
||||
const top = target.offsetTop - 3 * target.clientHeight + target.clientHeight / 2;
|
||||
|
||||
if (el.scrollTop !== top) {
|
||||
if (scrollEl.scrollTop !== top) {
|
||||
/**
|
||||
* Setting this flag prevents input
|
||||
* mode from exiting in the picker column's
|
||||
@@ -190,7 +206,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
* of these can cause a scroll to occur.
|
||||
*/
|
||||
this.canExitInputMode = canExitInputMode;
|
||||
el.scroll({
|
||||
scrollEl.scroll({
|
||||
top,
|
||||
left: 0,
|
||||
behavior: smooth ? 'smooth' : undefined,
|
||||
@@ -267,13 +283,15 @@ export class PickerColumn implements ComponentInterface {
|
||||
* be disabled on Android.
|
||||
*/
|
||||
const enableHaptics = isPlatform('ios');
|
||||
const { el } = this;
|
||||
const { el, scrollEl } = this;
|
||||
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
let activeEl: HTMLElement | null = this.activeItem;
|
||||
|
||||
const scrollCallback = () => {
|
||||
raf(() => {
|
||||
if (!scrollEl) return;
|
||||
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = undefined;
|
||||
@@ -288,7 +306,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
* Select item in the center of the column
|
||||
* which is the month/year that we want to select
|
||||
*/
|
||||
const bbox = el.getBoundingClientRect();
|
||||
const bbox = scrollEl.getBoundingClientRect();
|
||||
const centerX = bbox.x + bbox.width / 2;
|
||||
const centerY = bbox.y + bbox.height / 2;
|
||||
|
||||
@@ -378,10 +396,12 @@ export class PickerColumn implements ComponentInterface {
|
||||
* does not fire when component is initially shown.
|
||||
*/
|
||||
raf(() => {
|
||||
el.addEventListener('scroll', scrollCallback);
|
||||
if (!scrollEl) return;
|
||||
|
||||
scrollEl.addEventListener('scroll', scrollCallback);
|
||||
|
||||
this.destroyScrollListener = () => {
|
||||
el.removeEventListener('scroll', scrollCallback);
|
||||
scrollEl.removeEventListener('scroll', scrollCallback);
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -434,62 +454,71 @@ export class PickerColumn implements ComponentInterface {
|
||||
<Host
|
||||
exportparts={`${PICKER_ITEM_PART}, ${PICKER_ITEM_ACTIVE_PART}`}
|
||||
disabled={pickerDisabled}
|
||||
tabindex={pickerDisabled ? null : 0}
|
||||
class={createColorClasses(color, {
|
||||
[mode]: true,
|
||||
['picker-column-active']: isActive,
|
||||
['picker-column-numeric-input']: numericInput,
|
||||
})}
|
||||
>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
{items.map((item, index) => {
|
||||
const isItemDisabled = pickerDisabled || item.disabled || false;
|
||||
<slot name="prefix"></slot>
|
||||
<div
|
||||
class="picker-opts"
|
||||
tabindex={pickerDisabled ? undefined : 0}
|
||||
ref={(el) => {
|
||||
this.scrollEl = el;
|
||||
}}
|
||||
>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
{items.map((item, index) => {
|
||||
const isItemDisabled = pickerDisabled || item.disabled || false;
|
||||
|
||||
{
|
||||
/*
|
||||
Users should be able to tab
|
||||
between multiple columns. As a result,
|
||||
we set tabindex here so that tabbing switches
|
||||
between columns instead of buttons. Users
|
||||
can still use arrow keys on the keyboard to
|
||||
navigate the column up and down.
|
||||
*/
|
||||
}
|
||||
return (
|
||||
<button
|
||||
tabindex="-1"
|
||||
class={{
|
||||
'picker-item': true,
|
||||
}}
|
||||
data-value={item.value}
|
||||
data-index={index}
|
||||
onClick={(ev: Event) => {
|
||||
this.centerPickerItemInView(ev.target as HTMLElement, true);
|
||||
}}
|
||||
disabled={isItemDisabled}
|
||||
part={PICKER_ITEM_PART}
|
||||
>
|
||||
{item.text}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
{
|
||||
/*
|
||||
Users should be able to tab
|
||||
between multiple columns. As a result,
|
||||
we set tabindex here so that tabbing switches
|
||||
between columns instead of buttons. Users
|
||||
can still use arrow keys on the keyboard to
|
||||
navigate the column up and down.
|
||||
*/
|
||||
}
|
||||
return (
|
||||
<button
|
||||
tabindex="-1"
|
||||
class={{
|
||||
'picker-item': true,
|
||||
}}
|
||||
data-value={item.value}
|
||||
data-index={index}
|
||||
onClick={(ev: Event) => {
|
||||
this.centerPickerItemInView(ev.target as HTMLElement, true);
|
||||
}}
|
||||
disabled={isItemDisabled}
|
||||
part={PICKER_ITEM_PART}
|
||||
>
|
||||
{item.text}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<slot name="suffix"></slot>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.0 KiB |
50
core/src/components/picker-column/test/slots/index.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Picker Column - Slots</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Picker Column - Basic</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<ion-picker>
|
||||
<ion-picker-column>
|
||||
<div slot="prefix">Prefix</div>
|
||||
<div slot="suffix">Suffix</div>
|
||||
</ion-picker-column>
|
||||
</ion-picker>
|
||||
<ion-picker>
|
||||
<ion-picker-column>
|
||||
<div slot="prefix">Prefix</div>
|
||||
<div slot="suffix">Long Suffix Long Suffix Long Suffix</div>
|
||||
</ion-picker-column>
|
||||
</ion-picker>
|
||||
</ion-content>
|
||||
<script>
|
||||
const pickerColumns = document.querySelectorAll('ion-picker-column');
|
||||
|
||||
const items = Array(24)
|
||||
.fill()
|
||||
.map((_, i) => ({
|
||||
text: `${i}`,
|
||||
value: i,
|
||||
}));
|
||||
|
||||
pickerColumns.forEach((col) => {
|
||||
col.items = [...items];
|
||||
});
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,58 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('picker-column: slots'), () => {
|
||||
test('should not have visual regressions with prefix and suffix', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker>
|
||||
<ion-picker-column value="b">
|
||||
<div slot="prefix">Prefix</div>
|
||||
<div slot="suffix">Suffix</div>
|
||||
</ion-picker-column>
|
||||
</ion-picker>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a' },
|
||||
{ text: 'B', value: 'b' },
|
||||
{ text: 'C', value: 'c' }
|
||||
]
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const picker = page.locator('ion-picker');
|
||||
await expect(picker).toHaveScreenshot(screenshot(`picker-prefix-suffix`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions with a long prefix and suffix', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker>
|
||||
<ion-picker-column value="b">
|
||||
<div slot="prefix">Long prefix long prefix long prefix</div>
|
||||
<div slot="suffix">Long suffix long suffix long suffix</div>
|
||||
</ion-picker-column>
|
||||
</ion-picker>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a' },
|
||||
{ text: 'B', value: 'b' },
|
||||
{ text: 'C', value: 'c' }
|
||||
]
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const picker = page.locator('ion-picker');
|
||||
await expect(picker).toHaveScreenshot(screenshot(`picker-long-prefix-suffix`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
@@ -131,7 +131,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
const firstColumn = page.locator('ion-picker-column#first');
|
||||
const secondColumn = page.locator('ion-picker-column#second');
|
||||
|
||||
await secondColumn.focus();
|
||||
await secondColumn.evaluate((el: HTMLIonPickerColumnElement) => el.setFocus());
|
||||
await expect(secondColumn).toBeFocused();
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@@ -32,7 +32,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
|
||||
const column = page.locator('ion-picker-column');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
await column.focus();
|
||||
await column.evaluate((el: HTMLIonPickerColumnElement) => el.setFocus());
|
||||
|
||||
await page.keyboard.press('Digit2');
|
||||
|
||||
@@ -126,7 +126,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
|
||||
const column = page.locator('ion-picker-column');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
await column.focus();
|
||||
await column.evaluate((el: HTMLIonPickerColumnElement) => el.setFocus());
|
||||
|
||||
await page.keyboard.press('Digit0');
|
||||
|
||||
|
||||
@@ -1446,7 +1446,8 @@ export declare interface IonPicker extends Components.IonPicker {
|
||||
|
||||
|
||||
@ProxyCmp({
|
||||
inputs: ['color', 'disabled', 'items', 'mode', 'value']
|
||||
inputs: ['color', 'disabled', 'items', 'mode', 'value'],
|
||||
methods: ['setFocus']
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-picker-column',
|
||||
|
||||
@@ -1441,7 +1441,8 @@ export declare interface IonPicker extends Components.IonPicker {
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineIonPickerColumn,
|
||||
inputs: ['color', 'disabled', 'items', 'mode', 'value']
|
||||
inputs: ['color', 'disabled', 'items', 'mode', 'value'],
|
||||
methods: ['setFocus']
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-picker-column',
|
||||
|
||||