@sectile/dom 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/calendar.d.ts +37 -88
- package/dist/calendar.d.ts.map +1 -1
- package/dist/calendar.js +157 -267
- package/dist/calendar.js.map +1 -1
- package/dist/date-field.d.ts +3 -3
- package/dist/date-field.d.ts.map +1 -1
- package/dist/date-field.js +2 -2
- package/dist/date-field.js.map +1 -1
- package/dist/date-picker.d.ts +7 -6
- package/dist/date-picker.d.ts.map +1 -1
- package/dist/date-picker.js +8 -7
- package/dist/date-picker.js.map +1 -1
- package/dist/date-range-field.d.ts +4 -4
- package/dist/date-range-field.d.ts.map +1 -1
- package/dist/date-range-field.js +3 -3
- package/dist/date-range-field.js.map +1 -1
- package/dist/date-range-picker.d.ts +6 -5
- package/dist/date-range-picker.d.ts.map +1 -1
- package/dist/date-range-picker.js +7 -7
- package/dist/date-range-picker.js.map +1 -1
- package/dist/date-time-field.d.ts +3 -3
- package/dist/date-time-field.d.ts.map +1 -1
- package/dist/date-time-field.js +2 -2
- package/dist/date-time-field.js.map +1 -1
- package/dist/date-time-picker.d.ts +6 -6
- package/dist/date-time-picker.d.ts.map +1 -1
- package/dist/date-time-picker.js +9 -9
- package/dist/date-time-picker.js.map +1 -1
- package/dist/date-time-range-picker.d.ts +6 -6
- package/dist/date-time-range-picker.d.ts.map +1 -1
- package/dist/date-time-range-picker.js +9 -9
- package/dist/date-time-range-picker.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/floating-position.d.ts.map +1 -1
- package/dist/internal/floating-position.js +6 -2
- package/dist/internal/floating-position.js.map +1 -1
- package/dist/month-picker.d.ts +2 -2
- package/dist/month-picker.d.ts.map +1 -1
- package/dist/month-picker.js +1 -1
- package/dist/month-picker.js.map +1 -1
- package/dist/month-range-picker.d.ts +1 -1
- package/dist/month-range-picker.d.ts.map +1 -1
- package/dist/month-range-picker.js +1 -1
- package/dist/month-range-picker.js.map +1 -1
- package/dist/reorder.d.ts.map +1 -1
- package/dist/reorder.js.map +1 -1
- package/dist/time-field.d.ts +3 -3
- package/dist/time-field.d.ts.map +1 -1
- package/dist/time-field.js +2 -2
- package/dist/time-field.js.map +1 -1
- package/dist/time-range-field.d.ts +4 -4
- package/dist/time-range-field.d.ts.map +1 -1
- package/dist/time-range-field.js +2 -2
- package/dist/time-range-field.js.map +1 -1
- package/package.json +3 -2
package/dist/calendar.d.ts
CHANGED
|
@@ -1,98 +1,47 @@
|
|
|
1
1
|
import { type FacadeConnection } from '@sectile/core/adapter-runtime';
|
|
2
|
-
import type { Result
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import { type
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
readonly altKey?: boolean;
|
|
10
|
-
readonly ctrlKey?: boolean;
|
|
11
|
-
readonly metaKey?: boolean;
|
|
12
|
-
}
|
|
13
|
-
export type CalendarEffect<ID extends StableID = StableID> = {
|
|
14
|
-
readonly type: 'focus-element';
|
|
15
|
-
readonly id: ID;
|
|
16
|
-
} | {
|
|
17
|
-
readonly type: 'request-page';
|
|
18
|
-
readonly direction: -1 | 1;
|
|
19
|
-
readonly from: ID | null;
|
|
20
|
-
};
|
|
21
|
-
export interface CalendarValueChangeDetails<ID extends StableID = StableID> {
|
|
22
|
-
readonly value: ID | null;
|
|
23
|
-
readonly previousValue: ID | null;
|
|
24
|
-
}
|
|
25
|
-
export interface CalendarHighlightChangeDetails<ID extends StableID = StableID> {
|
|
26
|
-
readonly value: ID | null;
|
|
27
|
-
readonly previousValue: ID | null;
|
|
28
|
-
}
|
|
29
|
-
export interface CalendarControllerOptions<ID extends StableID = StableID> {
|
|
30
|
-
readonly grid: Grid<ID>;
|
|
31
|
-
readonly disabled?: boolean;
|
|
32
|
-
readonly policies?: CalendarPolicies<ID>;
|
|
33
|
-
readonly value?: ID | null;
|
|
34
|
-
readonly defaultValue?: ID | null;
|
|
35
|
-
readonly highlightedValue?: ID | null;
|
|
36
|
-
readonly defaultHighlightedValue?: ID | null;
|
|
37
|
-
readonly onValueChange?: (change: CalendarValueChangeDetails<ID>) => void;
|
|
38
|
-
readonly onHighlightedValueChange?: (change: CalendarHighlightChangeDetails<ID>) => void;
|
|
39
|
-
}
|
|
40
|
-
export type CalendarControllerValueChangeHandler<ID extends StableID = StableID> = NonNullable<CalendarControllerOptions<ID>['onValueChange']>;
|
|
41
|
-
export type CalendarControllerHighlightedValueChangeHandler<ID extends StableID = StableID> = NonNullable<CalendarControllerOptions<ID>['onHighlightedValueChange']>;
|
|
42
|
-
export interface CalendarControlledValues<ID extends StableID = StableID> {
|
|
43
|
-
readonly value?: ID | null;
|
|
44
|
-
readonly highlightedValue?: ID | null;
|
|
45
|
-
}
|
|
46
|
-
export interface CalendarController<ID extends StableID = StableID> {
|
|
47
|
-
readonly grid: Grid<ID>;
|
|
48
|
-
getSnapshot(): RevisionSnapshot<CalendarState<ID>>;
|
|
49
|
-
syncControlledValues(values: CalendarControlledValues<ID>): Result<RevisionSnapshot<CalendarState<ID>>>;
|
|
50
|
-
handleKeyboardInput(input: KeyboardInput, expectedRevision?: number): RevisionResult<CalendarState<ID>, CalendarEffect<ID>>;
|
|
51
|
-
handleEvent(event: CalendarEvent<ID>, expectedRevision?: number): RevisionResult<CalendarState<ID>, CalendarEffect<ID>>;
|
|
52
|
-
}
|
|
53
|
-
export interface CalendarPageRequestDetails<ID extends StableID = StableID> {
|
|
54
|
-
readonly direction: -1 | 1;
|
|
55
|
-
readonly from: ID | null;
|
|
56
|
-
}
|
|
57
|
-
export interface CalendarTransitionDetails<ID extends StableID = StableID> {
|
|
58
|
-
readonly event: CalendarEvent<ID>;
|
|
59
|
-
readonly result: RevisionResult<CalendarState<ID>, CalendarEffect<ID>>;
|
|
60
|
-
}
|
|
61
|
-
export interface CalendarConnectionOptions<ID extends StableID = StableID> {
|
|
62
|
-
readonly controller: CalendarController<ID>;
|
|
2
|
+
import type { Result } from '@sectile/core';
|
|
3
|
+
import type { RevisionSnapshot } from '@sectile/core/revision';
|
|
4
|
+
import { type CalendarEvent, type CalendarMonthValue, type CalendarPolicies, type CalendarState } from '@sectile/temporal/calendar';
|
|
5
|
+
import { type DateValue } from '@sectile/temporal/date-field';
|
|
6
|
+
export type { CalendarCommand, CalendarEvent, CalendarMonthValue, CalendarPolicies, CalendarState, CalendarView, CalendarViewMode, } from '@sectile/temporal/calendar';
|
|
7
|
+
export type { DateValue } from '@sectile/temporal/date-field';
|
|
8
|
+
export interface CalendarOptions {
|
|
63
9
|
readonly root: HTMLElement;
|
|
10
|
+
readonly grid?: HTMLElement;
|
|
11
|
+
readonly policies?: CalendarPolicies;
|
|
12
|
+
readonly value?: DateValue | null;
|
|
13
|
+
readonly defaultValue?: DateValue | null;
|
|
14
|
+
readonly highlightedValue?: DateValue;
|
|
15
|
+
readonly defaultHighlightedValue?: DateValue;
|
|
64
16
|
readonly disabled?: boolean;
|
|
65
|
-
readonly
|
|
66
|
-
readonly
|
|
17
|
+
readonly readOnly?: boolean;
|
|
18
|
+
readonly required?: boolean;
|
|
19
|
+
readonly label?: string;
|
|
20
|
+
readonly onValueChange?: (value: DateValue | null) => void;
|
|
21
|
+
readonly onHighlightedValueChange?: (value: DateValue) => void;
|
|
67
22
|
readonly onUpdate?: () => void;
|
|
68
23
|
}
|
|
69
|
-
export type
|
|
70
|
-
export type
|
|
71
|
-
export type
|
|
72
|
-
export interface
|
|
73
|
-
readonly
|
|
74
|
-
readonly
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
readonly
|
|
80
|
-
|
|
81
|
-
syncControlledValues(values: CalendarControlledValues
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
handleEvent(event: CalendarEvent<ID>): boolean;
|
|
24
|
+
export type CalendarValueChangeHandler = NonNullable<CalendarOptions['onValueChange']>;
|
|
25
|
+
export type CalendarHighlightedValueChangeHandler = NonNullable<CalendarOptions['onHighlightedValueChange']>;
|
|
26
|
+
export type CalendarUpdateHandler = NonNullable<CalendarOptions['onUpdate']>;
|
|
27
|
+
export interface CalendarControlledValues {
|
|
28
|
+
readonly value?: DateValue | null;
|
|
29
|
+
readonly highlightedValue?: DateValue;
|
|
30
|
+
}
|
|
31
|
+
export interface CalendarConnection {
|
|
32
|
+
getSnapshot(): RevisionSnapshot<CalendarState>;
|
|
33
|
+
getMonth(): readonly (readonly DateValue[])[];
|
|
34
|
+
getWeek(): readonly DateValue[];
|
|
35
|
+
getYear(): readonly (readonly CalendarMonthValue[])[];
|
|
36
|
+
syncControlledValues(values: CalendarControlledValues): Result<RevisionSnapshot<CalendarState>>;
|
|
37
|
+
setCellAttributes(element: HTMLElement, value: DateValue): void;
|
|
38
|
+
handleEvent(event: CalendarEvent): boolean;
|
|
85
39
|
handleKeyboardEvent(event: KeyboardEvent): boolean;
|
|
86
40
|
focusCurrent(): void;
|
|
41
|
+
refresh(): void;
|
|
87
42
|
disconnect(): void;
|
|
88
43
|
}
|
|
89
|
-
export
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
export declare function createCalendarController<ID extends StableID>(options: CalendarControllerOptions<ID>): Result<CalendarController<ID>>;
|
|
93
|
-
export declare function createCalendar<ID extends StableID>(options: CalendarOptions<ID>): FacadeConnection<CalendarConnection<ID>>;
|
|
94
|
-
export declare function tryCreateCalendar<ID extends StableID>(options: CalendarOptions<ID>): Result<FacadeConnection<CalendarConnection<ID>>>;
|
|
95
|
-
export declare function connectCalendar<ID extends StableID>(options: CalendarConnectionOptions<ID>): CalendarConnection<ID>;
|
|
96
|
-
export declare function toCalendarEvent<ID extends StableID = StableID>(input: KeyboardInput): CalendarEvent<ID> | null;
|
|
97
|
-
export declare function toCalendarEffect<ID extends StableID>(command: CalendarCommand<ID>): CalendarEffect<ID>;
|
|
44
|
+
export declare function createCalendar(options: CalendarOptions): FacadeConnection<CalendarConnection>;
|
|
45
|
+
export declare function tryCreateCalendar(options: CalendarOptions): Result<FacadeConnection<CalendarConnection>>;
|
|
46
|
+
export declare function toCalendarEvent(input: Pick<KeyboardEvent, 'key' | 'altKey' | 'ctrlKey' | 'metaKey' | 'shiftKey'>): CalendarEvent | null;
|
|
98
47
|
//# sourceMappingURL=calendar.d.ts.map
|
package/dist/calendar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../src/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../src/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,gBAAgB,EAA2B,MAAM,+BAA+B,CAAC;AAEjJ,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EASL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAIjG,YAAY,EACV,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IACtC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,SAAS,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3D,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC/D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,0BAA0B,GAAG,WAAW,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC;AACvF,MAAM,MAAM,qCAAqC,GAAG,WAAW,CAAC,eAAe,CAAC,0BAA0B,CAAC,CAAC,CAAC;AAC7G,MAAM,MAAM,qBAAqB,GAAG,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;AAE7E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,IAAI,gBAAgB,CAAC,aAAa,CAAC,CAAC;IAC/C,QAAQ,IAAI,SAAS,CAAC,SAAS,SAAS,EAAE,CAAC,EAAE,CAAC;IAC9C,OAAO,IAAI,SAAS,SAAS,EAAE,CAAC;IAChC,OAAO,IAAI,SAAS,CAAC,SAAS,kBAAkB,EAAE,CAAC,EAAE,CAAC;IACtD,oBAAoB,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC;IAChG,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC;IAC3C,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC;IACnD,YAAY,IAAI,IAAI,CAAC;IACrB,OAAO,IAAI,IAAI,CAAC;IAChB,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CAAC,kBAAkB,CAAC,CAE7F;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAExG;AA+ID,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC,GAAG,aAAa,GAAG,IAAI,CAYvI"}
|
package/dist/calendar.js
CHANGED
|
@@ -1,296 +1,186 @@
|
|
|
1
|
-
import { createFacadeConnection } from '@sectile/core/adapter-runtime';
|
|
1
|
+
import { createFacadeConnection, createSemanticController } from '@sectile/core/adapter-runtime';
|
|
2
2
|
import { unwrap } from '@sectile/core/result';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { tryCreateRevisionSnapshot, rejectRevisionInput, } from '@sectile/core/revision';
|
|
7
|
-
import { applyControllerEvent, synchronizeControllerState } from '@sectile/core/adapter-runtime';
|
|
8
|
-
import { findDelegatedID } from './internal/delegated-event.js';
|
|
3
|
+
import { applyCalendarEvent, calendarID, createCalendarMonth, createCalendarWeek, createCalendarYear, isCalendarValueAvailable, tryCreateCalendarState, } from '@sectile/temporal/calendar';
|
|
4
|
+
import { compareDateValues, parseDateValue } from '@sectile/temporal/date-field';
|
|
5
|
+
import { setDatePickerCellAvailability } from './internal/date-picker-cell.js';
|
|
9
6
|
import { setInteractionAttributes } from './internal/interaction.js';
|
|
10
|
-
export function createCalendarController(options) {
|
|
11
|
-
const value = options.value !== undefined ? options.value : options.defaultValue ?? null;
|
|
12
|
-
const current = options.highlightedValue !== undefined
|
|
13
|
-
? options.highlightedValue
|
|
14
|
-
: options.defaultHighlightedValue ?? null;
|
|
15
|
-
const initial = tryCreateCalendarState(options.grid, {
|
|
16
|
-
selected: value === null ? [] : [value],
|
|
17
|
-
anchor: value,
|
|
18
|
-
current,
|
|
19
|
-
});
|
|
20
|
-
if (!initial.ok)
|
|
21
|
-
return initial;
|
|
22
|
-
const snapshot = tryCreateRevisionSnapshot(initial.value);
|
|
23
|
-
if (!snapshot.ok)
|
|
24
|
-
return snapshot;
|
|
25
|
-
const interaction = tryCreateInteractionState(options);
|
|
26
|
-
if (!interaction.ok)
|
|
27
|
-
return interaction;
|
|
28
|
-
return { ok: true, value: new DOMCalendarController(options, snapshot.value, interaction.value) };
|
|
29
|
-
}
|
|
30
7
|
export function createCalendar(options) {
|
|
31
8
|
return unwrap(tryCreateCalendar(options));
|
|
32
9
|
}
|
|
33
10
|
export function tryCreateCalendar(options) {
|
|
34
|
-
return createFacadeConnection(options,
|
|
35
|
-
}
|
|
36
|
-
function tryCreateCalendarConnection(options) {
|
|
37
|
-
const grid = tryCreateGrid(options.rows);
|
|
38
|
-
if (!grid.ok)
|
|
39
|
-
return grid;
|
|
40
|
-
const controller = createCalendarController({ ...options, grid: grid.value });
|
|
41
|
-
if (!controller.ok)
|
|
42
|
-
return controller;
|
|
43
|
-
return { ok: true, value: connectCalendar({ ...options, controller: controller.value }) };
|
|
44
|
-
}
|
|
45
|
-
export function connectCalendar(options) {
|
|
46
|
-
return new DOMCalendarConnection(options);
|
|
11
|
+
return createFacadeConnection(options, constructCalendar);
|
|
47
12
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
13
|
+
function constructCalendar(options) {
|
|
14
|
+
const controls = {
|
|
15
|
+
value: options.value !== undefined,
|
|
16
|
+
highlighted: options.highlightedValue !== undefined,
|
|
17
|
+
};
|
|
18
|
+
const requestedValue = controls.value ? options.value : options.defaultValue;
|
|
19
|
+
const requestedHighlight = controls.highlighted ? options.highlightedValue : options.defaultHighlightedValue;
|
|
20
|
+
const initial = tryCreateCalendarState({
|
|
21
|
+
...(requestedValue === undefined ? {} : { value: requestedValue }),
|
|
22
|
+
...(requestedHighlight === undefined ? {} : { highlighted: requestedHighlight }),
|
|
23
|
+
});
|
|
24
|
+
const runtime = createSemanticController({
|
|
25
|
+
initial,
|
|
26
|
+
reducer: (state, event) => applyCalendarEvent(state, event, {
|
|
27
|
+
...options.policies,
|
|
28
|
+
...(options.required === undefined ? {} : { required: options.required }),
|
|
29
|
+
}),
|
|
30
|
+
reconcile: (previous, proposed) => tryCreateCalendarState({
|
|
31
|
+
value: controls.value ? previous.value : proposed.value,
|
|
32
|
+
highlighted: controls.highlighted ? previous.highlighted : proposed.highlighted,
|
|
33
|
+
view: controls.highlighted ? previous.view : proposed.view,
|
|
34
|
+
viewMode: proposed.viewMode,
|
|
35
|
+
}),
|
|
36
|
+
notify: (previous, proposed) => {
|
|
37
|
+
if (compareNullable(previous.value, proposed.value) !== 0)
|
|
38
|
+
options.onValueChange?.(proposed.value);
|
|
39
|
+
if (compareDateValues(previous.highlighted, proposed.highlighted) !== 0)
|
|
40
|
+
options.onHighlightedValueChange?.(proposed.highlighted);
|
|
41
|
+
},
|
|
42
|
+
toEffect: (command) => command,
|
|
43
|
+
interaction: options,
|
|
44
|
+
interactionIntent: calendarInteractionIntent,
|
|
45
|
+
});
|
|
46
|
+
return runtime.ok
|
|
47
|
+
? { ok: true, value: new DOMCalendar(options, runtime.value, controls) }
|
|
48
|
+
: runtime;
|
|
71
49
|
}
|
|
72
|
-
class
|
|
73
|
-
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.#
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return this
|
|
50
|
+
class DOMCalendar {
|
|
51
|
+
#options;
|
|
52
|
+
#grid;
|
|
53
|
+
#runtime;
|
|
54
|
+
#controls;
|
|
55
|
+
#keydown = (event) => {
|
|
56
|
+
if (this.handleKeyboardEvent(event))
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
};
|
|
59
|
+
#click = (event) => {
|
|
60
|
+
const target = event.target instanceof Element ? event.target.closest('[data-calendar-id]') : null;
|
|
61
|
+
if (target === null || !this.#grid.contains(target))
|
|
62
|
+
return;
|
|
63
|
+
const parsed = parseDateValue(target.dataset['calendarId'] ?? '');
|
|
64
|
+
if (parsed.ok)
|
|
65
|
+
this.handleEvent({ type: 'select', value: parsed.value });
|
|
66
|
+
};
|
|
67
|
+
constructor(options, runtime, controls) {
|
|
68
|
+
this.#options = options;
|
|
69
|
+
this.#grid = options.grid ?? options.root;
|
|
70
|
+
this.#runtime = runtime;
|
|
71
|
+
this.#controls = controls;
|
|
72
|
+
this.#grid.addEventListener('keydown', this.#keydown);
|
|
73
|
+
this.#grid.addEventListener('click', this.#click);
|
|
74
|
+
this.#grid.setAttribute('role', 'grid');
|
|
75
|
+
setInteractionAttributes(this.#grid, options);
|
|
76
|
+
this.refresh();
|
|
77
|
+
}
|
|
78
|
+
getSnapshot() { return this.#runtime.getSnapshot(); }
|
|
79
|
+
getMonth() {
|
|
80
|
+
return createCalendarMonth(this.getSnapshot().state.view, this.#options.policies?.weekStartsOn);
|
|
81
|
+
}
|
|
82
|
+
getWeek() {
|
|
83
|
+
return createCalendarWeek(this.getSnapshot().state.highlighted, this.#options.policies?.weekStartsOn);
|
|
84
|
+
}
|
|
85
|
+
getYear() {
|
|
86
|
+
return createCalendarYear(this.getSnapshot().state.view.year);
|
|
103
87
|
}
|
|
104
88
|
syncControlledValues(values) {
|
|
105
|
-
|
|
89
|
+
if (this.#controls.value !== (values.value !== undefined) || this.#controls.highlighted !== (values.highlightedValue !== undefined)) {
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
error: {
|
|
93
|
+
class: 'construction',
|
|
94
|
+
code: 'controlled-shape-mismatch',
|
|
95
|
+
message: 'Controlled calendar values must preserve their construction-time shape.',
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const state = this.getSnapshot().state;
|
|
100
|
+
const highlighted = this.#controls.highlighted ? values.highlightedValue : state.highlighted;
|
|
101
|
+
const result = this.#runtime.replace(tryCreateCalendarState({
|
|
102
|
+
value: this.#controls.value ? values.value : state.value,
|
|
103
|
+
highlighted,
|
|
104
|
+
view: { year: highlighted.year, month: highlighted.month },
|
|
105
|
+
viewMode: state.viewMode,
|
|
106
|
+
}));
|
|
106
107
|
if (result.ok) {
|
|
107
|
-
this
|
|
108
|
-
this.
|
|
108
|
+
this.refresh();
|
|
109
|
+
this.#options.onUpdate?.();
|
|
109
110
|
}
|
|
110
111
|
return result;
|
|
111
112
|
}
|
|
112
|
-
|
|
113
|
-
this
|
|
114
|
-
|
|
115
|
-
this.#root.setAttribute('aria-colcount', String(this.grid.columnCount));
|
|
116
|
-
if (label === undefined)
|
|
117
|
-
this.#root.removeAttribute('aria-label');
|
|
118
|
-
else
|
|
119
|
-
this.#root.setAttribute('aria-label', label);
|
|
120
|
-
}
|
|
121
|
-
setCellAttributes(element, attributes) {
|
|
122
|
-
const state = this.#controller.getSnapshot().state;
|
|
123
|
-
element.dataset['calendarId'] = String(attributes.id);
|
|
124
|
-
element.tabIndex = state.cursor.current === attributes.id ? 0 : -1;
|
|
113
|
+
setCellAttributes(element, value) {
|
|
114
|
+
const state = this.getSnapshot().state;
|
|
115
|
+
element.dataset['calendarId'] = calendarID(value);
|
|
125
116
|
element.setAttribute('role', 'gridcell');
|
|
126
|
-
element.setAttribute('aria-
|
|
127
|
-
element
|
|
128
|
-
element.
|
|
129
|
-
if (attributes.disabled === true)
|
|
130
|
-
element.setAttribute('aria-disabled', 'true');
|
|
131
|
-
else
|
|
132
|
-
element.removeAttribute('aria-disabled');
|
|
133
|
-
}
|
|
134
|
-
handleKeyboardEvent(event) {
|
|
135
|
-
const input = {
|
|
136
|
-
key: event.key,
|
|
137
|
-
altKey: event.altKey,
|
|
138
|
-
ctrlKey: event.ctrlKey,
|
|
139
|
-
metaKey: event.metaKey,
|
|
140
|
-
};
|
|
141
|
-
const semanticEvent = toCalendarEvent(input);
|
|
142
|
-
if (semanticEvent === null)
|
|
143
|
-
return false;
|
|
144
|
-
return this.handleEvent(semanticEvent);
|
|
117
|
+
element.setAttribute('aria-selected', String(state.value !== null && compareDateValues(state.value, value) === 0));
|
|
118
|
+
setDatePickerCellAvailability(element, isCalendarValueAvailable(value, this.#options.policies));
|
|
119
|
+
element.tabIndex = compareDateValues(state.highlighted, value) === 0 ? 0 : -1;
|
|
145
120
|
}
|
|
146
121
|
handleEvent(event) {
|
|
147
|
-
const result = this.#
|
|
148
|
-
if (result.ok)
|
|
149
|
-
|
|
150
|
-
this
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
this.focusCurrent();
|
|
154
|
-
}
|
|
155
|
-
return result.ok;
|
|
156
|
-
}
|
|
157
|
-
focusCurrent() {
|
|
158
|
-
queueMicrotask(() => {
|
|
159
|
-
const current = this.#controller.getSnapshot().state.cursor.current;
|
|
160
|
-
if (current === null) {
|
|
161
|
-
this.#root.focus();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
for (const element of this.#root.querySelectorAll('[data-calendar-id]')) {
|
|
165
|
-
if (element.dataset['calendarId'] !== String(current))
|
|
166
|
-
continue;
|
|
167
|
-
element.focus();
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
disconnect() {
|
|
173
|
-
this.#root.removeEventListener('keydown', this.#handleKeydown);
|
|
174
|
-
this.#root.removeEventListener('click', this.#handleClick);
|
|
175
|
-
}
|
|
176
|
-
#applyEffects(effects) {
|
|
177
|
-
for (const effect of effects) {
|
|
178
|
-
if (effect.type !== 'request-page')
|
|
179
|
-
continue;
|
|
180
|
-
this.#onPageRequest?.(Object.freeze({ direction: effect.direction, from: effect.from }));
|
|
122
|
+
const result = this.#runtime.handle(event);
|
|
123
|
+
if (!result.ok)
|
|
124
|
+
return false;
|
|
125
|
+
this.refresh();
|
|
126
|
+
this.#options.onUpdate?.();
|
|
127
|
+
if (result.commands.some((command) => command.type === 'highlight-changed')) {
|
|
128
|
+
queueMicrotask(() => this.focusCurrent());
|
|
181
129
|
}
|
|
130
|
+
return true;
|
|
182
131
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
#grid;
|
|
187
|
-
#policies;
|
|
188
|
-
#valueControlled;
|
|
189
|
-
#highlightControlled;
|
|
190
|
-
#onValueChange;
|
|
191
|
-
#onHighlightedValueChange;
|
|
192
|
-
#interaction;
|
|
193
|
-
#snapshot;
|
|
194
|
-
constructor(options, snapshot, interaction) {
|
|
195
|
-
this.grid = options.grid;
|
|
196
|
-
this.#grid = options.grid;
|
|
197
|
-
this.#policies = options.policies ?? {};
|
|
198
|
-
this.#valueControlled = options.value !== undefined;
|
|
199
|
-
this.#highlightControlled = options.highlightedValue !== undefined;
|
|
200
|
-
this.#onValueChange = options.onValueChange;
|
|
201
|
-
this.#onHighlightedValueChange = options.onHighlightedValueChange;
|
|
202
|
-
this.#interaction = interaction;
|
|
203
|
-
this.#snapshot = snapshot;
|
|
132
|
+
handleKeyboardEvent(event) {
|
|
133
|
+
const semantic = toCalendarEvent(event);
|
|
134
|
+
return semantic !== null && this.handleEvent(semantic);
|
|
204
135
|
}
|
|
205
|
-
|
|
206
|
-
|
|
136
|
+
focusCurrent() {
|
|
137
|
+
this.#grid.querySelector('[tabindex="0"]')?.focus();
|
|
207
138
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
anchor: this.#valueControlled ? selected : this.#snapshot.state.selection.anchor,
|
|
218
|
-
current: this.#highlightControlled
|
|
219
|
-
? values.highlightedValue
|
|
220
|
-
: this.#snapshot.state.cursor.current,
|
|
139
|
+
refresh() {
|
|
140
|
+
if (this.#options.label === undefined)
|
|
141
|
+
this.#grid.removeAttribute('aria-label');
|
|
142
|
+
else
|
|
143
|
+
this.#grid.setAttribute('aria-label', this.#options.label);
|
|
144
|
+
this.#grid.querySelectorAll('[data-calendar-id]').forEach((element) => {
|
|
145
|
+
const parsed = parseDateValue(element.dataset['calendarId'] ?? '');
|
|
146
|
+
if (parsed.ok)
|
|
147
|
+
this.setCellAttributes(element, parsed.value);
|
|
221
148
|
});
|
|
222
|
-
const snapshot = synchronizeControllerState(this.#snapshot, state);
|
|
223
|
-
if (!snapshot.ok)
|
|
224
|
-
return snapshot;
|
|
225
|
-
this.#snapshot = snapshot.value;
|
|
226
|
-
return snapshot;
|
|
227
|
-
}
|
|
228
|
-
handleKeyboardInput(input, expectedRevision = this.#snapshot.revision) {
|
|
229
|
-
const event = toCalendarEvent(input);
|
|
230
|
-
if (event === null) {
|
|
231
|
-
return rejectRevisionInput(this.#snapshot, {
|
|
232
|
-
class: 'transition-rejection',
|
|
233
|
-
code: 'unsupported-dom-key',
|
|
234
|
-
message: 'DOM keyboard input does not map to a calendar semantic event.',
|
|
235
|
-
details: { key: input.key },
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
return this.handleEvent(event, expectedRevision);
|
|
239
149
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return rejectRevisionInput(this.#snapshot, permitted.error);
|
|
244
|
-
const result = applyControllerEvent(this.#snapshot, expectedRevision, event, (state, semanticEvent) => applyCalendarEvent(this.#grid, state, semanticEvent, this.#policies), (previous, proposed) => controlledState(this.#grid, previous, proposed, this.#valueControlled, this.#highlightControlled), (previous, proposed) => this.#notify(previous, proposed), toCalendarEffect);
|
|
245
|
-
if (result.ok)
|
|
246
|
-
this.#snapshot = result.snapshot;
|
|
247
|
-
return result;
|
|
248
|
-
}
|
|
249
|
-
#notify(previous, proposed) {
|
|
250
|
-
const previousValue = selectedValue(previous);
|
|
251
|
-
const value = selectedValue(proposed);
|
|
252
|
-
if (previousValue !== value) {
|
|
253
|
-
this.#onValueChange?.(Object.freeze({ value, previousValue }));
|
|
254
|
-
}
|
|
255
|
-
if (previous.cursor.current !== proposed.cursor.current) {
|
|
256
|
-
this.#onHighlightedValueChange?.(Object.freeze({
|
|
257
|
-
value: proposed.cursor.current,
|
|
258
|
-
previousValue: previous.cursor.current,
|
|
259
|
-
}));
|
|
260
|
-
}
|
|
150
|
+
disconnect() {
|
|
151
|
+
this.#grid.removeEventListener('keydown', this.#keydown);
|
|
152
|
+
this.#grid.removeEventListener('click', this.#click);
|
|
261
153
|
}
|
|
262
154
|
}
|
|
263
|
-
function
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
155
|
+
export function toCalendarEvent(input) {
|
|
156
|
+
if (input.altKey || input.ctrlKey || input.metaKey)
|
|
157
|
+
return null;
|
|
158
|
+
if (input.key === 'ArrowLeft')
|
|
159
|
+
return 'previous-day';
|
|
160
|
+
if (input.key === 'ArrowRight')
|
|
161
|
+
return 'next-day';
|
|
162
|
+
if (input.key === 'ArrowUp')
|
|
163
|
+
return 'previous-week';
|
|
164
|
+
if (input.key === 'ArrowDown')
|
|
165
|
+
return 'next-week';
|
|
166
|
+
if (input.key === 'Home')
|
|
167
|
+
return 'start-of-week';
|
|
168
|
+
if (input.key === 'End')
|
|
169
|
+
return 'end-of-week';
|
|
170
|
+
if (input.key === 'PageUp')
|
|
171
|
+
return input.shiftKey ? 'previous-year' : 'previous-month';
|
|
172
|
+
if (input.key === 'PageDown')
|
|
173
|
+
return input.shiftKey ? 'next-year' : 'next-month';
|
|
174
|
+
if (input.key === 'Enter' || input.key === ' ')
|
|
175
|
+
return 'select-highlighted';
|
|
176
|
+
return null;
|
|
269
177
|
}
|
|
270
|
-
function
|
|
271
|
-
|
|
178
|
+
function calendarInteractionIntent(event) {
|
|
179
|
+
if (event === 'select-highlighted')
|
|
180
|
+
return 'mutate';
|
|
181
|
+
return typeof event === 'object' && (event.type === 'select' || event.type === 'set-value') ? 'mutate' : 'navigate';
|
|
272
182
|
}
|
|
273
|
-
function
|
|
274
|
-
|
|
275
|
-
return {
|
|
276
|
-
class: 'construction',
|
|
277
|
-
code: valueControlled ? 'controlled-value-required' : 'uncontrolled-value-update',
|
|
278
|
-
message: valueControlled
|
|
279
|
-
? 'Controlled calendar selection sync requires value.'
|
|
280
|
-
: 'Uncontrolled calendar selection cannot be synchronized externally.',
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
if (highlightControlled !== (values.highlightedValue !== undefined)) {
|
|
284
|
-
return {
|
|
285
|
-
class: 'construction',
|
|
286
|
-
code: highlightControlled
|
|
287
|
-
? 'controlled-highlighted-value-required'
|
|
288
|
-
: 'uncontrolled-highlighted-value-update',
|
|
289
|
-
message: highlightControlled
|
|
290
|
-
? 'Controlled calendar highlight sync requires highlightedValue.'
|
|
291
|
-
: 'Uncontrolled calendar highlight cannot be synchronized externally.',
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
return null;
|
|
183
|
+
function compareNullable(left, right) {
|
|
184
|
+
return left === null ? right === null ? 0 : -1 : right === null ? 1 : compareDateValues(left, right);
|
|
295
185
|
}
|
|
296
186
|
//# sourceMappingURL=calendar.js.map
|