mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-10 00:27:41 +08:00
fix(datetime): RTL will no longer infinitely scroll (#24475)
Resolves #24472
This commit is contained in:
@ -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>
|
||||
|
||||
@ -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();
|
||||
});
|
||||
|
||||
32
core/src/utils/rtl/dir.spec.ts
Normal file
32
core/src/utils/rtl/dir.spec.ts
Normal 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
14
core/src/utils/rtl/dir.ts
Normal 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';
|
||||
}
|
||||
1
core/src/utils/rtl/index.ts
Normal file
1
core/src/utils/rtl/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './dir';
|
||||
Reference in New Issue
Block a user