Skip to content

Commit

Permalink
fix: improve keyboard support and various bug fixes on navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
motss committed May 27, 2021
1 parent 2276524 commit 3f1445e
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 99 deletions.
5 changes: 1 addition & 4 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,7 @@ export const navigationKeyCodeSet = {
dayPrevious: new Set([keyCodesRecord.ARROW_LEFT, ...navigationKeyCodes.previous]),
} as const;

export const calendarKeyCodeSet = new Set([
...navigationKeyCodeSet.all,
...confirmKeyCodeList,
]);
export const calendarKeyCodeSet = new Set(navigationKeyCodeSet.all);

export const yearGridNavigationKeyCodeSet = new Set([
keyCodesRecord.ARROW_DOWN,
Expand Down
136 changes: 74 additions & 62 deletions src/date-picker/date-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import '../year-grid/app-year-grid.js';
import type { TemplateResult } from 'lit';
import { nothing } from 'lit';
import { html,LitElement } from 'lit';
import { state } from 'lit/decorators.js';
import { queryAsync, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { repeat } from 'lit/directives/repeat.js';
import { toUTCDate } from 'nodemod/dist/calendar/helpers/to-utc-date.js';

import { calendarViews,MAX_DATE } from '../constants.js';
Expand All @@ -32,6 +31,8 @@ import type { DatePickerChangedProperties } from './typings.js';

export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement)) implements DatePickerProperties {
//#region public properties
@queryAsync('.month-dropdown')
public monthDropdown!: Promise<HTMLButtonElement | null>;
//#endregion public properties

//#region private states
Expand Down Expand Up @@ -146,9 +147,7 @@ export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement
}
}

protected firstUpdated(changedProperties: DatePickerChangedProperties): void {
super.firstUpdated(changedProperties);

protected firstUpdated(): void {
const focusableElements: HTMLElement[] = [];

// TODO: focus element
Expand All @@ -165,15 +164,16 @@ export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement
});
}

