Skip to content

Commit

Permalink
fix(time-picker, date-picker, date-range-picker): update formatted va…
Browse files Browse the repository at this point in the history
…lue when format changes (VIV-2209) (#2005)

* Update formatted value when clock changes

* Update formatted date when locale changes

* Fix linting issues
  • Loading branch information
RichardHelm authored Nov 15, 2024
1 parent 396a4b7 commit ed94617
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 10 deletions.
28 changes: 28 additions & 0 deletions libs/components/src/lib/date-picker/date-picker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {
setupDelegatesFocusPolyfill,
} from '@vivid-nx/shared';
import { FoundationElementRegistry } from '@microsoft/fast-foundation';
import enUS from '@vonage/vivid/locales/en-US';
import deDE from '../../locales/de-DE';
import { setLocale } from '../../shared/localization';
import { TextField } from '../text-field/text-field';
import { Button } from '../button/button';
import { DatePicker } from './date-picker';
Expand Down Expand Up @@ -309,6 +312,31 @@ describe('vwc-date-picker', () => {
});
});

describe('localization', () => {
afterEach(() => {
setLocale(enUS);
});

it('should format the date according to the locale', async () => {
setLocale(deDE);

element.value = '2021-01-21';
await elementUpdated(element);

expect(textField.currentValue).toBe('21.01.2021');
});

it('should update the text field when the locale changes', async () => {
element.value = '2021-01-21';
await elementUpdated(element);

setLocale(deDE);
await elementUpdated(element);

expect(textField.currentValue).toBe('21.01.2021');
});
});

describe('a11y', () => {
it('should pass html a11y test', async () => {
element.value = '2012-12-12';
Expand Down
8 changes: 7 additions & 1 deletion libs/components/src/lib/date-picker/date-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ export class DatePicker extends DatePickerBase {
return;
}

this._adjustSelectedMonthToEnsureVisibilityOf(this.value);
}
this._updatePresentationValue();
}

protected override _updatePresentationValue() {
if (this.value) {
this._presentationValue = formatPresentationDate(
this.value,
this.locale.datePicker
);
this._adjustSelectedMonthToEnsureVisibilityOf(this.value);
} else {
this._presentationValue = '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
setupDelegatesFocusPolyfill,
} from '@vivid-nx/shared';
import { FoundationElementRegistry } from '@microsoft/fast-foundation';
import { setLocale } from '../../shared/localization';
import deDE from '../../locales/de-DE';
import enUS from '../../locales/en-US';
import { TextField } from '../text-field/text-field';
import { Popup } from '../popup/popup';
import { Button } from '../button/button';
Expand Down Expand Up @@ -610,6 +613,33 @@ describe('vwc-date-range-picker', () => {
);
});

describe('localization', () => {
afterEach(() => {
setLocale(enUS);
});

it('should format the date according to the locale', async () => {
setLocale(deDE);

element.start = '2021-01-21';
element.end = '2021-01-22';
await elementUpdated(element);

expect(textField.value).toBe('21.01.2021 – 22.01.2021');
});

it('should update the text field when the locale changes', async () => {
element.start = '2021-01-21';
element.end = '2021-01-22';
await elementUpdated(element);

setLocale(deDE);
await elementUpdated(element);

expect(textField.value).toBe('21.01.2021 – 22.01.2021');
});
});

describe('a11y', () => {
it('should pass html a11y test', async () => {
element.start = '2012-12-12';
Expand Down
27 changes: 19 additions & 8 deletions libs/components/src/lib/date-range-picker/date-range-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,20 +184,14 @@ export class DateRangePicker extends DatePickerBase {
return;
}

this._presentationValue = formatPresentationDateRange(
{
start: this.start,
end: this.end,
},
this.locale.datePicker
);
// Set a dummy value for required validation
this.value = formatRange(this.start, this.end);
} else {
this.value = '';
this._presentationValue = '';
}

this._updatePresentationValue();

const dateToEnsureVisibilityOf = this.start || this.end;
if (dateToEnsureVisibilityOf) {
this._adjustSelectedMonthToEnsureVisibilityOf(dateToEnsureVisibilityOf);
Expand All @@ -206,6 +200,23 @@ export class DateRangePicker extends DatePickerBase {
this.#updateFormValue();
}

/**
* @internal
*/
protected override _updatePresentationValue() {
if (this.start && this.end) {
this._presentationValue = formatPresentationDateRange(
{
start: this.start,
end: this.end,
},
this.locale.datePicker
);
} else {
this._presentationValue = '';
}
}

/**
* @internal
*/
Expand Down
23 changes: 22 additions & 1 deletion libs/components/src/lib/time-picker/time-picker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
setupDelegatesFocusPolyfill,
} from '@vivid-nx/shared';
import { FoundationElementRegistry } from '@microsoft/fast-foundation';
import { setLocale } from '@vonage/vivid';
import { setLocale } from '../../shared/localization';
import { Popup } from '../popup/popup.ts';
import { Button } from '../button/button.ts';
import { TextField } from '../text-field/text-field.ts';
Expand Down Expand Up @@ -349,6 +349,27 @@ describe('vwc-time-picker', () => {
]);
});
});

it('should update the text field when the clock is changed', async () => {
element.clock = '12h';
element.value = '13:45:00';
await elementUpdated(element);

element.clock = '24h';
await elementUpdated(element);

expect(textField.currentValue).toBe('13:45');
});

it('should update the text field when the locale is changed', async () => {
element.value = '13:45:00';
await elementUpdated(element);

setLocale(enGB);
await elementUpdated(element);

expect(textField.currentValue).toBe('13:45');
});
});

