Skip to content

Commit

Permalink
fix(input-time-picker, input-date-picker): internal pickers update wh…
Browse files Browse the repository at this point in the history
…en changing locales (#5887)

**Related Issue:** #5855 

## Summary
The `effectiveLocale` is kept up to date using a MutationObserver, so it
doesn't need to be passed down via attribute.
  • Loading branch information
benelan committed Dec 5, 2022
1 parent 6b6f46a commit 9c2dc42
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { dateFromRange, nextMonth, prevMonth, getOrder } from "../../utils/date"
import { DateLocaleData } from "../date-picker/utils";
import { Scale } from "../interfaces";
import { HeadingLevel, Heading } from "../functional/Heading";
import { BUDDHIST_CALENDAR_YEAR_OFFSET } from "./resources";
import { BUDDHIST_CALENDAR_YEAR_OFFSET, CSS, ICON } from "./resources";
import { isActivationKey } from "../../utils/key";
import { numberStringFormatter } from "../../utils/locale";
import { closestElementCrossShadowBoundary } from "../../utils/dom";
Expand Down Expand Up @@ -100,7 +100,7 @@ export class DatePickerMonthHeader {
}

render(): VNode {
return <div class="header">{this.renderContent()}</div>;
return <div class={CSS.header}>{this.renderContent()}</div>;
}

renderContent(): VNode {
Expand Down Expand Up @@ -132,25 +132,25 @@ export class DatePickerMonthHeader {
<a
aria-disabled={`${this.prevMonthDate.getMonth() === activeMonth}`}
aria-label={this.intlPrevMonth}
class="chevron"
class={CSS.chevron}
href="#"
onClick={this.prevMonthClick}
onKeyDown={this.prevMonthKeydown}
role="button"
tabindex={this.prevMonthDate.getMonth() === activeMonth ? -1 : 0}
>
<calcite-icon flip-rtl icon="chevron-left" scale={iconScale} />
<calcite-icon flip-rtl icon={ICON.chevronLeft} scale={iconScale} />
</a>
<div class={{ text: true, "text--reverse": reverse }}>
<Heading class="month" level={this.headingLevel}>
<div class={{ text: true, [CSS.textReverse]: reverse }}>
<Heading class={CSS.month} level={this.headingLevel}>
{localizedMonth}
</Heading>
<span class="year-wrap">
<span class={CSS.yearWrap}>
<input
aria-label={this.intlYear}
class={{
year: true,
"year--suffix": !!suffix
[CSS.yearSuffix]: !!suffix
}}
inputmode="numeric"
maxlength="4"
Expand All @@ -163,20 +163,20 @@ export class DatePickerMonthHeader {
type="text"
value={localizedYear}
/>
{suffix && <span class="suffix">{suffix}</span>}
{suffix && <span class={CSS.suffix}>{suffix}</span>}
</span>
</div>
<a
aria-disabled={`${this.nextMonthDate.getMonth() === activeMonth}`}
aria-label={this.intlNextMonth}
class="chevron"
class={CSS.chevron}
href="#"
onClick={this.nextMonthClick}
onKeyDown={this.nextMonthKeydown}
role="button"
tabindex={this.nextMonthDate.getMonth() === activeMonth ? -1 : 0}
>
<calcite-icon flip-rtl icon="chevron-right" scale={iconScale} />
<calcite-icon flip-rtl icon={ICON.chevronRight} scale={iconScale} />
</a>
</Fragment>
);
Expand Down
15 changes: 15 additions & 0 deletions src/components/date-picker-month-header/resources.ts
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
export const BUDDHIST_CALENDAR_YEAR_OFFSET = 543;

export const CSS = {
header: "header",
month: "month",
chevron: "chevron",
suffix: "suffix",
yearSuffix: "year--suffix",
yearWrap: "year-wrap",
textReverse: "text--reverse"
};

export const ICON = {
chevronLeft: "chevron-left",
chevronRight: "chevron-right"
};
31 changes: 31 additions & 0 deletions src/components/input-date-picker/input-date-picker.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {
} from "../../tests/commonTests";
import { html } from "../../../support/formatting";
import { CSS } from "./resources";
import { CSS as MONTH_HEADER_CSS } from "../date-picker-month-header/resources";
import { dateFromISO, setEndOfDay } from "../../utils/date";
import englishTranslations from "../date-picker/assets/date-picker/nls/en.json";
import arabicTranslations from "../date-picker/assets/date-picker/nls/ar.json";

const animationDurationInMs = 200;

Expand Down Expand Up @@ -257,6 +260,34 @@ describe("calcite-input-date-picker", () => {
expect(await calendar.isVisible()).toBe(true);
});

it("syncs locale changes to internal date-picker", async () => {
const lang = "en";
const newLang = "ar";
const month = 4;

const page = await newE2EPage();
await page.setContent(
`<calcite-input-date-picker lang=${lang} value="2020-${month}-19"></calcite-input-date-picker>`
);
const inputDatePicker = await page.find("calcite-input-date-picker");

const getLocalizedMonth = async () =>
await page.evaluate(
async (MONTH_HEADER_CSS) =>
document
.querySelector("calcite-input-date-picker")
.shadowRoot.querySelector("calcite-date-picker")
.shadowRoot.querySelector("calcite-date-picker-month-header")
.shadowRoot.querySelector(`.${MONTH_HEADER_CSS.month}`).textContent,
MONTH_HEADER_CSS
);

expect(await getLocalizedMonth()).toEqual(englishTranslations.months.wide[month - 1]);
inputDatePicker.setProperty("lang", newLang);
await page.waitForChanges();
expect(await getLocalizedMonth()).toEqual(arabicTranslations.months.wide[month - 1]);
});

it("allows clicking a date in the calendar popup", async () => {
const page = await newE2EPage();
await page.setContent(`<calcite-input-date-picker value="2023-01-31"></calcite-input-date-picker>`);
Expand Down
16 changes: 6 additions & 10 deletions src/components/input-date-picker/input-date-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,6 @@ export class InputDatePicker
disabled={disabled}
icon="calendar"
label={getLabelText(this)}
lang={effectiveLocale}
number-button-type="none"
numberingSystem={numberingSystem}
onCalciteInputInput={this.calciteInternalInputInputHandler}
Expand Down Expand Up @@ -601,7 +600,6 @@ export class InputDatePicker
intlNextMonth={this.intlNextMonth}
intlPrevMonth={this.intlPrevMonth}
intlYear={this.intlYear}
lang={effectiveLocale}
max={this.max}
maxAsDate={this.maxAsDate}
min={this.min}
Expand Down Expand Up @@ -638,7 +636,6 @@ export class InputDatePicker
}}
disabled={disabled}
icon="calendar"
lang={effectiveLocale}
number-button-type="none"
numberingSystem={numberingSystem}
onCalciteInputInput={this.calciteInternalInputInputHandler}
Expand Down Expand Up @@ -875,7 +872,11 @@ export class InputDatePicker
if (!Build.isBrowser) {
return;
}

numberStringFormatter.numberFormatOptions = {
numberingSystem: this.numberingSystem,
locale: this.effectiveLocale,
useGrouping: false
};
this.localeData = await getLocaleData(this.effectiveLocale);
}

Expand Down Expand Up @@ -1039,17 +1040,12 @@ export class InputDatePicker
);
}

