fix(datetime): improve datetime sizing in modals (#24762)

Resolves #23992
This commit is contained in:
Sean Perkins
2022-02-22 16:05:39 -05:00
committed by GitHub
parent 7f1086740b
commit b0ac7de168
5 changed files with 289 additions and 2 deletions

View File

@ -811,6 +811,12 @@ export class Datetime implements ComponentInterface {
navigator.maxTouchPoints > 1 ?
[0.7, 1] : 1;
// Intersection observers cannot accurately detect the
// intersection with a threshold of 1, when the observed
// element width is a sub-pixel value (i.e. 334.05px).
// Setting a root margin to 1px solves the issue.
const rootMargin = '1px';
/**
* Listen on the first month to
* prepend a new month and on the last
@ -829,15 +835,18 @@ export class Datetime implements ComponentInterface {
* it applies to active gestures which is not
* something WebKit does.
*/
endIO = new IntersectionObserver(ev => ioCallback('end', ev), {
threshold,
root: calendarBodyRef
root: calendarBodyRef,
rootMargin
});
endIO.observe(endMonth);
startIO = new IntersectionObserver(ev => ioCallback('start', ev), {
threshold,
root: calendarBodyRef
root: calendarBodyRef,
rootMargin
});
startIO.observe(startMonth);

View File

@ -0,0 +1,53 @@
import { newE2EPage } from '@stencil/core/testing';
describe('datetime: sub-pixel width', () => {
test('should update the month when next button is clicked', async () => {
const page = await newE2EPage({
url: '/src/components/datetime/test/sub-pixel-width?ionic:_testing=true'
});
const openModalBtn = await page.find('#open-modal');
await openModalBtn.click();
const modal = await page.find('ion-modal');
await modal.waitForVisible();
await page.waitForTimeout(250);
const buttons = await page.findAll('ion-datetime >>> .calendar-next-prev ion-button')
await buttons[1].click();
await page.waitForTimeout(350);
const monthYear = await page.find('ion-datetime >>> .calendar-month-year');
expect(monthYear.textContent.trim()).toBe('March 2022');
});
test('should update the month when prev button is clicked', async () => {
const page = await newE2EPage({
url: '/src/components/datetime/test/sub-pixel-width?ionic:_testing=true'
});
const openModalBtn = await page.find('#open-modal');
await openModalBtn.click();
const modal = await page.find('ion-modal');
await modal.waitForVisible();
await page.waitForTimeout(250);
const buttons = await page.findAll('ion-datetime >>> .calendar-next-prev ion-button')
await buttons[0].click();
await page.waitForTimeout(350);
const monthYear = await page.find('ion-datetime >>> .calendar-month-year');
expect(monthYear.textContent.trim()).toBe('January 2022');
});
});

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Datetime - Sub Pixel Width</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>
ion-datetime {
width: 334.05px;
height: 500px;
}
#background {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<ion-app>
<ion-header translucent="true">
<ion-toolbar>
<ion-title>Datetime - Sub Pixel Width</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<h2>Modal</h2>
<ion-button id="open-modal">Present Modal</ion-button>
<ion-modal trigger="open-modal" id="modal">
<div id="background">
<ion-datetime id="picker" value="2022-02-01"></ion-datetime>
</div>
</ion-modal>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -0,0 +1,136 @@
import { newE2EPage } from '@stencil/core/testing';
/**
* This test emulates zoom behavior in the browser to make sure
* that key functions of the ion-datetime continue to function even
* if the page is zoomed in or out.
*/
describe('datetime: zoom interactivity', () => {
let deviceScaleFactor;
describe('zoom out', () => {
beforeEach(() => {
deviceScaleFactor = 0.75;
});
test('should update the month when next button is clicked', async () => {
const page = await newE2EPage({
url: '/src/components/datetime/test/sub-pixel-width?ionic:_testing=true'
});
page.setViewport({
width: 640,
height: 480,
deviceScaleFactor
});
const openModalBtn = await page.find('#open-modal');
await openModalBtn.click();
const modal = await page.find('ion-modal');
await modal.waitForVisible();
await page.waitForTimeout(250);
const buttons = await page.findAll('ion-datetime >>> .calendar-next-prev ion-button')
await buttons[1].click();
await page.waitForTimeout(350);
const monthYear = await page.find('ion-datetime >>> .calendar-month-year');
expect(monthYear.textContent.trim()).toBe('March 2022');
});
test('should update the month when prev button is clicked', async () => {
const page = await newE2EPage({
url: '/src/components/datetime/test/sub-pixel-width?ionic:_testing=true'
});
const openModalBtn = await page.find('#open-modal');
await openModalBtn.click();
const modal = await page.find('ion-modal');
await modal.waitForVisible();
await page.waitForTimeout(250);
const buttons = await page.findAll('ion-datetime >>> .calendar-next-prev ion-button')
await buttons[0].click();
await page.waitForTimeout(350);
const monthYear = await page.find('ion-datetime >>> .calendar-month-year');
expect(monthYear.textContent.trim()).toBe('January 2022');
});
});
describe('zoom in', () => {
beforeEach(() => {
deviceScaleFactor = 2;
});
test('should update the month when next button is clicked', async () => {
const page = await newE2EPage({
url: '/src/components/datetime/test/sub-pixel-width?ionic:_testing=true'
});
page.setViewport({
width: 640,
height: 480,
deviceScaleFactor
});
const openModalBtn = await page.find('#open-modal');
await openModalBtn.click();
const modal = await page.find('ion-modal');
await modal.waitForVisible();
await page.waitForTimeout(250);
const buttons = await page.findAll('ion-datetime >>> .calendar-next-prev ion-button')
await buttons[1].click();
await page.waitForTimeout(350);
const monthYear = await page.find('ion-datetime >>> .calendar-month-year');
expect(monthYear.textContent.trim()).toBe('March 2022');
});
test('should update the month when prev button is clicked', async () => {
const page = await newE2EPage({
url: '/src/components/datetime/test/sub-pixel-width?ionic:_testing=true'
});
const openModalBtn = await page.find('#open-modal');
await openModalBtn.click();
const modal = await page.find('ion-modal');
await modal.waitForVisible();
await page.waitForTimeout(250);
const buttons = await page.findAll('ion-datetime >>> .calendar-next-prev ion-button')
await buttons[0].click();
await page.waitForTimeout(350);
const monthYear = await page.find('ion-datetime >>> .calendar-month-year');
expect(monthYear.textContent.trim()).toBe('January 2022');
});
});
});

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Datetime - Zoom</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>
#background {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<ion-app>
<ion-header translucent="true">
<ion-toolbar>
<ion-title>Datetime - Zoom</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<h2>Modal</h2>
<ion-button id="open-modal">Present Modal</ion-button>
<ion-modal trigger="open-modal" id="modal">
<div id="background">
<ion-datetime id="picker" value="2022-02-01"></ion-datetime>
</div>
</ion-modal>
</ion-content>
</ion-app>
</body>
</html>