diff --git a/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts b/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts index 652dee33be..b0bf7b2eae 100644 --- a/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts +++ b/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts @@ -1,6 +1,6 @@ import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor'; -import { html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; +import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbInputDateElement } from '@umbraco-cms/backoffice/components'; import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; @@ -42,13 +42,16 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen @property() value?: string; + @state() + private _inputValue?: string; + public set config(config: UmbPropertyEditorConfigCollection | undefined) { if (!config) return; // Format string prevalue/config const format = config.getValueByAlias('format'); - const hasTime = format?.includes('H') || format?.includes('m'); - const hasSeconds = format?.includes('s'); + const hasTime = (format?.includes('H') || format?.includes('m')) ?? false; + const hasSeconds = format?.includes('s') ?? false; this._inputType = hasTime ? 'datetime-local' : 'date'; // Based on the type of format string change the UUI-input type @@ -70,33 +73,54 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen } #onChange(event: CustomEvent & { target: UmbInputDateElement }) { - this.#formatValue(event.target.value.toString()); + let value = event.target.value.toString(); + + switch (this._inputType) { + case 'time': + value = `0001-01-01 ${value}`; + break; + case 'date': + value = `${value} 00:00:00`; + break; + case 'datetime-local': + value = value.replace('T', ' '); + break; + } + + this.#syncValue(value); } /** * Formats the value depending on the input type. */ #formatValue(value: string) { - // Check that the value is a valid date - const valueToDate = new Date(value); - if (isNaN(valueToDate.getTime())) { - console.warn('[Umbraco.DatePicker] The value is not a valid date.', value); + this._inputValue = undefined; + + if (isNaN(new Date(value).getTime())) { + console.warn(`[UmbDatePicker] Invalid date: ${value}`); return; } - // Replace the potential time demoninator 'T' with a whitespace for backwards compatibility - value = value.replace('T', ' '); - - // If the inputType is 'date', we need to make sure the value doesn't have a time - if (this._inputType === 'date' && value.includes(' ')) { - value = value.split(' ')[0]; + const dateSplit = value.split(' '); + if (dateSplit.length !== 2) { + console.warn(`[UmbDatePicker] Invalid date: ${value}`); + return; } - // If the inputType is 'time', we need to remove the date part of the value - if (this._inputType === 'time' && value.includes(' ')) { - value = value.split(' ')[1]; + switch (this._inputType) { + case 'time': + this._inputValue = dateSplit[1]; + break; + case 'date': + this._inputValue = dateSplit[0]; + break; + default: + this._inputValue = dateSplit.join('T'); + break; } + } + #syncValue(value: string) { const valueHasChanged = this.value !== value; if (valueHasChanged) { this.value = value; @@ -107,7 +131,7 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen override render() { return html` { await expect(element).shadowDom.to.be.accessible(defaultA11yConfig); }); } + + describe('input', () => { + it('should format the value to a datetime-local', async () => { + element.value = '2024-05-03 10:44:00'; + element.config = new UmbPropertyEditorConfigCollection([{ alias: 'format', value: 'YYYY-MM-dd HH:mm:ss' }]); + await element.updateComplete; + expect((element as any)._inputValue).to.equal('2024-05-03T10:44:00'); + }); + + it('should format the value to a date', async () => { + element.value = '2024-05-03 10:44:00'; + element.config = new UmbPropertyEditorConfigCollection([{ alias: 'format', value: 'YYYY-MM-dd' }]); + await element.updateComplete; + expect((element as any)._inputValue).to.equal('2024-05-03'); + }); + + it('should format the value to a time', async () => { + element.value = '2024-05-03 10:44:00'; + element.config = new UmbPropertyEditorConfigCollection([{ alias: 'format', value: 'HH:mm' }]); + await element.updateComplete; + expect((element as any)._inputValue).to.equal('10:44:00'); + }); + + it('should disregard a non-datetime value', async () => { + element.value = '03/05/2024 10:44:00'; + await element.updateComplete; + expect((element as any)._inputValue).to.be.undefined; + }); + }); + + describe('output', () => { + it('should format the value to a datetime-local', async () => { + inputElement.value = '2024-05-03T10:44:00'; + inputElement.dispatchEvent(new CustomEvent('change')); + await element.updateComplete; + expect(element.value).to.equal('2024-05-03 10:44:00'); + }); + + it('should format the value to a date', async () => { + element.config = new UmbPropertyEditorConfigCollection([{ alias: 'format', value: 'YYYY-MM-dd' }]); + await element.updateComplete; + inputElement.value = '2024-05-03'; + inputElement.dispatchEvent(new CustomEvent('change')); + await element.updateComplete; + expect(element.value).to.equal('2024-05-03 00:00:00'); + }); + + it('should format the value to a time', async () => { + element.config = new UmbPropertyEditorConfigCollection([{ alias: 'format', value: 'HH:mm' }]); + await element.updateComplete; + inputElement.value = '10:44:00'; + inputElement.dispatchEvent(new CustomEvent('change')); + await element.updateComplete; + expect(element.value).to.equal('0001-01-01 10:44:00'); + }); + }); });