private commonDateSeparators = [".", "-", "/"];

private formatNumerals = (value: string): string =>
value
? value
.split("")
.map((char: string) =>
// convert common separators to the locale's
this.commonDateSeparators.includes(char)
? this.localeData.separator
: numberKeys.includes(char)
numberKeys.includes(char)
? numberStringFormatter.numberFormatter.format(Number(char))
: char
)
Expand Down
32 changes: 32 additions & 0 deletions src/components/input-time-picker/input-time-picker.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,38 @@ describe("calcite-input-time-picker", () => {
expect(inputTimePickerValue).toBe(expectedValue);
});

it("value displays correctly in the time-picker after changing locales", async () => {
const lang = "en";
const newLang = "ar";
const time = "11:59";
const numberingSystem = "latn";

const page = await newE2EPage({
html: `<calcite-input-time-picker lang="${lang}" numbering-system="${numberingSystem}" value="${time}"></calcite-input-time-picker>`
});
const inputTimePicker = await page.find("calcite-input-time-picker");

const getLocalizedTime = async () =>
await page.evaluate(
async () =>
document.querySelector("calcite-input-time-picker").shadowRoot.querySelector("calcite-time-picker").value
);

const langLocalized = localizeTimeString({ value: time, locale: lang, numberingSystem, includeSeconds: false });
expect(await getLocalizedTime()).toBe(langLocalized.substring(0, langLocalized.indexOf(" ")));

inputTimePicker.setProperty("lang", newLang);
await page.waitForChanges();

const newLangLocalized = localizeTimeString({
value: time,
locale: newLang,
numberingSystem,
includeSeconds: false
});
expect(await getLocalizedTime()).toBe(newLangLocalized.substring(0, newLangLocalized.indexOf(" ")));
});

it("appropriately triggers calciteInputTimePickerChange event when the user types a value", async () => {
const page = await newE2EPage();
await page.setContent(`<calcite-input-time-picker step="1"></calcite-input-time-picker>`);
Expand Down
1 change: 0 additions & 1 deletion src/components/input-time-picker/input-time-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,6 @@ export class InputTimePicker
intlSecond={this.intlSecond}
intlSecondDown={this.intlSecondDown}
intlSecondUp={this.intlSecondUp}
lang={this.effectiveLocale}
numberingSystem={this.numberingSystem}
onCalciteInternalTimePickerChange={this.timePickerChangeHandler}
ref={this.setCalciteTimePickerEl}
Expand Down

0 comments on commit 9c2dc42

Please sign in to comment.