mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 18:54:11 +08:00
fix(datetime): persist minutes column on hour change (#24829)
Resolves #24821
This commit is contained in:
@ -118,6 +118,25 @@ export class PickerColumnInternal implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidRender() {
|
||||
const { activeItem, items, isColumnVisible, value } = this;
|
||||
|
||||
if (isColumnVisible) {
|
||||
if (activeItem) {
|
||||
this.scrollActiveItemIntoView();
|
||||
} else if (items[0]?.value !== value) {
|
||||
/**
|
||||
* If the picker column does not have an active item and the current value
|
||||
* does not match the first item in the picker column, that means
|
||||
* the value is out of bounds. In this case, we assign the value to the
|
||||
* first item to match the scroll position of the column.
|
||||
*
|
||||
*/
|
||||
this.value = items[0].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@Method()
|
||||
async scrollActiveItemIntoView() {
|
||||
@ -129,13 +148,20 @@ export class PickerColumnInternal implements ComponentInterface {
|
||||
}
|
||||
|
||||
private centerPickerItemInView = (target: HTMLElement, smooth = true) => {
|
||||
this.el.scroll({
|
||||
const { el, isColumnVisible } = this;
|
||||
if (isColumnVisible) {
|
||||
// (Vertical offset from parent) - (three empty picker rows) + (half the height of the target to ensure the scroll triggers)
|
||||
top: target.offsetTop - (3 * target.clientHeight) + (target.clientHeight / 2),
|
||||
const top = target.offsetTop - (3 * target.clientHeight) + (target.clientHeight / 2);
|
||||
|
||||
if (el.scrollTop !== top) {
|
||||
el.scroll({
|
||||
top,
|
||||
left: 0,
|
||||
behavior: smooth ? 'smooth' : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When ionInputModeChange is emitted, each column
|
||||
|
56
core/src/components/picker-column-internal/test/basic/e2e.ts
Normal file
56
core/src/components/picker-column-internal/test/basic/e2e.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { E2EPage, newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
|
||||
describe('picker-column-internal', () => {
|
||||
|
||||
let page: E2EPage;
|
||||
|
||||
describe('default', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
page = await newE2EPage({
|
||||
url: '/src/components/picker-column-internal/test/basic?ionic:_testing=true'
|
||||
});
|
||||
});
|
||||
|
||||
it('should render a picker item for each item', async () => {
|
||||
const columns = await page.findAll('ion-picker-column-internal >>> .picker-item:not(.picker-item-empty)');
|
||||
expect(columns.length).toEqual(24);
|
||||
});
|
||||
|
||||
it('should render 6 empty picker items', async () => {
|
||||
const columns = await page.findAll('ion-picker-column-internal >>> .picker-item-empty');
|
||||
expect(columns.length).toEqual(6);
|
||||
});
|
||||
|
||||
it('should not have an active item when value is not set', async () => {
|
||||
const activeColumn = await page.findAll('ion-picker-column-internal >>> .picker-item-active');
|
||||
expect(activeColumn.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should have an active item when value is set', async () => {
|
||||
await page.$eval('ion-picker-column-internal#default', (el: any) => {
|
||||
el.value = '12';
|
||||
});
|
||||
await page.waitForChanges();
|
||||
|
||||
const activeColumn = await page.find('ion-picker-column-internal >>> .picker-item-active');
|
||||
|
||||
expect(activeColumn).not.toBeNull();
|
||||
});
|
||||
|
||||
it('scrolling should change the active item', async () => {
|
||||
await page.$eval('ion-picker-column-internal#default', (el: any) => {
|
||||
el.scrollTop = 801;
|
||||
});
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
const activeColumn = await page.find('ion-picker-column-internal >>> .picker-item-active');
|
||||
|
||||
expect(activeColumn.innerText).toEqual('23');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Picker Column Internal - Basic</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>
|
||||
<style>
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(250px, 1fr));
|
||||
grid-row-gap: 20px;
|
||||
grid-column-gap: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
|
||||
color: #6f7378;
|
||||
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Picker Column Internal - Basic</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Default</h2>
|
||||
<ion-picker-internal>
|
||||
<ion-picker-column-internal id="default"></ion-picker-column-internal>
|
||||
</ion-picker-internal>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
<script>
|
||||
const defaultPickerColumn = document.getElementById('default');
|
||||
|
||||
const items = Array(24).fill().map((_, i) => ({
|
||||
text: `${i}`,
|
||||
value: i
|
||||
}));
|
||||
|
||||
defaultPickerColumn.items = items;
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user