diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx
index 2c71c5e2bd..494530f56d 100644
--- a/core/src/components/datetime/datetime.tsx
+++ b/core/src/components/datetime/datetime.tsx
@@ -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);
diff --git a/core/src/components/datetime/test/sub-pixel-width/e2e.ts b/core/src/components/datetime/test/sub-pixel-width/e2e.ts
new file mode 100644
index 0000000000..cab744acbe
--- /dev/null
+++ b/core/src/components/datetime/test/sub-pixel-width/e2e.ts
@@ -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');
+ });
+
+});
diff --git a/core/src/components/datetime/test/sub-pixel-width/index.html b/core/src/components/datetime/test/sub-pixel-width/index.html
new file mode 100644
index 0000000000..f532491e1b
--- /dev/null
+++ b/core/src/components/datetime/test/sub-pixel-width/index.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ Datetime - Sub Pixel Width
+
+
+
+
+
+
+
+
+
+
+
+
+ Datetime - Sub Pixel Width
+
+
+
+ Modal
+ Present Modal
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/components/datetime/test/zoom/e2e.ts b/core/src/components/datetime/test/zoom/e2e.ts
new file mode 100644
index 0000000000..a81b71d18e
--- /dev/null
+++ b/core/src/components/datetime/test/zoom/e2e.ts
@@ -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');
+ });
+
+ });
+
+});
diff --git a/core/src/components/datetime/test/zoom/index.html b/core/src/components/datetime/test/zoom/index.html
new file mode 100644
index 0000000000..b17d394f56
--- /dev/null
+++ b/core/src/components/datetime/test/zoom/index.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+ Datetime - Zoom
+
+
+
+
+
+
+
+
+
+
+
+
+ Datetime - Zoom
+
+
+
+ Modal
+ Present Modal
+
+
+
+
+
+
+
+
+
+