protected updated(changedProperties: DatePickerChangedProperties): void {
super.updated(changedProperties);
protected async updated(
changedProperties: DatePickerChangedProperties
): Promise<void> {
if (changedProperties.has('startView') && this.startView === 'calendar') {
const monthDropdown = await this.monthDropdown;

// FIXME: focus element based on start view
// if (this.startView === 'calendar') {
// // TODO: Do stuff for calendar
// } else if (this.startView === 'yearGrid') {
// // TODO: Do stuff for year grid
// }
if (monthDropdown) {
monthDropdown.focus();
}
}
}

protected render(): TemplateResult {
Expand All @@ -182,38 +182,16 @@ export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement
const selectedDate = this._selectedDate;
const max = this._max;
const min = this._min;
const locale = this.locale;
const todayDate = this._TODAY_DATE;
const showWeekNumber = this.showWeekNumber;
const startView = this.startView;

const {
dayFormat,
fullDateFormat,
longMonthFormat,
yearFormat,
longWeekdayFormat,
narrowWeekdayFormat,
} = formatters;
const selectedMonth = longMonthFormat(currentDate);
const selectedYear = yearFormat(currentDate);
const isStartViewYearGrid = startView === 'yearGrid';
const multiCldr = isStartViewYearGrid ? undefined : toMultiCalendars({
dayFormat,
disabledDates: splitString(this.disabledDates, toResolvedDate),
disabledDays: splitString(this.disabledDays, Number),
firstDayOfWeek: this.firstDayOfWeek,
fullDateFormat,
locale,
longWeekdayFormat,
max,
min,
narrowWeekdayFormat,
currentDate,
showWeekNumber: Boolean(this.showWeekNumber),
weekLabel: this.weekLabel,
weekNumberType: this.weekNumberType,
});

return html`
<div class=header>
Expand Down Expand Up @@ -250,8 +228,7 @@ export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement
<div class=${classMap({
body: true,
'start-view--calendar': !isStartViewYearGrid,
'start-view--year-grid': isStartViewYearGrid,
[`start-view--${isStartViewYearGrid ? 'year-grid' : 'calendar'}`]: true,
'show-week-number': showWeekNumber,
})}>${
isStartViewYearGrid ?
Expand All @@ -267,35 +244,70 @@ export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement
@year-updated=${this.#updateYear}
></app-year-grid>
` :
multiCldr ? html`${
repeat(multiCldr.calendars, ({ key }) => key, (calendar) => {
const data: MonthCalendarData = {
calendar: calendar.calendar,
date: selectedDate,
disabledDatesSet: multiCldr.disabledDatesSet,
disabledDaysSet: multiCldr.disabledDaysSet,
currentDate,
max,
min,
showWeekNumber,
todayDate,
weekdays: multiCldr.weekdays,
formatters,
};
return html`
<app-month-calendar
class=calendar
.data=${data}
@date-updated=${this.#updateSelectedDate}
></app-month-calendar>
`;
})
}` : nothing
this.#renderCalendar()
}</div>
`;
}

// FIXME: Optimize this code
#renderCalendar = (): TemplateResult => {
const currentDate = this._currentDate;
const max = this._max;
const min = this._min;
const showWeekNumber = this.showWeekNumber;
const formatters = this.#formatters;
const {
dayFormat,
fullDateFormat,
longWeekdayFormat,
narrowWeekdayFormat,
} = formatters;

const {
calendars,
disabledDatesSet,
disabledDaysSet,
weekdays,
} = toMultiCalendars({
dayFormat,
disabledDates: splitString(this.disabledDates, toResolvedDate),
disabledDays: splitString(this.disabledDays, Number),
firstDayOfWeek: this.firstDayOfWeek,
fullDateFormat,
locale: this.locale,
longWeekdayFormat,
max,
min,
narrowWeekdayFormat,
currentDate,
showWeekNumber: Boolean(this.showWeekNumber),
weekLabel: this.weekLabel,
weekNumberType: this.weekNumberType,
});
const [{ calendar }] = calendars;
const data: MonthCalendarData = {
calendar,
date: this._selectedDate,
disabledDatesSet,
disabledDaysSet,
currentDate,
max,
min,
showWeekNumber,
todayDate: this._TODAY_DATE,
weekdays,
formatters,
};

return html`
<app-month-calendar
class=calendar
.data=${data}
@date-updated=${this.#updateSelectedDate}
></app-month-calendar>
`;
};

#navigateMonth = (ev: MouseEvent): void => {
const currentDate = this._currentDate;
const isPreviousNavigation = (
Expand Down
28 changes: 14 additions & 14 deletions src/helpers/compute-next-selected-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ export function computeNextSelectedDate({
* c. If new focused date is either `min` or `max`, reverse order `d += 1` -> `d -= 1` and
* continue the loop until new selectable focused date.
*/
const oldFy = currentDate.getUTCFullYear();
const oldM = currentDate.getUTCMonth();
const oldD = currentDate.getUTCDate();
const focusedDateTime = +currentDate;
const dateFullYear = date.getUTCFullYear();
const dateMonth = date.getUTCMonth();
const dateDate = date.getUTCDate();
const dateTime = +date;

const sdFy = date.getUTCFullYear();
const sdM = date.getUTCMonth();
const currentDateFullYear = currentDate.getUTCFullYear();
const currentDateMonth = currentDate.getUTCMonth();

const notInCurrentMonth = sdM !== oldM || sdFy !== oldFy;
const notInCurrentMonth = currentDateMonth !== dateMonth || currentDateFullYear !== dateFullYear;

let fy = oldFy;
let m = oldM;
let d = oldD;
let fy = dateFullYear;
let m = dateMonth;
let d = dateDate;
let shouldRunSwitch = true;

// If the focused date is not in the current month, focus the first day of the month
Expand All @@ -70,8 +70,8 @@ export function computeNextSelectedDate({
// * PageUp (w/ or w/o Alt)
// * End
if (notInCurrentMonth) {
fy = sdFy;
m = sdM;
fy = currentDateFullYear;
m = currentDateMonth;
d = 1;

shouldRunSwitch =
Expand All @@ -81,8 +81,8 @@ export function computeNextSelectedDate({
}

switch (shouldRunSwitch) {
case focusedDateTime === minTime && (navigationKeyCodeSet.dayPrevious as Set<SupportedKeyCode>).has(keyCode):
case focusedDateTime === maxTime && (navigationKeyCodeSet.dayNext as Set<SupportedKeyCode>).has(keyCode):
case dateTime === minTime && (navigationKeyCodeSet.dayPrevious as Set<SupportedKeyCode>).has(keyCode):
case dateTime === maxTime && (navigationKeyCodeSet.dayNext as Set<SupportedKeyCode>).has(keyCode):
break;
case keyCode === ARROW_UP: {
d -= 7;
Expand Down
Loading

0 comments on commit 3f1445e

Please sign in to comment.