Skip to content

Commit

Permalink
refactor: improve code
Browse files Browse the repository at this point in the history
  • Loading branch information
motss committed Nov 6, 2021
1 parent c785fb7 commit d4321bf
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 53 deletions.
6 changes: 5 additions & 1 deletion src/__tests__/year-grid/app-year-grid.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ describe(appYearGridName, () => {
n.getAttribute('tabindex') ?? '',
n.getAttribute('aria-selected') ?? '',
]);
const expectedYearUpdatedEvent: YearUpdatedEvent = { year: data.max.getUTCFullYear() };
const expectedYearUpdatedEvent: YearUpdatedEvent = {
year: data.max.getUTCFullYear(),
isKeypress: testEventType.startsWith('key'),
key: testKey,
};

expect(yearGridButtonAttrsList).deep.equal([
['2019', '2019', '-1', 'false'],
Expand Down
16 changes: 13 additions & 3 deletions src/date-picker-input-surface/date-picker-input-surface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,30 @@ import { MenuSurface } from '@material/mwc-menu/mwc-menu-surface.js';

import { appDatePickerName } from '../date-picker/constants.js';
import { appDatePickerInputName } from '../date-picker-input/constants.js';
import type { InferredFromSet } from '../typings.js';
import { DatePickerInputSurfaceStyling } from './stylings.js';

const alwaysOpenElementSet = new Set([
appDatePickerInputName,
appDatePickerName,
]);

export class DatePickerInputSurface extends MenuSurface {
public static override styles = [
...MenuSurface.styles,
DatePickerInputSurfaceStyling,
];

protected override onBodyClick(ev: MouseEvent) {
const elements = (ev.composedPath() as HTMLElement[]).filter(({ nodeType }) => nodeType === Node.ELEMENT_NODE);
const elements =
(ev.composedPath() as HTMLElement[])
.filter(({ nodeType }) => nodeType === Node.ELEMENT_NODE);
const shouldClose =
elements.some(n => n.classList.contains('calendar-day')) ||
!elements.some(n => n.localName === appDatePickerName) ||
!elements.some(n => n.localName === appDatePickerInputName);
!elements.some(
n =>
alwaysOpenElementSet.has(n.localName as InferredFromSet<typeof alwaysOpenElementSet>)
);

shouldClose && this.close();
}
Expand Down
5 changes: 3 additions & 2 deletions src/helpers/to-next-selected-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,11 @@ export function toNextSelectedDate({
d = 0;
break;
}
case key === keyHome:
default: {
case key === keyHome: {
d = 1;
break;
}
default:
}

/**
Expand Down
21 changes: 12 additions & 9 deletions src/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ export type CalendarView = CalendarViewTuple[number];

export type CalendarViewTuple = typeof calendarViews;

export interface ChangedEvent {
isKeypress: boolean;
export interface ChangedEvent extends KeyEvent {
value: DatePickerMixinProperties['value'];
}

Expand All @@ -21,8 +20,7 @@ export type Constructor<T> = new (...args: any[]) => T;
export interface DatePickerProperties extends DatePickerMixinProperties,
DatePickerMinMaxProperties {}

export interface DateUpdatedEvent {
isKeypress: boolean;
export interface DateUpdatedEvent extends KeyEvent {
value: Date;
}

Expand All @@ -45,11 +43,11 @@ export interface Formatters extends Pick<DatePickerMixinProperties, 'locale'> {
export type InferredFromSet<SetType> = SetType extends Set<infer T> ? T : never;

export interface SupportedCustomEventDetail {
['animation-finished']: null;
['changed']: ChangedEvent;
// ['animation-finished']: null;
// ['changed']: ChangedEvent;
['date-updated']: DateUpdatedEvent;
['first-updated']: FirstUpdatedEvent;
['value-updated']: ValueUpdatedEvent;
// ['value-updated']: ValueUpdatedEvent;
['year-updated']: YearUpdatedEvent;
}

Expand All @@ -66,10 +64,15 @@ export type SupportedKey =
| typeof keySpace
| typeof keyTab;

export interface ValueUpdatedEvent extends Pick<DateUpdatedEvent, 'isKeypress'> {
export interface ValueUpdatedEvent extends KeyEvent {
value: string;
}

export interface YearUpdatedEvent {
export interface YearUpdatedEvent extends KeyEvent {
year: number;
}

interface KeyEvent {
isKeypress: boolean;
key?: SupportedKey;
}
6 changes: 6 additions & 0 deletions src/year-grid/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ export interface YearGridData {
export interface YearGridProperties {
data?: YearGridData;
}

export interface YearGridRenderButtonInit extends Pick<YearGridData, 'date'> {
focusingYear: number;
label: string;
year: number;
}
86 changes: 48 additions & 38 deletions src/year-grid/year-grid.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { nothing, TemplateResult } from 'lit';
import type { TemplateResult } from 'lit';
import { html, LitElement } from 'lit';
import { property, queryAsync, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
Expand All @@ -10,20 +10,19 @@ import { toClosestTarget } from '../helpers/to-closest-target.js';
import { toResolvedDate } from '../helpers/to-resolved-date.js';
import { toYearList } from '../helpers/to-year-list.js';
import { baseStyling, resetButton, resetShadowRoot } from '../stylings.js';
import type { Formatters, InferredFromSet } from '../typings.js';
import type { Formatters, InferredFromSet, SupportedKey } from '../typings.js';
import { yearGridStyling } from './stylings.js';
import { toNextSelectedYear } from './to-next-selected-year.js';
import type { YearGridChangedProperties, YearGridData, YearGridProperties } from './typings.js';
import type { YearGridChangedProperties, YearGridData, YearGridProperties, YearGridRenderButtonInit } from './typings.js';

export class YearGrid extends LitElement implements YearGridProperties {
@property({ attribute: false })
public data?: YearGridData;
@property({ attribute: false }) public data?: YearGridData;

@queryAsync('button[data-year][aria-selected="true"]')
public selectedYearGridButton!: Promise<HTMLButtonElement | null>;
@queryAsync('button[data-year][aria-selected="true"]') public selectedYearGridButton!: Promise<HTMLButtonElement | null>;

@state()
protected $focusingYear: number;
@state() protected $focusingYear: number;

#todayYear: number;

public static override styles = [
baseStyling,
Expand All @@ -32,9 +31,6 @@ export class YearGrid extends LitElement implements YearGridProperties {
yearGridStyling,
];

#selectedYear: number;
#todayYear: number;

constructor() {
super();

Expand All @@ -47,9 +43,7 @@ export class YearGrid extends LitElement implements YearGridProperties {
min: todayDate,
};

this.$focusingYear =
this.#selectedYear =
this.#todayYear = todayDate.getUTCFullYear();
this.$focusingYear = this.#todayYear = todayDate.getUTCFullYear();
}

protected override shouldUpdate(): boolean {
Expand All @@ -61,7 +55,7 @@ export class YearGrid extends LitElement implements YearGridProperties {
const { date } = this.data;

if (date) {
this.$focusingYear = this.#selectedYear = date.getUTCFullYear();
this.$focusingYear = date.getUTCFullYear();
}
}
}
Expand All @@ -70,7 +64,7 @@ export class YearGrid extends LitElement implements YearGridProperties {
await focusElement(this.selectedYearGridButton, element => element.scrollIntoView());
}

protected override render(): TemplateResult | typeof nothing {
protected override render(): TemplateResult {
const {
date,
formatters,
Expand All @@ -89,32 +83,42 @@ export class YearGrid extends LitElement implements YearGridProperties {
@keydown=${this.#updateYear}
@keyup=${this.#updateYear}
>${
yearList.map((year) => {
const yearLabel = yearFormat(new Date(`${year}-01-01`));
return html`
<button
class="year-grid-button ${classMap({ 'year--today': this.#todayYear === year })}"
tabindex=${year === focusingYear ? '0' : '-1'}
data-year=${year}
aria-label=${yearLabel}
aria-selected=${year === date.getUTCFullYear() ? 'true' : 'false'}
></button>
`;
})
yearList.map((year) => this.$renderButton({
date,
focusingYear,
label: yearFormat(new Date(`${year}-01-01`)),
year,
}))
}</div>
`;
}

#updateYear = (ev: MouseEvent | KeyboardEvent): void => {
if (ev.type === 'keydown') {
protected $renderButton({
date,
focusingYear,
label,
year,
}: YearGridRenderButtonInit): TemplateResult {
return html`
<button
class="year-grid-button ${classMap({ 'year--today': this.#todayYear === year })}"
tabindex=${year === focusingYear ? '0' : '-1'}
data-year=${year}
aria-label=${label}
aria-selected=${year === date.getUTCFullYear() ? 'true' : 'false'}
></button>
`;
}

#updateYear = (event: MouseEvent | KeyboardEvent): void => {
if (event.type === 'keydown') {
const key =
(ev as KeyboardEvent).key as InferredFromSet<typeof navigationKeySetGrid>;
(event as KeyboardEvent).key as InferredFromSet<typeof navigationKeySetGrid>;

if (!navigationKeySetGrid.has(key)) return;

// Stop scrolling with arrow keys
ev.preventDefault();
event.preventDefault();

// Focus new year with Home, End, and arrow keys
const {
Expand All @@ -135,18 +139,24 @@ export class YearGrid extends LitElement implements YearGridProperties {

this.$focusingYear = focusingYear;
focusingYearGridButton?.focus();
} else if (ev.type === 'click') {
} else if (event.type === 'click') {
const selectedYearStr =
toClosestTarget(ev, `button[data-year]`)
toClosestTarget(event, `button[data-year]`)
?.getAttribute('data-year');

/** Do nothing when not tapping on the year button */
if (selectedYearStr == null) return;

const key = (event as KeyboardEvent).key as SupportedKey;
const year = Number(selectedYearStr);

this.$focusingYear = this.#selectedYear = year;
dispatchCustomEvent(this, 'year-updated', { year });
this.$focusingYear = year;

dispatchCustomEvent(this, 'year-updated', {
isKeypress: Boolean(key),
key,
year,
});
}
};
}

0 comments on commit d4321bf

Please sign in to comment.