Skip to content

Commit

Permalink
refactor: use KeyboardEvent.key and add disabled state
Browse files Browse the repository at this point in the history
  • Loading branch information
motss committed May 29, 2021
1 parent ec24740 commit 28771a7
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 138 deletions.
71 changes: 9 additions & 62 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { toResolvedDate } from './helpers/to-resolved-date.js';
import type { CalendarViewTuple } from './typings.js';
import { keyArrowDown, keyArrowLeft, keyArrowRight, keyArrowUp, keyEnd, keyEnter, keyHome, keyPageDown, keyPageUp, keySpace } from './key-values.js';

//#region constants
export const APP_DATE_PICKER_DIALOG_NAME = 'app-date-picker-dialog';
Expand All @@ -9,69 +9,16 @@ export const MAX_DATE = toResolvedDate('2100-12-31');
export const ONE_DAY_IN_SECONDS = 864e5;
//#endregion constants

export const calendarViews: CalendarViewTuple = [
export const calendarViews = [
'calendar',
'yearGrid',
];

export const DateTimeFormat = Intl.DateTimeFormat;

export const keyCodesRecord = {
// CTRL: 17,
// ALT: 18,
ESCAPE: 27,
SHIFT: 16,
TAB: 9,
ENTER: 13,
SPACE: 32,
PAGE_UP: 33,
PAGE_DOWN: 34,
END: 35,
HOME: 36,
ARROW_LEFT: 37,
ARROW_UP: 38,
ARROW_RIGHT: 39,
ARROW_DOWN: 40,
} as const;

export const confirmKeyCodeList = [
keyCodesRecord.ENTER,
keyCodesRecord.SPACE,
] as const;

export const confirmKeyCodeSet = new Set(confirmKeyCodeList);

export const navigationKeyCodes = {
next: [
keyCodesRecord.ARROW_DOWN,
keyCodesRecord.PAGE_DOWN,
keyCodesRecord.END,
],
previous: [
keyCodesRecord.ARROW_UP,
keyCodesRecord.PAGE_UP,
keyCodesRecord.HOME,
],
} as const;

export const navigationKeyCodeSet = {
all: new Set([
...navigationKeyCodes.next,
...navigationKeyCodes.previous,
keyCodesRecord.ARROW_LEFT,
keyCodesRecord.ARROW_RIGHT,
]),
dayNext: new Set([keyCodesRecord.ARROW_RIGHT, ...navigationKeyCodes.next]),
dayPrevious: new Set([keyCodesRecord.ARROW_LEFT, ...navigationKeyCodes.previous]),
} as const;

export const calendarKeyCodeSet = new Set(navigationKeyCodeSet.all);
export const DateTimeFormat = Intl.DateTimeFormat;

export const yearGridNavigationKeyCodeSet = new Set([
keyCodesRecord.ARROW_DOWN,
keyCodesRecord.ARROW_LEFT,
keyCodesRecord.ARROW_RIGHT,
keyCodesRecord.ARROW_UP,
keyCodesRecord.END,
keyCodesRecord.HOME,
]);
export const confirmKeySet = new Set([keyEnter, keySpace]);
export const navigationKeyListNext = [keyArrowDown, keyPageDown, keyEnd];
export const navigationKeyListPrevious = [keyArrowUp, keyPageUp, keyHome];
export const navigationKeySetDayNext = new Set([...navigationKeyListNext, keyArrowRight]);
export const navigationKeySetDayPrevious = new Set([...navigationKeyListPrevious, keyArrowLeft]);
export const navigationKeySetGrid = new Set([...navigationKeySetDayNext, ...navigationKeySetDayPrevious]);
49 changes: 20 additions & 29 deletions src/helpers/compute-next-selected-date.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import { toUTCDate } from 'nodemod/dist/calendar/helpers/to-utc-date.js';

import { keyCodesRecord, navigationKeyCodeSet } from '../constants.js';
import type { SupportedKeyCode } from '../typings.js';
import type { navigationKeyListNext} from '../constants.js';
import { navigationKeySetDayNext, navigationKeySetDayPrevious } from '../constants.js';
import { keyArrowDown, keyArrowLeft, keyArrowRight, keyArrowUp, keyEnd, keyHome, keyPageDown, keyPageUp } from '../key-values.js';
import type { InferredFromSet } from '../typings.js';
import { toNextSelectableDate } from './to-next-selectable-date.js';
import type { ComputeNextSelectedDateInit as ComputeNextSelectedDateInit } from './typings.js';

const {
ARROW_DOWN,
ARROW_LEFT,
ARROW_RIGHT,
ARROW_UP,
END,
HOME,
PAGE_DOWN,
PAGE_UP,
} = keyCodesRecord;

export function computeNextSelectedDate({
currentDate,
date,
disabledDatesSet,
disabledDaysSet,
hasAltKey,
keyCode,
key,
maxTime,
minTime,
}: ComputeNextSelectedDateInit): Date {
Expand Down Expand Up @@ -75,45 +66,45 @@ export function computeNextSelectedDate({
d = 1;

shouldRunSwitch =
keyCode === PAGE_DOWN ||
keyCode === PAGE_UP ||
keyCode === END;
key === keyPageDown ||
key === keyPageUp ||
key === keyEnd;
}

switch (shouldRunSwitch) {
case dateTime === minTime && (navigationKeyCodeSet.dayPrevious as Set<SupportedKeyCode>).has(keyCode):
case dateTime === maxTime && (navigationKeyCodeSet.dayNext as Set<SupportedKeyCode>).has(keyCode):
case dateTime === minTime && navigationKeySetDayPrevious.has(key as InferredFromSet<typeof navigationKeySetDayPrevious>):
case dateTime === maxTime && navigationKeySetDayNext.has(key as InferredFromSet<typeof navigationKeyListNext>):
break;
case keyCode === ARROW_UP: {
case key === keyArrowUp: {
d -= 7;
break;
}
case keyCode === ARROW_DOWN: {
case key === keyArrowDown: {
d += 7;
break;
}
case keyCode === ARROW_LEFT: {
case key === keyArrowLeft: {
d -= 1;
break;
}
case keyCode === ARROW_RIGHT: {
case key === keyArrowRight: {
d += 1;
break;
}
case keyCode === PAGE_DOWN: {
case key === keyPageDown: {
hasAltKey ? fy += 1 : m += 1;
break;
}
case keyCode === PAGE_UP: {
case key === keyPageUp: {
hasAltKey ? fy -= 1 : m -= 1;
break;
}
case keyCode === END: {
case key === keyEnd: {
m += 1;
d = 0;
break;
}
case keyCode === HOME:
case key === keyHome:
default: {
d = 1;
}
Expand All @@ -127,7 +118,7 @@ export function computeNextSelectedDate({
* - `2020-01-31` -> next month -> `2020-02-31` (invalid) -> fallback to `2020-02-29`
* - `2020-02-29` -> next year -> `2021-02-29` (invalid) -> fallback to `2021-02-28`
*/
if (keyCode === PAGE_DOWN || keyCode === PAGE_UP) {
if (key === keyPageDown || key === keyPageUp) {
const totalDaysOfMonth = toUTCDate(fy, m + 1, 0).getUTCDate();
if (d > totalDaysOfMonth) {
d = totalDaysOfMonth;
Expand All @@ -139,7 +130,7 @@ export function computeNextSelectedDate({
date: toUTCDate(fy, m, d),
disabledDatesSet,
disabledDaysSet,
keyCode,
key,
maxTime,
minTime,
});
Expand Down
10 changes: 5 additions & 5 deletions src/helpers/to-next-selectable-date.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { toUTCDate } from 'nodemod/dist/calendar/helpers/to-utc-date.js';

import { navigationKeyCodeSet } from '../constants.js';
import type { SupportedKeyCode } from '../typings.js';
import { navigationKeySetDayNext, navigationKeySetDayPrevious } from '../constants.js';
import type { InferredFromSet } from '../typings.js';
import { toDateRange } from './to-date-range.js';
import type { ToNextSelectableDateInit } from './typings.js';

export function toNextSelectableDate({
date,
disabledDatesSet,
disabledDaysSet,
keyCode,
key,
maxTime,
minTime,
}: ToNextSelectableDateInit): Date {
Expand Down Expand Up @@ -38,8 +38,8 @@ export function toNextSelectableDate({
let d = selectableDate.getUTCDate();

while (isDisabledDay) {
if (isLessThanMinTime || (!isMoreThanMaxTime && (navigationKeyCodeSet.dayNext as Set<SupportedKeyCode>).has(keyCode))) d += 1;
if (isMoreThanMaxTime || (!isLessThanMinTime && (navigationKeyCodeSet.dayPrevious as Set<SupportedKeyCode>).has(keyCode))) d -= 1;
if (isLessThanMinTime || (!isMoreThanMaxTime && navigationKeySetDayNext.has(key as InferredFromSet<typeof navigationKeySetDayNext>))) d += 1;
if (isMoreThanMaxTime || (!isLessThanMinTime && navigationKeySetDayPrevious.has(key as InferredFromSet<typeof navigationKeySetDayPrevious>))) d -= 1;

selectableDate = toUTCDate(fy, m, d);
selectableDateTime = +selectableDate;
Expand Down
6 changes: 3 additions & 3 deletions src/helpers/typings.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { Calendar, CalendarInit, CalendarWeekday } from 'nodemod/dist/calendar/typings.js';

import type { DatePickerProperties, Formatters, SupportedKeyCode } from '../typings.js';
import type { DatePickerProperties, Formatters, SupportedKey } from '../typings.js';

export interface ComputeNextSelectedDateInit {
currentDate: Date;
date: Date;
disabledDatesSet: Set<number>;
disabledDaysSet: Set<number>;
hasAltKey: boolean;
keyCode: SupportedKeyCode;
key: SupportedKey;
maxTime: number;
minTime: number;
}
Expand Down Expand Up @@ -40,7 +40,7 @@ export interface ToNextSelectableDateInit {
date: Date;
disabledDatesSet: Set<number>;
disabledDaysSet: Set<number>;
keyCode: SupportedKeyCode;
key: SupportedKey;
maxTime: number;
minTime: number;
}
11 changes: 11 additions & 0 deletions src/key-values.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const keyArrowDown = 'ArrowDown' as const;
export const keyArrowLeft = 'ArrowLeft' as const;
export const keyArrowRight = 'ArrowRight' as const;
export const keyArrowUp = 'ArrowUp' as const;
export const keyEnd = 'End' as const;
export const keyEnter = 'Enter' as const;
export const keyHome = 'Home' as const;
export const keyPageDown = 'PageDown' as const;
export const keyPageUp = 'PageUp' as const;
export const keySpace = ' ' as const;
export const keyTab = 'Tab' as const;
15 changes: 8 additions & 7 deletions src/month-calendar/month-calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { nothing } from 'lit';
import { html, LitElement } from 'lit';
import { classMap } from 'lit/directives/class-map.js';

import { keyCodesRecord, navigationKeyCodeSet } from '../constants.js';
import { navigationKeySetGrid } from '../constants.js';
import { computeNextSelectedDate } from '../helpers/compute-next-selected-date.js';
import { dispatchCustomEvent } from '../helpers/dispatch-custom-event.js';
import { isInTargetMonth } from '../helpers/is-in-current-month.js';
import { toClosestTarget } from '../helpers/to-closest-target.js';
import { toResolvedDate } from '../helpers/to-resolved-date.js';
import { keyHome } from '../key-values.js';
import { baseStyling, resetShadowRoot } from '../stylings.js';
import type { InferredFromSet } from '../typings.js';
import { monthCalendarStyling } from './stylings.js';
import type { MonthCalendarData, MonthCalendarProperties } from './typings.js';

Expand Down Expand Up @@ -116,7 +118,7 @@ export class MonthCalendar extends LitElement implements MonthCalendarProperties
disabledDatesSet,
disabledDaysSet,
hasAltKey: false,
keyCode: keyCodesRecord.HOME,
key: keyHome,
maxTime: +max,
minTime: +min,
});
Expand Down Expand Up @@ -219,11 +221,10 @@ export class MonthCalendar extends LitElement implements MonthCalendarProperties
let newSelectedDate: Date | undefined = undefined;

if (['keydown', 'keyup'].includes(ev.type)) {
const { altKey, keyCode } = ev as KeyboardEvent;
const keyCodeNum = keyCode as typeof navigationKeyCodeSet.all extends Set<infer T> ? T : never;
const key = (ev as KeyboardEvent).key as InferredFromSet<typeof navigationKeySetGrid>;

if (
!(navigationKeyCodeSet.all.has(keyCodeNum) && ev.type === 'keydown')
!(ev.type === 'keydown' && navigationKeySetGrid.has(key))
) return;

// Stop scrolling with arrow keys
Expand All @@ -244,8 +245,8 @@ export class MonthCalendar extends LitElement implements MonthCalendarProperties
date,
disabledDatesSet,
disabledDaysSet,
hasAltKey: altKey,
keyCode: keyCodeNum,
hasAltKey: ev.altKey,
key,
maxTime: +max,
minTime: +min,
}) :
Expand Down
9 changes: 6 additions & 3 deletions src/month-calendar/stylings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ td {
border-radius: 50%;
pointer-events: none;
}
.calendar-day.day--today:not([aria-selected="true"])::before,
.calendar-day:hover::after,
.calendar-day:focus::after {
.calendar-day.day--today:not([aria-disabled="true"]):not([aria-selected="true"])::before,
.calendar-day:not([aria-disabled="true"]):hover::after,
.calendar-day:not([aria-disabled="true"]):focus::after {
width: 26px;
height: 26px;
border-style: solid;
Expand Down Expand Up @@ -102,4 +102,7 @@ td {
.calendar-day:hover::after {
border-color: var(--date-picker-hover-color, var(--base-hover-color));
}
.calendar-day[aria-disabled="true"] {
color: rgba(0, 0, 0, .38);
}
`;
20 changes: 17 additions & 3 deletions src/typings.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { DateTimeFormatter } from 'nodemod/dist/calendar/typings.js';

import type { keyCodesRecord } from './constants.js';
import type { calendarViews } from './constants.js';
import type { keyArrowDown, keyArrowLeft, keyArrowRight, keyArrowUp, keyEnd, keyEnter, keyHome, keyPageDown, keyPageUp, keySpace, keyTab } from './key-values.js';
import type { DatePickerMinMaxProperties, DatePickerMixinProperties } from './mixins/typings.js';

export type CalendarView = CalendarViewTuple[number];

export type CalendarViewTuple = ['calendar', 'yearGrid'];
export type CalendarViewTuple = typeof calendarViews;

export interface ChangedEvent {
isKeypress: boolean;
Expand Down Expand Up @@ -41,6 +42,8 @@ export interface Formatters extends Pick<DatePickerMixinProperties, 'locale'> {
yearFormat: DateTimeFormatter;
}

export type InferredFromSet<SetType> = SetType extends Set<infer T> ? T : never;

export interface SupportedCustomEvent {
['animation-finished']: null;
['changed']: ChangedEvent;
Expand All @@ -50,7 +53,18 @@ export interface SupportedCustomEvent {
['year-updated']: YearUpdatedEvent;
}

export type SupportedKeyCode = typeof keyCodesRecord[keyof typeof keyCodesRecord];
export type SupportedKey =
| typeof keyArrowDown
| typeof keyArrowLeft
| typeof keyArrowRight
| typeof keyArrowUp
| typeof keyEnd
| typeof keyEnter
| typeof keyHome
| typeof keyPageDown
| typeof keyPageUp
| typeof keySpace
| typeof keyTab;

export interface ValueUpdatedEvent extends Pick<DateUpdatedEvent, 'isKeypress'> {
value: string;
Expand Down
Loading

0 comments on commit 28771a7

Please sign in to comment.