describe('min', () => {
Expand Down
28 changes: 28 additions & 0 deletions libs/components/src/lib/time-picker/time-picker.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import {
attr,
type BindingObserver,
defaultExecutionContext,
DOM,
nullableNumberConverter,
Observable,
observable,
type ValueConverter,
volatile,
} from '@microsoft/fast-element';
import {
type ErrorText,
Expand Down Expand Up @@ -175,12 +179,28 @@ export class TimePicker extends FormAssociatedTimePicker {
/**
* @internal
*/
@volatile
get _use12hClock() {
return this.clock
? this.clock === '12h'
: this.locale.timePicker.defaultTo12HourClock;
}

// Reformat the presentation value when the clock changes
#clockChangeHandler = {
handleChange: () => {
if (this.value) {
this._presentationValue = formatPresentationTime(
this.value,
this._displaySeconds,
this._use12hClock
);
}
},
};

#clockChangeObserver!: BindingObserver;

#getFocusableEls = () =>
this.shadowRoot!.querySelectorAll(`
.dialog [tabindex="0"],
Expand Down Expand Up @@ -229,6 +249,12 @@ export class TimePicker extends FormAssociatedTimePicker {
document.addEventListener('click', this.#dismissOnClickOutside);
this.addEventListener('focusin', this.#onFocusIn);
this.addEventListener('focusout', this.#onFocusOut);

this.#clockChangeObserver = Observable.binding(
() => this._use12hClock,
this.#clockChangeHandler
);
this.#clockChangeObserver.observe(this, defaultExecutionContext);
}

override disconnectedCallback() {
Expand All @@ -237,6 +263,8 @@ export class TimePicker extends FormAssociatedTimePicker {
document.removeEventListener('click', this.#dismissOnClickOutside);
this.removeEventListener('focusin', this.#onFocusIn);
this.removeEventListener('focusout', this.#onFocusOut);

this.#clockChangeObserver.disconnect();
}

#onFocusIn = () => {
Expand Down
22 changes: 22 additions & 0 deletions libs/components/src/shared/date-picker/date-picker-base.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {
attr,
type BindingObserver,
defaultExecutionContext,
DOM,
Observable,
observable,
type ValueConverter,
volatile,
Expand Down Expand Up @@ -232,6 +235,12 @@ export abstract class DatePickerBase extends FormAssociatedDatePickerBase {
document.addEventListener('click', this.#dismissOnClickOutside);
this.addEventListener('focusin', this.#onFocusIn);
this.addEventListener('focusout', this.#onFocusOut);

this.#localeChangeObserver = Observable.binding(
() => this.locale,
this.#localeChangeHandler
);
this.#localeChangeObserver.observe(this, defaultExecutionContext);
}

override disconnectedCallback() {
Expand All @@ -240,6 +249,8 @@ export abstract class DatePickerBase extends FormAssociatedDatePickerBase {
document.removeEventListener('click', this.#dismissOnClickOutside);
this.removeEventListener('focusin', this.#onFocusIn);
this.removeEventListener('focusout', this.#onFocusOut);

this.#localeChangeObserver.disconnect();
}

#onFocusIn = () => {
Expand Down Expand Up @@ -272,6 +283,15 @@ export abstract class DatePickerBase extends FormAssociatedDatePickerBase {

protected abstract _getCustomValidationError(): string | null;

// Reformat the presentation value when the locale changes
#localeChangeHandler = {
handleChange: () => {
this._updatePresentationValue();
},
};

#localeChangeObserver!: BindingObserver;

// --- Popup ---

/**
Expand Down Expand Up @@ -353,6 +373,8 @@ export abstract class DatePickerBase extends FormAssociatedDatePickerBase {
this.validate();
}

protected abstract _updatePresentationValue(): void;

/**
* @internal
*/
Expand Down

0 comments on commit ed94617

Please sign in to comment.