Skip to content

Commit ef27ca1

Browse files
authored
feat(ui5-datetime-picker): introduce new component (#1437)
* feat(ui5-datetime-picker): introduce new component Background The DateTimePicker component alows users to select both date (day, month and year) and time (hours, minutes and seconds). The component opens a popover with calendar and time controls. On smaller screen and on phone device there is a switch to change between the calendar and time controls. Technical points - extends DatePicker - reuses the DatePicker template and WheelSlider component - refactors the DatePicker to make it more extensible and overwrite few methods - extracts time related functions
1 parent b8ae60e commit ef27ca1

17 files changed

+1533
-100
lines changed

packages/main/bundle.esm.js

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import ComboBox from "./dist/ComboBox.js";
3535
import ComboBoxItem from "./dist/ComboBoxItem.js";
3636
import MultiComboBoxItem from "./dist/MultiComboBoxItem.js";
3737
import DatePicker from "./dist/DatePicker.js";
38+
import DateTimePicker from "./dist/DateTimePicker.js";
3839
import DurationPicker from "./dist/DurationPicker.js";
3940
import Dialog from "./dist/Dialog.js";
4041
import FileUploader from "./dist/FileUploader.js";

packages/main/src/DatePicker.hbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
{{#unless readonly}}
2222
<ui5-icon
2323
slot="icon"
24-
name="appointment-2"
24+
name="{{openIconName}}"
2525
tabindex="-1"
2626
accessible-name="{{openIconTitle}}"
2727
show-tooltip
@@ -34,4 +34,4 @@
3434
</ui5-input>
3535

3636
<slot name="formSupport"></slot>
37-
</div>
37+
</div>

packages/main/src/DatePicker.js

+55-20
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,6 @@ class DatePicker extends UI5Element {
303303
allowTargetOverlap: true,
304304
stayOpenOnScroll: true,
305305
afterClose: () => {
306-
const calendar = this.responsivePopover.querySelector(`#${this._id}-calendar`);
307-
308306
this._isPickerOpen = false;
309307

310308
if (isPhone()) {
@@ -315,13 +313,20 @@ class DatePicker extends UI5Element {
315313
this._focusInputAfterClose = false;
316314
}
317315

318-
calendar._hideMonthPicker();
319-
calendar._hideYearPicker();
316+
const calendar = this.responsivePopover.querySelector(`#${this._id}-calendar`);
317+
if (calendar) {
318+
calendar._hideMonthPicker();
319+
calendar._hideYearPicker();
320+
}
320321
},
321322
afterOpen: () => {
322323
const calendar = this.responsivePopover.querySelector(`#${this._id}-calendar`);
323-
const dayPicker = calendar.shadowRoot.querySelector(`#${calendar._id}-daypicker`);
324324

325+
if (!calendar) {
326+
return;
327+
}
328+
329+
const dayPicker = calendar.shadowRoot.querySelector(`#${calendar._id}-daypicker`);
325330
const selectedDay = dayPicker.shadowRoot.querySelector(".ui5-dp-item--selected");
326331
const today = dayPicker.shadowRoot.querySelector(".ui5-dp-item--now");
327332
let focusableDay = selectedDay || today;
@@ -346,7 +351,7 @@ class DatePicker extends UI5Element {
346351
};
347352

348353
this._calendar = {
349-
onSelectedDatesChange: this._handleCalendarSelectedDatesChange.bind(this),
354+
onSelectedDatesChange: this._handleCalendarChange.bind(this),
350355
selectedDates: [],
351356
};
352357

@@ -534,6 +539,18 @@ class DatePicker extends UI5Element {
534539
return this.i18nBundle.getText(INPUT_SUGGESTIONS_TITLE);
535540
}
536541

542+
get phone() {
543+
return isPhone();
544+
}
545+
546+
get showHeader() {
547+
return this.phone;
548+
}
549+
550+
get showFooter() {
551+
return this.phone;
552+
}
553+
537554
getFormat() {
538555
if (this._isPattern) {
539556
this._oDateFormat = DateFormat.getInstance({
@@ -579,6 +596,10 @@ class DatePicker extends UI5Element {
579596
return this.i18nBundle.getText(DATEPICKER_OPEN_ICON_TITLE);
580597
}
581598

599+
get openIconName() {
600+
return "appointment-2";
601+
}
602+
582603
get dateAriaDescription() {
583604
return this.i18nBundle.getText(DATEPICKER_DATE_ACC_TEXT);
584605
}
@@ -596,35 +617,49 @@ class DatePicker extends UI5Element {
596617
return !this.disabled && !this.readonly;
597618
}
598619

599-
_handleCalendarSelectedDatesChange(event) {
620+
_handleCalendarChange(event) {
600621
const iNewValue = event.detail.dates && event.detail.dates[0];
601622

602623
if (this._calendar.selectedDates.indexOf(iNewValue) !== -1) {
603624
this.closePicker();
604-
return;
625+
return false;
605626
}
606627

607-
this.value = this.getFormat().format(
608-
new Date(CalendarDate.fromTimestamp(
609-
iNewValue * 1000,
610-
this._primaryCalendarType
611-
).valueOf()),
612-
true
613-
);
614-
this._calendar.timestamp = iNewValue;
628+
const fireChange = this._handleCalendarSelectedDatesChange(event, iNewValue);
629+
630+
if (fireChange) {
631+
this.fireEvent("change", { value: this.value, valid: true });
632+
// Angular two way data binding
633+
this.fireEvent("value-changed", { value: this.value, valid: true });
634+
}
635+
636+
this.closePicker();
637+
}
638+
639+
_handleCalendarSelectedDatesChange(event, newValue) {
640+
this._updateValueCalendarSelectedDatesChange(newValue);
641+
642+
this._calendar.timestamp = newValue;
615643
this._calendar.selectedDates = event.detail.dates;
616644
this._focusInputAfterClose = true;
617-
this.closePicker();
618645

619646
if (this.isInValidRange(this._getTimeStampFromString(this.value))) {
620647
this.valueState = ValueState.None;
621648
} else {
622649
this.valueState = ValueState.Error;
623650
}
624651

625-
this.fireEvent("change", { value: this.value, valid: true });
626-
// Angular two way data binding
627-
this.fireEvent("value-changed", { value: this.value, valid: true });
652+
return true;
653+
}
654+
655+
_updateValueCalendarSelectedDatesChange(newValue) {
656+
this.value = this.getFormat().format(
657+
new Date(CalendarDate.fromTimestamp(
658+
newValue * 1000,
659+
this._primaryCalendarType
660+
).valueOf()),
661+
true
662+
);
628663
}
629664

630665
/**

packages/main/src/DatePickerPopover.hbs

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<ui5-responsive-popover
22
id="{{_id}}-responsive-popover"
3-
content-only-on-desktop
43
allow-target-overlap="{{_respPopoverConfig.allowTargetOverlap}}"
54
stay-open-on-scroll="{{_respPopoverConfig.stayOpenOnScroll}}"
65
placement-type="Bottom"
@@ -11,6 +10,18 @@
1110
@ui5-afterClose="{{_respPopoverConfig.afterClose}}"
1211
@ui5-afterOpen="{{_respPopoverConfig.afterOpen}}"
1312
>
13+
{{#if showHeader}}
14+
{{> header}}
15+
{{/if}}
16+
17+
{{> content}}
18+
19+
{{#if showFooter}}
20+
{{> footer}}
21+
{{/if}}
22+
</ui5-responsive-popover>
23+
24+
{{#*inline "header"}}
1425
<div slot="header" class="ui5-responsive-popover-header">
1526
<div class="row">
1627
<span>{{_headerTitleText}}</span>
@@ -22,6 +33,9 @@
2233
</ui5-button>
2334
</div>
2435
</div>
36+
{{/inline}}
37+
38+
{{#*inline "content"}}
2539
<ui5-calendar
2640
id="{{_id}}-calendar"
2741
primary-calendar-type="{{_calendar.primaryCalendarType}}"
@@ -32,4 +46,6 @@
3246
.maxDate="{{_calendar.maxDate}}"
3347
@ui5-selectedDatesChange="{{_calendar.onSelectedDatesChange}}"
3448
></ui5-calendar>
35-
</ui5-responsive-popover>
49+
{{/inline}}
50+
51+
{{#*inline "footer"}}{{/inline}}

0 commit comments

Comments
 (0)