Skip to content

Commit

Permalink
fix(sbb-time-input): create get/set for valueAsDate (#2244)
Browse files Browse the repository at this point in the history
Closes #2223

BREAKING CHANGE: `getValueAsDate()` and `setValueAsDate()` methods 
of the `sbb-time-input` have been replaced by getter/setter `valueAsDate`.
  • Loading branch information
DavideMininni-Fincons authored Nov 21, 2024
1 parent f3b192c commit 7d39928
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 49 deletions.
22 changes: 8 additions & 14 deletions src/elements/time-input/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ If the `sbb-time-input` is used within a `sbb-form-field`:
</sbb-form-field>
```

The initial value can be set using the `value` property (string) of the `input`or the `setValueAsDate()` method of the `sbb-time-input`.
The initial value can be set using the `value` property (string) of the `input`or the `valueAsDate` setter of the `sbb-time-input`.

When the input changes, if it is valid, the component updates the `value` of the `input`.

To get the value as a `Date` object, the `getValueAsDate()` method of the `sbb-time-input` can be called.
To get the value as a `Date` object, the `valueAsDate` property can be used.
The date is constructed like following: the start date is set to 01.01.1970, 00:00:00 UTC, then the typed hours and minuted are added,
e.g.: with a value of `12:34`, the `getValueAsDate()` will be 01.01.1970, 12:34:00 UTC.
e.g.: with a value of `12:34`, the `valueAsDate` will be 01.01.1970, 12:34:00 UTC.

If the value is invalid because not real (e.g. 12:61 or 25:30), the component does not format the `value`,
and will return `null` if `getValueAsDate()` was called.
and `valueAsDate` will return `null`.

## Format example

Expand Down Expand Up @@ -62,16 +62,10 @@ Whenever the validation state changes (e.g., a valid value becomes invalid or vi

## Properties

| Name | Attribute | Privacy | Type | Default | Description |
| ------- | --------- | ------- | ------------------------------- | ------- | ---------------------------------------------------------- |
| `input` | `input` | public | `string \| HTMLElement \| null` | `null` | Reference of the native input connected to the datepicker. |

## Methods

| Name | Privacy | Description | Parameters | Return | Inherited From |
| ---------------- | ------- | ----------------------------------------------------- | ------------------- | -------------- | -------------- |
| `getValueAsDate` | public | Gets the input value with the correct date format. | | `Date \| null` | |
| `setValueAsDate` | public | Set the input value to the correctly formatted value. | `date: SbbDateLike` | `void` | |
| Name | Attribute | Privacy | Type | Default | Description |
| ------------- | --------- | ------- | ------------------------------- | ------- | ---------------------------------------------------------- |
| `input` | `input` | public | `string \| HTMLElement \| null` | `null` | Reference of the native input connected to the datepicker. |
| `valueAsDate` | - | public | `Date \| null` | | Formats the current input's value as date. |

## Events

Expand Down
14 changes: 7 additions & 7 deletions src/elements/time-input/time-input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,25 +198,25 @@ describe(`sbb-time-input`, () => {
const blurSpy = new EventSpy('blur', input);
const date = new Date('2023-01-01T15:00:00');

element.setValueAsDate(date);
element.valueAsDate = date;
await waitForLitRender(element);

expect(input.value).to.be.equal('15:00');
expect(blurSpy.count).to.be.equal(1);

const dateCalculated = element.getValueAsDate()!.getTime();
const dateCalculated = element.valueAsDate.getTime();
expect(new Date(dateCalculated).getHours()).to.be.equal(date.getHours());
expect(new Date(dateCalculated).getMinutes()).to.be.equal(date.getMinutes());
});

it('should set and get value as a date (string)', async () => {
const date = new Date('2023-01-01T15:00:00');

element.setValueAsDate(date.toISOString());
element.valueAsDate = date.toISOString();
await waitForLitRender(element);
expect(input.value).to.be.equal('15:00');

const dateCalculated = element.getValueAsDate()!.getTime();
const dateCalculated = element.valueAsDate!.getTime();
expect(new Date(dateCalculated).getHours()).to.be.equal(date.getHours());
expect(new Date(dateCalculated).getMinutes()).to.be.equal(date.getMinutes());
});
Expand All @@ -231,7 +231,7 @@ describe(`sbb-time-input`, () => {
element = root.querySelector<SbbTimeInputElement>('sbb-time-input')!;
input = root.querySelector<HTMLInputElement>('input')!;

element.setValueAsDate('2023-01-01T15:00:00');
element.valueAsDate = '2023-01-01T15:00:00';
await waitForLitRender(element);
expect(input.value).to.be.equal('15:00');
});
Expand All @@ -246,7 +246,7 @@ describe(`sbb-time-input`, () => {
element = root.querySelector<SbbTimeInputElement>('sbb-time-input')!;
input = root.querySelector<HTMLInputElement>('input')!;
element.input = input;
element.setValueAsDate('2023-01-01T15:00:00');
element.valueAsDate = '2023-01-01T15:00:00';
await waitForLitRender(element);

expect(input.value).to.be.equal('15:00');
Expand All @@ -263,7 +263,7 @@ describe(`sbb-time-input`, () => {
input = root.querySelector<HTMLInputElement>('input')!;

element.input = 'input-2';
element.setValueAsDate('2023-01-01T15:00:00');
element.valueAsDate = '2023-01-01T15:00:00';
await waitForLitRender(element);

expect(input.value).to.be.equal('15:00');
Expand Down
10 changes: 5 additions & 5 deletions src/elements/time-input/time-input.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ const updateFormError = (event: CustomEvent): void => {
}
};

const changeEventHandler = async (event: CustomEvent): Promise<void> => {
const changeEventHandler = (event: CustomEvent): void => {
const target = event.target as SbbTimeInputElement;
const exampleParent = target.closest<HTMLDivElement>('div#example-parent');
const div = document.createElement('div');
div.innerText = `value is: ${
(exampleParent?.querySelector('#input-id') as HTMLInputElement).value
}; valueAsDate is: ${await target.getValueAsDate()}.`;
}; valueAsDate is: ${target.valueAsDate}.`;
exampleParent?.querySelector('#container-value')!.append(div);
};

