diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/manifests.ts index 51139cd0ea..0a4b96eb04 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/manifests.ts @@ -15,15 +15,25 @@ export const manifest: ManifestPropertyEditorUI = { { alias: 'format', label: 'Date format', - description: 'If left empty then the format is YYYY-MM-DD. (see momentjs.com for supported formats)', + description: 'If left empty then the format is YYYY-MM-DD', propertyEditorUI: 'Umb.PropertyEditorUI.TextBox', }, + { + alias: 'offsetTime', + label: 'Offset time', + description: 'When enabled the time displayed will be offset with the servers timezone, this is useful for scenarios like scheduled publishing when an editor is in a different timezone than the hosted server', + propertyEditorUI: 'Umb.PropertyEditorUI.Toggle', + }, ], defaultData: [ { alias: 'format', value: 'YYYY-MM-DD HH:mm:ss', }, + { + alias: 'offsetTime', + value: false + } ], }, }, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts index 3ebaf9d8a0..de79bbf833 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts @@ -1,7 +1,10 @@ import { html } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { InputType } from '@umbraco-ui/uui'; +import { UmbPropertyValueChangeEvent } from '../..'; import { UmbLitElement } from '@umbraco-cms/element'; +import { PropertyEditorConfigDefaultData } from '@umbraco-cms/extensions-registry'; /** * @element umb-property-editor-ui-date-picker @@ -10,14 +13,68 @@ import { UmbLitElement } from '@umbraco-cms/element'; export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement { static styles = [UUITextStyles]; + private _value?: Date; + private _valueString?: string; + @property() - value = ''; + set value(value: string | undefined) { + if (value) { + const d = new Date(value); + this._value = d; + this._valueString = `${d.getFullYear()}-${ + d.getMonth() + 1 + }-${d.getDate()}T${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`; + } else { + this._value = undefined; + this._valueString = undefined; + } + } + + get value() { + return this._valueString; + } + + private _onInput(e: InputEvent) { + const dateField = e.target as HTMLInputElement; + this.value = dateField.value; + this.dispatchEvent(new UmbPropertyValueChangeEvent()); + } + + private _format?: string; + + @state() + private _inputType: InputType = 'datetime-local'; + + private _offsetTime?: boolean; @property({ type: Array, attribute: false }) - public config = []; + public set config(config: Array) { + // Format string prevalue/config + this._format = config.find((x) => x.alias === 'format')?.value; + const pickTime = this._format?.includes('H') || this._format?.includes('m'); + if (pickTime) { + this._inputType = 'datetime-local'; + } else { + this._inputType = 'date'; + } + + // Based on the type of format string change the UUI-input type + const timeFormatPattern = /^h{1,2}:m{1,2}(:s{1,2})?\s?a?$/gim; + if (this._format?.toLowerCase().match(timeFormatPattern)) { + this._inputType = 'time'; + } + + // TODO: Warren - Need to deal with offSetTime prevalue/config + // Currently the date picker in uui-iinput does not change based on this config + this._offsetTime = config.find((x) => x.alias === 'offsetTime')?.value; + } render() { - return html`
umb-property-editor-ui-date-picker
`; + return html` `; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.stories.ts index 783f397430..b3f5beae7e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.stories.ts @@ -8,8 +8,51 @@ export default { title: 'Property Editor UIs/Date Picker', component: 'umb-property-editor-ui-date-picker', id: 'umb-property-editor-ui-date-picker', -} as Meta; + args: { + config: [ + { + alias: 'format', + value: 'YYYY-MM-DD HH:mm:ss' + } + ] + } +} as Meta; -export const AAAOverview: Story = () => - html``; -AAAOverview.storyName = 'Overview'; +const Template: Story = ({config, value}) => html``; + +export const Overview = Template.bind({}); + +export const WithDateValue = Template.bind({}); +WithDateValue.args = { + value: '2021-01-24 15:20' +}; + +export const WithFormat = Template.bind({}); +WithFormat.args = { + config: [ + { + alias: 'format', + value: 'dd/MM/yyyy HH:mm:ss' + } + ] +}; + +export const TimeOnly = Template.bind({}); +TimeOnly.args = { + config: [ + { + alias: 'format', + value: 'HH:mm:ss' + } + ] +}; + +export const DateOnly = Template.bind({}); +DateOnly.args = { + config: [ + { + alias: 'format', + value: 'dd/MM/yyyy' + } + ] +}; \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts index 48583babe9..05c9ab0920 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts @@ -1,21 +1,44 @@ import { expect, fixture, html } from '@open-wc/testing'; +import { UUIInputElement } from '@umbraco-ui/uui'; import { UmbPropertyEditorUIDatePickerElement } from './property-editor-ui-date-picker.element'; import { defaultA11yConfig } from '@umbraco-cms/test-utils'; describe('UmbPropertyEditorUIDatePickerElement', () => { let element: UmbPropertyEditorUIDatePickerElement; + let inputElement: UUIInputElement; beforeEach(async () => { - element = await fixture( - html` ` - ); + element = await fixture( + html` ` + ); + inputElement = element.shadowRoot?.querySelector('uui-input') as UUIInputElement; }); it('is defined with its own instance', () => { - expect(element).to.be.instanceOf(UmbPropertyEditorUIDatePickerElement); + expect(element).to.be.instanceOf(UmbPropertyEditorUIDatePickerElement); + }); + + it('should have an input element', () => { + expect(inputElement).to.exist; + }); + + it('should show a datetime-local input by default', () => { + expect(inputElement.type).to.equal('datetime-local'); + }); + + it('should show a type=date field if the format only contains a date', async () => { + element.config = [{alias: 'format', value: 'YYYY-MM-dd'}]; + await element.updateComplete; + expect(inputElement.type).to.equal('date'); + }); + + it('should show a type=time field if the format only contains a time', async () => { + element.config = [{alias: 'format', value: 'HH:mm'}]; + await element.updateComplete; + expect(inputElement.type).to.equal('time'); }); it('passes the a11y audit', async () => { - await expect(element).shadowDom.to.be.accessible(defaultA11yConfig); + await expect(element).shadowDom.to.be.accessible(defaultA11yConfig); }); }); diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts index f1403b64d6..fd0b0b01c0 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts @@ -206,7 +206,54 @@ export const data: Array = [ parentKey: null, propertyEditorAlias: 'Umbraco.DateTime', propertyEditorUiAlias: 'Umb.PropertyEditorUI.DatePicker', - data: [], + data: [ + { + alias: 'format', + value: 'YYYY-MM-DD', + }, + { + alias: 'offsetTime', + value: true, + }, + ], + }, + { + $type: 'data-type', + name: 'Date Picker With Time', + type: 'data-type', + key: 'dt-datePicker-time', + parentKey: null, + propertyEditorAlias: 'Umbraco.DateTime', + propertyEditorUiAlias: 'Umb.PropertyEditorUI.DatePicker', + data: [ + { + alias: 'format', + value: 'YYYY-MM-DD HH:mm:ss', + }, + { + alias: 'offsetTime', + value: true, + }, + ], + }, + { + $type: 'data-type', + name: 'Time', + type: 'data-type', + key: 'dt-time', + parentKey: null, + propertyEditorAlias: 'Umbraco.DateTime', + propertyEditorUiAlias: 'Umb.PropertyEditorUI.DatePicker', + data: [ + { + alias: 'format', + value: 'HH:mm:ss', + }, + { + alias: 'offsetTime', + value: false, + }, + ], }, { $type: 'data-type', diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts index d52e61ab8a..8f5b4bfd10 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts @@ -59,7 +59,19 @@ export const data: Array = [ alias: 'datePicker', culture: null, segment: null, - value: null, + value: '2023-12-24', + }, + { + alias: 'datePickerTime', + culture: null, + segment: null, + value: '2023-12-24 14:52', + }, + { + alias: 'time', + culture: null, + segment: null, + value: '14:52:00', }, { alias: 'email',