From d7a6e6e0f93912dd976afa0936b1f613fa647fa0 Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Wed, 22 Dec 2021 14:05:33 -0500 Subject: [PATCH 1/6] fix(datetime): RTL will no longer infinitily scroll Resolves #24472 --- core/src/components/datetime/datetime.tsx | 15 ++++++++++----- core/src/components/datetime/test/basic/e2e.ts | 11 ++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index 4e9d22a500d..b514eeae280 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -675,6 +675,8 @@ export class Datetime implements ComponentInterface { */ const months = calendarBodyRef.querySelectorAll('.calendar-month'); + const isRTL = document.dir === 'rtl'; + const startMonth = months[0] as HTMLElement; const workingMonth = months[1] as HTMLElement; const endMonth = months[2] as HTMLElement; @@ -686,7 +688,7 @@ export class Datetime implements ComponentInterface { * if element is not in viewport. Use scrollLeft instead. */ writeTask(() => { - calendarBodyRef.scrollLeft = startMonth.clientWidth; + calendarBodyRef.scrollLeft = startMonth.clientWidth * (isRTL ? -1 : 1); let endIO: IntersectionObserver | undefined; let startIO: IntersectionObserver | undefined; @@ -765,7 +767,7 @@ export class Datetime implements ComponentInterface { year }); - calendarBodyRef.scrollLeft = workingMonth.clientWidth; + calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL ? -1 : 1); calendarBodyRef.style.removeProperty('overflow'); calendarBodyRef.style.removeProperty('pointer-events'); @@ -1000,9 +1002,12 @@ export class Datetime implements ComponentInterface { const nextMonth = calendarBodyRef.querySelector('.calendar-month:last-of-type'); if (!nextMonth) { return; } + const isRTL = document.dir === 'rtl'; + const left = (nextMonth as HTMLElement).offsetWidth * 2; + calendarBodyRef.scrollTo({ top: 0, - left: (nextMonth as HTMLElement).offsetWidth * 2, + left: left * (isRTL ? -1 : 1), behavior: 'smooth' }); } @@ -1150,10 +1155,10 @@ export class Datetime implements ComponentInterface {
this.prevMonth()}> - + this.nextMonth()}> - +
diff --git a/core/src/components/datetime/test/basic/e2e.ts b/core/src/components/datetime/test/basic/e2e.ts index 89af77f0411..a6ef616cf84 100644 --- a/core/src/components/datetime/test/basic/e2e.ts +++ b/core/src/components/datetime/test/basic/e2e.ts @@ -78,7 +78,6 @@ describe('Footer', () => { }); }); - describe('datetime: selecting a day', () => { it('should update the active day', async () => { @@ -100,4 +99,14 @@ describe('datetime: selecting a day', () => { expect(newActiveDay.innerText).toEqual('13'); }); + +}); + +test('datetime:rtl: basic', async () => { + const page = await newE2EPage({ + url: '/src/components/datetime/test/basic?ionic:_testing=true&rtl=true' + }); + + const compare = await page.compareScreenshot(); + expect(compare).toMatchScreenshot(); }); From d6f3cb51a8d5d56da2e6bb4f2025a0b623e7d31d Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Tue, 4 Jan 2022 14:08:14 -0500 Subject: [PATCH 2/6] fix(): isRTL util function --- core/src/components/datetime/datetime.tsx | 10 +++----- core/src/utils/rtl/dir.spec.ts | 31 +++++++++++++++++++++++ core/src/utils/rtl/dir.ts | 12 +++++++++ core/src/utils/rtl/index.ts | 1 + 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 core/src/utils/rtl/dir.spec.ts create mode 100644 core/src/utils/rtl/dir.ts create mode 100644 core/src/utils/rtl/index.ts diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index b514eeae280..5912d5452f0 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -12,6 +12,7 @@ import { Color, DatetimeChangeEventDetail, DatetimeParts, Mode, StyleEventDetail import { startFocusVisible } from '../../utils/focus-visible'; import { getElementRoot, raf, renderHiddenInput } from '../../utils/helpers'; import { createColorClasses } from '../../utils/theme'; +import { isRTL } from '../../utils/rtl'; import { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces'; import { @@ -675,8 +676,6 @@ export class Datetime implements ComponentInterface { */ const months = calendarBodyRef.querySelectorAll('.calendar-month'); - const isRTL = document.dir === 'rtl'; - const startMonth = months[0] as HTMLElement; const workingMonth = months[1] as HTMLElement; const endMonth = months[2] as HTMLElement; @@ -688,7 +687,7 @@ export class Datetime implements ComponentInterface { * if element is not in viewport. Use scrollLeft instead. */ writeTask(() => { - calendarBodyRef.scrollLeft = startMonth.clientWidth * (isRTL ? -1 : 1); + calendarBodyRef.scrollLeft = startMonth.clientWidth * (isRTL(this.el) ? -1 : 1); let endIO: IntersectionObserver | undefined; let startIO: IntersectionObserver | undefined; @@ -767,7 +766,7 @@ export class Datetime implements ComponentInterface { year }); - calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL ? -1 : 1); + calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL(this.el) ? -1 : 1); calendarBodyRef.style.removeProperty('overflow'); calendarBodyRef.style.removeProperty('pointer-events'); @@ -1002,12 +1001,11 @@ export class Datetime implements ComponentInterface { const nextMonth = calendarBodyRef.querySelector('.calendar-month:last-of-type'); if (!nextMonth) { return; } - const isRTL = document.dir === 'rtl'; const left = (nextMonth as HTMLElement).offsetWidth * 2; calendarBodyRef.scrollTo({ top: 0, - left: left * (isRTL ? -1 : 1), + left: left * (isRTL(this.el) ? -1 : 1), behavior: 'smooth' }); } diff --git a/core/src/utils/rtl/dir.spec.ts b/core/src/utils/rtl/dir.spec.ts new file mode 100644 index 00000000000..8474faad5dd --- /dev/null +++ b/core/src/utils/rtl/dir.spec.ts @@ -0,0 +1,31 @@ +import { isRTL } from './dir'; + +describe('rtl: dir', () => { + + describe('with host element', () => { + + it('should return true', () => { + expect(isRTL({ dir: 'rtl' })).toBe(true); + }); + + it('should return false', () => { + expect(isRTL({ dir: 'ltr' })).toBe(false); + }); + + }); + + describe('without host element', () => { + + it('should return true', () => { + global.document.dir = 'rtl'; + expect(isRTL()).toBe(true); + }); + + it('should return false', () => { + global.document.dir = 'ltr'; + expect(isRTL()).toBe(false); + }); + + }); + +}); diff --git a/core/src/utils/rtl/dir.ts b/core/src/utils/rtl/dir.ts new file mode 100644 index 00000000000..72deecdbcaf --- /dev/null +++ b/core/src/utils/rtl/dir.ts @@ -0,0 +1,12 @@ + +/** + * Returns `true` if the document or host element + * has a `dir` set to `rtl`. The host value will always + * take priority over the root document value. + */ +export const isRTL = (hostEl?: Pick) => { + if (hostEl && hostEl.dir) { + return hostEl.dir.toLowerCase() === 'rtl'; + } + return document?.dir.toLowerCase() === 'rtl'; +} diff --git a/core/src/utils/rtl/index.ts b/core/src/utils/rtl/index.ts new file mode 100644 index 00000000000..0ed899d679a --- /dev/null +++ b/core/src/utils/rtl/index.ts @@ -0,0 +1 @@ +export * from './dir'; From 9e91a95e91b406f913bf77a9eec29831a0df7bab Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Tue, 4 Jan 2022 14:13:11 -0500 Subject: [PATCH 3/6] chore(): lint --- core/src/components/datetime/datetime.tsx | 2 +- core/src/utils/rtl/dir.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index 5912d5452f0..0865b9546c5 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -11,8 +11,8 @@ import { getIonMode } from '../../global/ionic-global'; import { Color, DatetimeChangeEventDetail, DatetimeParts, Mode, StyleEventDetail } from '../../interface'; import { startFocusVisible } from '../../utils/focus-visible'; import { getElementRoot, raf, renderHiddenInput } from '../../utils/helpers'; -import { createColorClasses } from '../../utils/theme'; import { isRTL } from '../../utils/rtl'; +import { createColorClasses } from '../../utils/theme'; import { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces'; import { diff --git a/core/src/utils/rtl/dir.ts b/core/src/utils/rtl/dir.ts index 72deecdbcaf..fe982da6ae2 100644 --- a/core/src/utils/rtl/dir.ts +++ b/core/src/utils/rtl/dir.ts @@ -5,7 +5,7 @@ * take priority over the root document value. */ export const isRTL = (hostEl?: Pick) => { - if (hostEl && hostEl.dir) { + if (typeof hostEl?.dir !== 'undefined') { return hostEl.dir.toLowerCase() === 'rtl'; } return document?.dir.toLowerCase() === 'rtl'; From 1f7710edfae1ecd4fcbdb830c26d064f49d2118a Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Tue, 4 Jan 2022 15:10:47 -0500 Subject: [PATCH 4/6] fix(): isRTL behavior when dir is empty --- core/src/utils/rtl/dir.spec.ts | 1 + core/src/utils/rtl/dir.ts | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/utils/rtl/dir.spec.ts b/core/src/utils/rtl/dir.spec.ts index 8474faad5dd..e0d3dc018aa 100644 --- a/core/src/utils/rtl/dir.spec.ts +++ b/core/src/utils/rtl/dir.spec.ts @@ -10,6 +10,7 @@ describe('rtl: dir', () => { it('should return false', () => { expect(isRTL({ dir: 'ltr' })).toBe(false); + expect(isRTL({ dir: '' })).toBe(false); }); }); diff --git a/core/src/utils/rtl/dir.ts b/core/src/utils/rtl/dir.ts index fe982da6ae2..6dfe8c198e5 100644 --- a/core/src/utils/rtl/dir.ts +++ b/core/src/utils/rtl/dir.ts @@ -5,8 +5,10 @@ * take priority over the root document value. */ export const isRTL = (hostEl?: Pick) => { - if (typeof hostEl?.dir !== 'undefined') { - return hostEl.dir.toLowerCase() === 'rtl'; + if (hostEl) { + if (hostEl.dir !== '') { + return hostEl.dir.toLowerCase() === 'rtl'; + } } return document?.dir.toLowerCase() === 'rtl'; } From 31fe01fe71420fd80c07ca67e60d7d9cca3affaf Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Tue, 4 Jan 2022 16:00:17 -0500 Subject: [PATCH 5/6] fix(): isRTL casing check/test --- core/src/utils/rtl/dir.spec.ts | 3 +++ core/src/utils/rtl/dir.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/utils/rtl/dir.spec.ts b/core/src/utils/rtl/dir.spec.ts index e0d3dc018aa..4dc9111aac7 100644 --- a/core/src/utils/rtl/dir.spec.ts +++ b/core/src/utils/rtl/dir.spec.ts @@ -11,6 +11,9 @@ describe('rtl: dir', () => { it('should return false', () => { expect(isRTL({ dir: 'ltr' })).toBe(false); expect(isRTL({ dir: '' })).toBe(false); + // Validates casing is aligned with spec + expect(isRTL({ dir: 'RTL' })).toBe(false); + expect(isRTL({ dir: 'Rtl' })).toBe(false); }); }); diff --git a/core/src/utils/rtl/dir.ts b/core/src/utils/rtl/dir.ts index 6dfe8c198e5..62fad7273b7 100644 --- a/core/src/utils/rtl/dir.ts +++ b/core/src/utils/rtl/dir.ts @@ -7,8 +7,8 @@ export const isRTL = (hostEl?: Pick) => { if (hostEl) { if (hostEl.dir !== '') { - return hostEl.dir.toLowerCase() === 'rtl'; + return hostEl.dir === 'rtl'; } } - return document?.dir.toLowerCase() === 'rtl'; + return document?.dir === 'rtl'; } From 0e8c13e27192a9705581048d8165719fc8e6f206 Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Tue, 4 Jan 2022 16:00:17 -0500 Subject: [PATCH 6/6] Revert "fix(): isRTL casing check/test" This reverts commit 31fe01fe71420fd80c07ca67e60d7d9cca3affaf. --- core/src/utils/rtl/dir.spec.ts | 3 --- core/src/utils/rtl/dir.ts | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/core/src/utils/rtl/dir.spec.ts b/core/src/utils/rtl/dir.spec.ts index 4dc9111aac7..e0d3dc018aa 100644 --- a/core/src/utils/rtl/dir.spec.ts +++ b/core/src/utils/rtl/dir.spec.ts @@ -11,9 +11,6 @@ describe('rtl: dir', () => { it('should return false', () => { expect(isRTL({ dir: 'ltr' })).toBe(false); expect(isRTL({ dir: '' })).toBe(false); - // Validates casing is aligned with spec - expect(isRTL({ dir: 'RTL' })).toBe(false); - expect(isRTL({ dir: 'Rtl' })).toBe(false); }); }); diff --git a/core/src/utils/rtl/dir.ts b/core/src/utils/rtl/dir.ts index 62fad7273b7..6dfe8c198e5 100644 --- a/core/src/utils/rtl/dir.ts +++ b/core/src/utils/rtl/dir.ts @@ -7,8 +7,8 @@ export const isRTL = (hostEl?: Pick) => { if (hostEl) { if (hostEl.dir !== '') { - return hostEl.dir === 'rtl'; + return hostEl.dir.toLowerCase() === 'rtl'; } } - return document?.dir === 'rtl'; + return document?.dir.toLowerCase() === 'rtl'; }