const setValueAsDate = async (event: Event): Promise<void> => {
const target = event.target as HTMLElement;
const exampleParent = target.closest<HTMLDivElement>('div#example-parent');
const exampleParent = target.closest<HTMLDivElement>('div#example-parent')!;

const timeInput = exampleParent?.querySelector<SbbTimeInputElement>('sbb-time-input');
await timeInput?.setValueAsDate(new Date());
const timeInput = exampleParent.querySelector<SbbTimeInputElement>('sbb-time-input')!;
timeInput.valueAsDate = new Date();

const input = exampleParent?.querySelector<HTMLInputElement>('#input-id');
input?.dispatchEvent(new Event('change')); // Trigger change to update invalid state
Expand Down
44 changes: 21 additions & 23 deletions src/elements/time-input/time-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,27 @@ class SbbTimeInputElement extends LitElement {

@state() private accessor _inputElement: HTMLInputElement | null = null;

/** Formats the current input's value as date. */
@property({ attribute: false })
public set valueAsDate(date: SbbDateLike | null) {
if (!date || !this._inputElement) {
return;
}
const dateObj = date instanceof Date ? date : new Date(date);

this._inputElement.value = this._formatValue({
hours: dateObj.getHours(),
minutes: dateObj.getMinutes(),
});

// Emit blur event when value is changed programmatically to notify
// frameworks that rely on that event to update form status.
this._inputElement.dispatchEvent(new FocusEvent('blur', { composed: true }));
}
public get valueAsDate(): Date | null {
return this._formatValueAsDate(this._parseInput(this._inputElement?.value)) ?? null;
}

/**
* @deprecated only used for React. Will probably be removed once React 19 is available.
*/
Expand Down Expand Up @@ -84,29 +105,6 @@ class SbbTimeInputElement extends LitElement {
this._abortController?.abort();
}

/** Gets the input value with the correct date format. */
// TODO: refactor this to be a get/set
public getValueAsDate(): Date | null {
return this._formatValueAsDate(this._parseInput(this._inputElement?.value));
}

/** Set the input value to the correctly formatted value. */
public setValueAsDate(date: SbbDateLike): void {
if (!date || !this._inputElement) {
return;
}
const dateObj = date instanceof Date ? date : new Date(date);

this._inputElement.value = this._formatValue({
hours: dateObj.getHours(),
minutes: dateObj.getMinutes(),
});

// Emit blur event when value is changed programmatically to notify
// frameworks that rely on that event to update form status.
this._inputElement.dispatchEvent(new FocusEvent('blur', { composed: true }));
}

private _findInputElement(): void {
const oldInput = this._inputElement;
this._inputElement = findInput(this, this.input);
Expand Down

0 comments on commit 7d39928

Please sign in to comment.