Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui5-calendar): introduce new component. #2424

Merged
merged 31 commits into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4ae812f
feat(ui5-calendar): component is no public and can be used standalone.
unazko Oct 30, 2020
a8cea25
feat(ui5-calendar): component is no public and can be used standalone.
unazko Nov 1, 2020
166375f
Merge branch 'master' of https://github.com/unazko/ui5-webcomponents …
unazko Nov 2, 2020
ce65ff8
Merge branch 'master' of https://github.com/unazko/ui5-webcomponents …
unazko Nov 4, 2020
7fcdf3d
feat(ui5-calendar): component is no public and can be used standalone
unazko Nov 10, 2020
4fb3b30
feat(ui5-calendar): component is no public and can be used standalone.
unazko Nov 10, 2020
e247bc8
Merge branch 'master' of https://github.com/unazko/ui5-webcomponents …
unazko Nov 10, 2020
eb8d8bf
Fixed lint errors
unazko Nov 10, 2020
5f25f27
Commented code is removed.
unazko Nov 11, 2020
12e00f0
Calendar navigation in the Calendar is now compliant with the specifi…
unazko Nov 11, 2020
ed99156
Lint errors fixed.
unazko Nov 11, 2020
001a656
- Calendar test page is improved.
unazko Nov 12, 2020
f8ba38e
Playground sample is added.
unazko Nov 12, 2020
fe9c039
- Default value is now used for the DayPicker and Calendar
unazko Nov 16, 2020
10fd067
Merge branch 'master' of https://github.com/unazko/ui5-webcomponents …
unazko Nov 16, 2020
271c33b
An issue with DateRangePicker is now fixed.
unazko Nov 16, 2020
d145da7
The DateRangePicker selected range is applied again
unazko Nov 16, 2020
7373c9a
Merge branch 'master' of https://github.com/unazko/ui5-webcomponents …
unazko Nov 19, 2020
bf9c7ff
Documenation recommendations are applied.
unazko Nov 19, 2020
9f736df
Merge branch 'master' of https://github.com/unazko/ui5-webcomponents …
unazko Nov 20, 2020
86a5e81
- Getters are created for the picker DOM elements.
unazko Nov 20, 2020
d20e693
Merge branch 'master' of https://github.com/unazko/ui5-webcomponents …
unazko Nov 24, 2020
0801850
Empty new line is removed from the "CalendarSelection" file.
unazko Nov 25, 2020
4bba3a0
Lint erros fixed.
unazko Nov 25, 2020
b7d4848
Lint erros fixed.
unazko Nov 25, 2020
591d94f
- Separate methods are created for the picker componets,
unazko Nov 25, 2020
9891406
feat(ui5-calendar): stand alone usage
unazko Nov 25, 2020
0870009
feat(ui5-calendar): component can be used standalone
unazko Nov 26, 2020
82eaace
feat(ui5-calendar): component can be used stand alone
unazko Nov 26, 2020
a687c2b
- ui5-calendar "selected-dates-change" event detail description
unazko Nov 29, 2020
042b3a8
- empty tab on the end of a line is deleted.
unazko Nov 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/base/src/types/CalendarSelection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import DataType from "./DataType.js";

const CalendarSelections = {
Single: "Single",
Multiple: "Multiple",
Range: "Range",
};

class CalendarSelection extends DataType {
static isValid(value) {
return !!CalendarSelections[value];
}
}

CalendarSelection.generataTypeAcessors(CalendarSelections);

unazko marked this conversation as resolved.
Show resolved Hide resolved
export default CalendarSelection;
4 changes: 3 additions & 1 deletion packages/main/src/Calendar.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<div
class="{{classes.main}}"
style="{{styles.main}} "
@keydown={{_onkeydown}}
@keydown={{_onkeydown}}
@focusout={{_onfocusout}}
>

