fix(datetime): RTL will no longer infinitely scroll (#24475)

Resolves #24472
This commit is contained in:
Sean Perkins
2022-01-04 16:15:38 -05:00
committed by GitHub
parent 430439191d
commit 8f000089c2
5 changed files with 65 additions and 6 deletions

View File

@ -11,6 +11,7 @@ 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 { isRTL } from '../../utils/rtl';
import { createColorClasses } from '../../utils/theme';
import { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces';
@ -686,7 +687,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(this.el) ? -1 : 1);
let endIO: IntersectionObserver | undefined;
let startIO: IntersectionObserver | undefined;
@ -765,7 +766,7 @@ export class Datetime implements ComponentInterface {
year
});
calendarBodyRef.scrollLeft = workingMonth.clientWidth;
calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
calendarBodyRef.style.removeProperty('overflow');
calendarBodyRef.style.removeProperty('pointer-events');
@ -1000,9 +1001,11 @@ export class Datetime implements ComponentInterface {
const nextMonth = calendarBodyRef.querySelector('.calendar-month:last-of-type');
if (!nextMonth) { return; }
const left = (nextMonth as HTMLElement).offsetWidth * 2;
calendarBodyRef.scrollTo({
top: 0,
left: (nextMonth as HTMLElement).offsetWidth * 2,
left: left * (isRTL(this.el) ? -1 : 1),
behavior: 'smooth'
});
}
@ -1150,10 +1153,10 @@ export class Datetime implements ComponentInterface {
<div class="calendar-next-prev">
<ion-buttons>
<ion-button onClick={() => this.prevMonth()}>
<ion-icon slot="icon-only" icon={chevronBack} lazy={false}></ion-icon>
<ion-icon slot="icon-only" icon={chevronBack} lazy={false} flipRtl></ion-icon>
</ion-button>
<ion-button onClick={() => this.nextMonth()}>
<ion-icon slot="icon-only" icon={chevronForward} lazy={false}></ion-icon>
<ion-icon slot="icon-only" icon={chevronForward} lazy={false} flipRtl></ion-icon>
</ion-button>
</ion-buttons>
</div>

View File

@ -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();
});

View File

@ -0,0 +1,32 @@
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);
expect(isRTL({ dir: '' })).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);
});
});
});

14
core/src/utils/rtl/dir.ts Normal file
View File

@ -0,0 +1,14 @@
/**
* 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<HTMLElement, 'dir'>) => {
if (hostEl) {
if (hostEl.dir !== '') {
return hostEl.dir.toLowerCase() === 'rtl';
}
}
return document?.dir.toLowerCase() === 'rtl';
}

View File

@ -0,0 +1 @@
export * from './dir';