<ui5-calendar-header
Expand All @@ -26,6 +27,7 @@
.selectedDates="{{_oMonth.selectedDates}}"
._hidden="{{_oMonth._hidden}}"
.primaryCalendarType="{{_oMonth.primaryCalendarType}}"
.selection="{{_oMonth.selection}}"
.minDate="{{_oMonth.minDate}}"
.maxDate="{{_oMonth.maxDate}}"
timestamp="{{_oMonth.timestamp}}"
Expand Down
213 changes: 168 additions & 45 deletions packages/main/src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js";
import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js";
import CalendarDate from "@ui5/webcomponents-localization/dist/dates/CalendarDate.js";
import CalendarType from "@ui5/webcomponents-base/dist/types/CalendarType.js";
import CalendarSelection from "@ui5/webcomponents-base/dist/types/CalendarSelection.js";
import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
import { isF4, isF4Shift } from "@ui5/webcomponents-base/dist/Keys.js";
import {
isF4,
isF4Shift,
isTabNext,
isTabPrevious,
} from "@ui5/webcomponents-base/dist/Keys.js";
import CalendarHeader from "./CalendarHeader.js";
import DayPicker from "./DayPicker.js";
import MonthPicker from "./MonthPicker.js";
Expand All @@ -32,7 +38,7 @@ const metadata = {
/**
* Defines the UNIX timestamp - seconds since 00:00:00 UTC on Jan 1, 1970.
* @type {Integer}
* @public
* @private
unazko marked this conversation as resolved.
Show resolved Hide resolved
*/
timestamp: {
type: Integer,
Expand All @@ -49,6 +55,22 @@ const metadata = {
type: CalendarType,
},

/**
* Defines the type of selection used in the calendar component.
* The property takes as value an object of type <code>CalendarSelection</code>.
* Accepted property values are:<br>
* <ul>
* <li><code>CalendarSelection.Single</code> - enables a single date selection.(default value)</li>
* <li><code>CalendarSelection.Range</code> - enables selection of a date range.</li>
* <li><code>CalendarSelection.Multiple</code> - enables selection of multiple dates.</li>
* </ul>
* @type {CalendarSelection}
* @public
*/
selection: {
type: CalendarSelection,
},

/**
* Defines the selected dates as UTC timestamps.
* @type {Array}
Expand All @@ -64,7 +86,6 @@ const metadata = {
*
* @type {string}
* @defaultvalue ""
* @since 1.0.0-rc.6
* @public
*/
minDate: {
Expand All @@ -76,7 +97,6 @@ const metadata = {
*
* @type {string}
* @defaultvalue ""
* @since 1.0.0-rc.6
* @public
*/
maxDate: {
Expand All @@ -93,7 +113,6 @@ const metadata = {
* @type {boolean}
* @defaultvalue false
* @public
* @since 1.0.0-rc.8
*/
hideWeekNumbers: {
type: Boolean,
Expand Down Expand Up @@ -143,52 +162,69 @@ const metadata = {
/**
* @class
*
* <h3 class="comment-api-title">Overview</h3>
unazko marked this conversation as resolved.
Show resolved Hide resolved
*
* The <code>ui5-calendar</code> can be used standale to display the years, months, weeks and days
unazko marked this conversation as resolved.
Show resolved Hide resolved
* but the main purpose of the <code>ui5-calendar</code> is to be used within a <code>ui5-date-picker</code>
unazko marked this conversation as resolved.
Show resolved Hide resolved
* <br><br>
*
* <h3>Usage</h3>
*
* The user can navigate to a particular date by:
* <br>
* <ul>
* <li>Pressing over a month inside the <code>ui5-monthpicker</code> component</li>
unazko marked this conversation as resolved.
Show resolved Hide resolved
* <li>Pressing over an year inside the <code>ui5-yearpicker</code> component</li>
* </ul>
* <br>
* The user can comfirm a date selection by pressing over a date inside the <code>ui5-daypicker</code> component.
* <br><br>
*
* <h3>Keyboard Handling</h3>
* The <code>ui5-calendar</code> provides advanced keyboard handling.
* If the <code>ui5-calendar</code> is focused the user can
* choose a picker by using the following shortcuts: <br>
* <ul>
* <li>[F4] - Shows month picker</li>
* <li>[SHIFT] + [F4] - Shows year picker</li>
* <br>
* When a picker is showed and focused the user can use the following keyboard
* shortcuts in order to perform a navigation:
* <br>
* - Day picker: <br>
* <ul>
* <li>[PAGEUP] - Navigate to the previous month</li>
* <li>[PAGEDOWN] - Navigate to the next month</li>
* <li>[SHIFT] + [PAGEUP] - Navigate to the previous year</li>
* <li>[SHIFT] + [PAGEDOWN] - Navigate to the next year</li>
* <li>[CTRL] + [SHIFT] + [PAGEUP] - Navigate ten years backwards</li>
* <li>[CTRL] + [SHIFT] + [PAGEDOWN] - Navigate ten years forwards</li>
* </ul>
* <br>
* - Month picker: <br>
* <ul>
* <li>[PAGEUP] - Navigate to the previous month</li>
* <li>[PAGEDOWN] - Navigate to the next month</li>
* </ul>
* <br>
* - Year picker: <br>
* <ul>
* <li>[PAGEUP] - Navigate to the previous year range</li>
* <li>[PAGEDOWN] - Navigate the next year range</li>
* </ul>
*/

/**
* @class
* The <code>ui5-calendar</code> provides advanced keyboard handling.
* If the <code>ui5-calendar</code> is focused the user can
* choose a picker by using the following shortcuts: <br>
* <ul>
* <li>[F4] - Shows month picker</li>
* <li>[SHIFT] + [F4] - Shows year picker</li>
* <br>
* When a picker is showed and focused the user can use the following keyboard
* shortcuts in order to perform a navigation:
* <br>
* - Day picker: <br>
* <ul>
* <li>[PAGEUP] - Navigate to the previous month</li>
* <li>[PAGEDOWN] - Navigate to the next month</li>
* <li>[SHIFT] + [PAGEUP] - Navigate to the previous year</li>
* <li>[SHIFT] + [PAGEDOWN] - Navigate to the next year</li>
* <li>[CTRL] + [SHIFT] + [PAGEUP] - Navigate ten years backwards</li>
* <li>[CTRL] + [SHIFT] + [PAGEDOWN] - Navigate ten years forwards</li>
* </ul>
* <br>
* - Month picker: <br>
* <ul>
* <li>[PAGEUP] - Navigate to the previous month</li>
* <li>[PAGEDOWN] - Navigate to the next month</li>
* </ul>
* <br>
* - Year picker: <br>
* <ul>
* <li>[PAGEUP] - Navigate to the previous year range</li>
* <li>[PAGEDOWN] - Navigate the next year range</li>
* </ul>
* <br>
*
* <h3>ES6 Module Import</h3>
*
* The <code>ui5-calendar</code> can be used standale to display the years, months, weeks and days,
* but the main purpose of the <code>ui5-calendar</code> is to be used within a <code>ui5-date-picker</code>.
* <code>import "@ui5/webcomponents/dist/Calendar";</code>
*
* @constructor
* @author SAP SE
* @alias sap.ui.webcomponents.main.Calendar
* @extends sap.ui.webcomponents.base.UI5Element
* @tagname ui5-calendar
* @public
* @since 1.0.0-rc.10
unazko marked this conversation as resolved.
Show resolved Hide resolved
*/
class Calendar extends UI5Element {
static get metadata() {
Expand All @@ -209,6 +245,8 @@ class Calendar extends UI5Element {

constructor() {
super();
this.selection = CalendarSelection.Single;

this._header = {};
this._header.onPressPrevious = this._handlePrevious.bind(this);
this._header.onPressNext = this._handleNext.bind(this);
Expand All @@ -219,6 +257,7 @@ class Calendar extends UI5Element {
this._oMonth.onSelectedDatesChange = this._handleSelectedDatesChange.bind(this);
this._oMonth.onNavigate = this._handleMonthNavigate.bind(this);


this._monthPicker = {};
this._monthPicker._hidden = true;
this._monthPicker.onSelectedMonthChange = this._handleSelectedMonthChange.bind(this);
Expand Down Expand Up @@ -247,8 +286,9 @@ class Calendar extends UI5Element {

this._oMonth.formatPattern = this._formatPattern;
this._oMonth.timestamp = this._timestamp;
this._oMonth.selectedDates = [...this._selectedDates];
this._oMonth.selectedDates = [...this.selectedDates];
this._oMonth.primaryCalendarType = this._primaryCalendarType;
this._oMonth.selection = this.selection;
this._oMonth.minDate = this.minDate;
this._oMonth.maxDate = this.maxDate;
this._header.monthText = localeData.getMonths("wide", this._primaryCalendarType)[this._month];
Expand All @@ -270,6 +310,18 @@ class Calendar extends UI5Element {
this._refreshNavigationButtonsState();
}

onAfterRendering() {
const header = this.shadowRoot.querySelector("ui5-calendar-header");
header.shadowRoot.querySelector("[data-sap-show-picker='Month']").setAttribute("tabindex", "-1");
header.shadowRoot.querySelector("[data-sap-show-picker='Year']").setAttribute("tabindex", "-1");

const dayPicker = this.shadowRoot.querySelector("ui5-daypicker");
const currentTimestamp = new CalendarDate(this._calendarDate, this._primaryCalendarType).valueOf() / 1000;
const newItemIndex = dayPicker._itemNav._getItems().findIndex(day => parseInt(day.timestamp) === currentTimestamp);
dayPicker._itemNav.currentIndex = newItemIndex;
dayPicker._itemNav.update();
}

_refreshNavigationButtonsState() {
const minDateParsed = this.minDate && this.getFormat().parse(this.minDate);
const maxDateParsed = this.maxDate && this.getFormat().parse(this.maxDate);
Expand Down Expand Up @@ -416,11 +468,83 @@ class Calendar extends UI5Element {
this._hideMonthPicker();
}
}

if (isTabNext(event)) {
const header = this.shadowRoot.querySelector("ui5-calendar-header");
unazko marked this conversation as resolved.
Show resolved Hide resolved
const monthButton = header.shadowRoot.querySelector("[data-sap-show-picker='Month']");
const yearButton = header.shadowRoot.querySelector("[data-sap-show-picker='Year']");
unazko marked this conversation as resolved.
Show resolved Hide resolved
const target = event.target;

if (target.tagName === "UI5-DAYPICKER" || target.tagName === "UI5-MONTHPICKER" || target.tagName === "UI5-YEARPICKER") {
if (monthButton.getAttribute("hidden") === null) {
monthButton.focus();
} else {
yearButton.focus();
}
event.preventDefault();
} else if (event.target.tagName === "UI5-CALENDAR-HEADER" && event.path[0].getAttribute("data-sap-show-picker") === "Month") {
yearButton.focus();
event.preventDefault();
} else {
this._setPickerCurrentTabindex(-1);
}
}

if (isTabPrevious(event)) {
const header = this.shadowRoot.querySelector("ui5-calendar-header");
if (event.target.tagName === "UI5-CALENDAR-HEADER" && event.path[0].getAttribute("data-sap-show-picker") === "Month") {
this._moveFocusToPickerContent();
event.preventDefault();
} else if (event.target.tagName === "UI5-CALENDAR-HEADER" && event.path[0].getAttribute("data-sap-show-picker") === "Year") {
const monthButton = header.shadowRoot.querySelector("[data-sap-show-picker='Month']");
if (monthButton.getAttribute("hidden") === null) {
monthButton.focus();
} else {
this._moveFocusToPickerContent();
}
event.preventDefault();
}
}
}

_moveFocusToPickerContent() {
if (!this._oMonth._hidden) {
this.shadowRoot.querySelector("ui5-daypicker")._itemNav.focusCurrent();
unazko marked this conversation as resolved.
Show resolved Hide resolved
} else if (!this._monthPicker._hidden) {
this.shadowRoot.querySelector("ui5-monthpicker")._itemNav.focusCurrent();
} else {
this.shadowRoot.querySelector("ui5-yearpicker")._itemNav.focusCurrent();
}
}

_onfocusout(event) {
const header = this.shadowRoot.querySelector("ui5-calendar-header");
header.shadowRoot.querySelector("[data-sap-show-picker='Month']").setAttribute("tabindex", "-1");
header.shadowRoot.querySelector("[data-sap-show-picker='Year']").setAttribute("tabindex", "-1");
this._setPickerCurrentTabindex(0);
}

_setPickerCurrentTabindex(index) {
const dayPicker = this.shadowRoot.querySelector("ui5-daypicker");
const monthPicker = this.shadowRoot.querySelector("ui5-monthpicker");
const yearPicker = this.shadowRoot.querySelector("ui5-yearpicker");

if (dayPicker) {
dayPicker._itemNav._getCurrentItem().setAttribute("tabindex", index.toString());
}

if (monthPicker) {
monthPicker._itemNav._getCurrentItem().setAttribute("tabindex", index.toString());
}

if (yearPicker) {
yearPicker._itemNav._getCurrentItem().setAttribute("tabindex", index.toString());
}
}

_handleSelectedDatesChange(event) {
this.timestamp = event.detail.dates[0];
this.selectedDates = [...event.detail.dates];

this.fireEvent("selected-dates-change", { dates: event.detail.dates });
}

Expand Down Expand Up @@ -493,7 +617,6 @@ class Calendar extends UI5Element {

_handleYearButtonPress() {
this._hideMonthPicker();

this[`_${this._yearPicker._hidden ? "show" : "hide"}YearPicker`]();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/main/src/DatePicker.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div
class="ui5-date-picker-root"
style="{{styles.main}}"
@keydown={{_onkeydown}}
@keydown="{{_onkeydown}}"
@focusout="{{_onfocusout}}"
>
<!-- INPUT -->
Expand Down
Loading