@cocoar/vue-calendar 1.16.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/README.md +257 -0
- package/dist/__test-utils__/event-fixtures.d.ts +4 -0
- package/dist/__test-utils__/event-fixtures.d.ts.map +1 -0
- package/dist/builders/calendar-builder-internals.d.ts +14 -0
- package/dist/builders/calendar-builder-internals.d.ts.map +1 -0
- package/dist/builders/calendar-builder.d.ts +296 -0
- package/dist/builders/calendar-builder.d.ts.map +1 -0
- package/dist/builders/event-zone-hints.d.ts +20 -0
- package/dist/builders/event-zone-hints.d.ts.map +1 -0
- package/dist/builders/render-helpers.d.ts +19 -0
- package/dist/builders/render-helpers.d.ts.map +1 -0
- package/dist/builders/types.d.ts +175 -0
- package/dist/builders/types.d.ts.map +1 -0
- package/dist/components/CoarCalendar.vue.d.ts +150 -0
- package/dist/components/CoarCalendar.vue.d.ts.map +1 -0
- package/dist/components/CoarDisplayZoneSwitcher.vue.d.ts +28 -0
- package/dist/components/CoarDisplayZoneSwitcher.vue.d.ts.map +1 -0
- package/dist/components/VirtualizedSurface1DY.vue.d.ts +90 -0
- package/dist/components/VirtualizedSurface1DY.vue.d.ts.map +1 -0
- package/dist/components/VirtualizedSurface2D.vue.d.ts +71 -0
- package/dist/components/VirtualizedSurface2D.vue.d.ts.map +1 -0
- package/dist/components/internal/CoarEventDecorations.vue.d.ts +13 -0
- package/dist/components/internal/CoarEventDecorations.vue.d.ts.map +1 -0
- package/dist/components/internal/RenderEventFallback.d.ts +17 -0
- package/dist/components/internal/RenderEventFallback.d.ts.map +1 -0
- package/dist/components/internal/agenda/CoarAgendaDayHeader.vue.d.ts +54 -0
- package/dist/components/internal/agenda/CoarAgendaDayHeader.vue.d.ts.map +1 -0
- package/dist/components/internal/month/CoarMonthBar.vue.d.ts +80 -0
- package/dist/components/internal/month/CoarMonthBar.vue.d.ts.map +1 -0
- package/dist/components/internal/month/CoarMonthCell.vue.d.ts +74 -0
- package/dist/components/internal/month/CoarMonthCell.vue.d.ts.map +1 -0
- package/dist/components/internal/month/CoarMonthGrid.vue.d.ts +50 -0
- package/dist/components/internal/month/CoarMonthGrid.vue.d.ts.map +1 -0
- package/dist/components/internal/month/CoarMonthPill.vue.d.ts +83 -0
- package/dist/components/internal/month/CoarMonthPill.vue.d.ts.map +1 -0
- package/dist/components/internal/month/CoarMonthRow.vue.d.ts +44 -0
- package/dist/components/internal/month/CoarMonthRow.vue.d.ts.map +1 -0
- package/dist/components/internal/time-grid/CoarTimeGridAllDayBand.vue.d.ts +39 -0
- package/dist/components/internal/time-grid/CoarTimeGridAllDayBand.vue.d.ts.map +1 -0
- package/dist/components/internal/time-grid/CoarTimeGridColumn.vue.d.ts +44 -0
- package/dist/components/internal/time-grid/CoarTimeGridColumn.vue.d.ts.map +1 -0
- package/dist/components/internal/time-grid/CoarTimeGridHeader.vue.d.ts +44 -0
- package/dist/components/internal/time-grid/CoarTimeGridHeader.vue.d.ts.map +1 -0
- package/dist/components/internal/time-grid/CoarTimeGridNowMarker.vue.d.ts +18 -0
- package/dist/components/internal/time-grid/CoarTimeGridNowMarker.vue.d.ts.map +1 -0
- package/dist/composables/useA11yAnnouncer.d.ts +9 -0
- package/dist/composables/useA11yAnnouncer.d.ts.map +1 -0
- package/dist/composables/useCalendarDnd.d.ts +212 -0
- package/dist/composables/useCalendarDnd.d.ts.map +1 -0
- package/dist/composables/useCoarDrag.d.ts +97 -0
- package/dist/composables/useCoarDrag.d.ts.map +1 -0
- package/dist/composables/useMonthDnd.d.ts +89 -0
- package/dist/composables/useMonthDnd.d.ts.map +1 -0
- package/dist/composables/useMonthExpansion.d.ts +35 -0
- package/dist/composables/useMonthExpansion.d.ts.map +1 -0
- package/dist/composables/useTimeGridDnd.d.ts +104 -0
- package/dist/composables/useTimeGridDnd.d.ts.map +1 -0
- package/dist/composables/useViewWindow.d.ts +14 -0
- package/dist/composables/useViewWindow.d.ts.map +1 -0
- package/dist/core/agendaLayout.d.ts +47 -0
- package/dist/core/agendaLayout.d.ts.map +1 -0
- package/dist/core/dnd/move-math.d.ts +136 -0
- package/dist/core/dnd/move-math.d.ts.map +1 -0
- package/dist/core/dragHitTest.d.ts +74 -0
- package/dist/core/dragHitTest.d.ts.map +1 -0
- package/dist/core/eventIndex.d.ts +106 -0
- package/dist/core/eventIndex.d.ts.map +1 -0
- package/dist/core/index.d.ts +32 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/measurementCache.d.ts +87 -0
- package/dist/core/measurementCache.d.ts.map +1 -0
- package/dist/core/monthGridLayout.d.ts +68 -0
- package/dist/core/monthGridLayout.d.ts.map +1 -0
- package/dist/core/overlapLayout.d.ts +88 -0
- package/dist/core/overlapLayout.d.ts.map +1 -0
- package/dist/core/recurrence-public.d.ts +59 -0
- package/dist/core/recurrence-public.d.ts.map +1 -0
- package/dist/core/recurrence.d.ts +112 -0
- package/dist/core/recurrence.d.ts.map +1 -0
- package/dist/core/recurrenceWorker.d.ts +62 -0
- package/dist/core/recurrenceWorker.d.ts.map +1 -0
- package/dist/core/temporal.d.ts +214 -0
- package/dist/core/temporal.d.ts.map +1 -0
- package/dist/core/timeGridLayout.d.ts +109 -0
- package/dist/core/timeGridLayout.d.ts.map +1 -0
- package/dist/core/types.d.ts +211 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/viewWindow.d.ts +53 -0
- package/dist/core/viewWindow.d.ts.map +1 -0
- package/dist/core/virtualScroll.d.ts +91 -0
- package/dist/core/virtualScroll.d.ts.map +1 -0
- package/dist/core-DK63eHat.js +959 -0
- package/dist/core.js +2 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4221 -0
- package/dist/useAgendaView.d.ts +6 -0
- package/dist/useAgendaView.d.ts.map +1 -0
- package/dist/useCalendar.d.ts +6 -0
- package/dist/useCalendar.d.ts.map +1 -0
- package/dist/useDayView.d.ts +6 -0
- package/dist/useDayView.d.ts.map +1 -0
- package/dist/useMonthView.d.ts +6 -0
- package/dist/useMonthView.d.ts.map +1 -0
- package/dist/useWeekView.d.ts +6 -0
- package/dist/useWeekView.d.ts.map +1 -0
- package/dist/vue-calendar.css +2 -0
- package/package.json +68 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
2
|
+
import { CalendarEvent, RecurrenceExpansionWindow, RecurringSeries } from './types';
|
|
3
|
+
import { DstPolicy } from './dnd/move-math';
|
|
4
|
+
/**
|
|
5
|
+
* Expand a `RecurringSeries` into the concrete occurrences that fall
|
|
6
|
+
* within `window`, applying `dstPolicy` to any occurrence whose
|
|
7
|
+
* wall-time hits a DST gap or overlap in the series' source zone.
|
|
8
|
+
*
|
|
9
|
+
* **Inputs**
|
|
10
|
+
*
|
|
11
|
+
* - `series` — the rule + dtstart + optional duration / rdate / exdate.
|
|
12
|
+
* - `window` — inclusive-start / exclusive-end. Typically the
|
|
13
|
+
* calendar's `_visibleRange` plus a small overscan.
|
|
14
|
+
* - `dstPolicy` — required (C4). Same options as the drag pipeline.
|
|
15
|
+
*
|
|
16
|
+
* **Output**
|
|
17
|
+
*
|
|
18
|
+
* `CalendarEvent<TMeta>[]` where every occurrence:
|
|
19
|
+
* - shares the series' `id` (use `start` to distinguish).
|
|
20
|
+
* - has `start` typed identically to `series.dtstart` (timed → ZDT,
|
|
21
|
+
* all-day → PD).
|
|
22
|
+
* - has `start.timeZoneId === series.dtstart.timeZoneId` for timed
|
|
23
|
+
* series — the engine never collapses to UTC or to the calendar's
|
|
24
|
+
* display zone.
|
|
25
|
+
* - has `end` computed from `series.duration` if present.
|
|
26
|
+
* - has `meta` shallow-copied from `series.meta`.
|
|
27
|
+
*
|
|
28
|
+
* **Throws**
|
|
29
|
+
*
|
|
30
|
+
* Until Phase 4: a `TypeError` with an informative message. Consumers
|
|
31
|
+
* can rely on the type contract NOW; expansion arrives without an
|
|
32
|
+
* API change.
|
|
33
|
+
*
|
|
34
|
+
* After Phase 4 (planned): a `DstResolutionError` if any occurrence
|
|
35
|
+
* lands in a DST gap/overlap and `dstPolicy === 'reject'`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function expandSeries<TMeta extends Record<string, unknown> = Record<string, unknown>>(_series: RecurringSeries<TMeta>, _window: RecurrenceExpansionWindow, _dstPolicy: DstPolicy): CalendarEvent<TMeta>[];
|
|
38
|
+
/**
|
|
39
|
+
* Re-export for ergonomics — consumers usually `import { expandSeries }`
|
|
40
|
+
* alongside the types they're constructing.
|
|
41
|
+
*
|
|
42
|
+
* Session 2 also re-uses this constant in tests to assert the stub
|
|
43
|
+
* shape without duplicating the message.
|
|
44
|
+
*/
|
|
45
|
+
export declare const EXPAND_SERIES_NOT_IMPLEMENTED_MESSAGE = "[@cocoar/vue-calendar] expandSeries() is not implemented yet \u2014 the recurrence engine integration is Phase 4. The TYPE contract for RecurringSeries is enforced from Session 2 so your data layer can build against it now; expansion will become available without API changes.";
|
|
46
|
+
/**
|
|
47
|
+
* Type-only re-exports so consumers writing `import { ... } from '@cocoar/vue-calendar'`
|
|
48
|
+
* find the recurrence types alongside `expandSeries` without needing
|
|
49
|
+
* to know they were declared in `core/types.ts`.
|
|
50
|
+
*/
|
|
51
|
+
export type { RecurringSeries, RecurrencePattern, RecurrenceExpansionWindow, } from './types';
|
|
52
|
+
/**
|
|
53
|
+
* Re-exported `Temporal` for convenience when constructing series.
|
|
54
|
+
*
|
|
55
|
+
* Without it consumers would have to add a separate
|
|
56
|
+
* `@js-temporal/polyfill` import for `Temporal.ZonedDateTime.from(...)`.
|
|
57
|
+
*/
|
|
58
|
+
export type { Temporal };
|
|
59
|
+
//# sourceMappingURL=recurrence-public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence-public.d.ts","sourceRoot":"","sources":["../../src/core/recurrence-public.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EACV,aAAa,EACb,yBAAyB,EACzB,eAAe,EAChB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,YAAY,CAC1B,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAG/D,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC,EAE/B,OAAO,EAAE,yBAAyB,EAElC,UAAU,EAAE,SAAS,GACpB,aAAa,CAAC,KAAK,CAAC,EAAE,CAExB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qCAAqC,yRAAkB,CAAC;AAErE;;;;GAIG;AACH,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,SAAS,CAAC;AAEjB;;;;;GAKG;AACH,YAAY,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recurrence engine — main-thread API.
|
|
3
|
+
*
|
|
4
|
+
* Two paths sharing one request/response shape:
|
|
5
|
+
*
|
|
6
|
+
* - `expandSync` — runs `rrule-rust` in the calling thread.
|
|
7
|
+
* Cheapest for small workloads (single rule,
|
|
8
|
+
* one-shot expansion). Blocks the main thread.
|
|
9
|
+
*
|
|
10
|
+
* - `expandAsync` — dispatches to a long-lived worker. Cheapest
|
|
11
|
+
* for large workloads where main-thread blocking
|
|
12
|
+
* would jank the UI. Pays a postMessage round-
|
|
13
|
+
* trip (~ 1-2 ms) on top of the actual expansion.
|
|
14
|
+
*
|
|
15
|
+
* Spike E benchmarks both at four scales (W1-W4) and locks the
|
|
16
|
+
* auto-dispatch threshold — when does the worker round-trip beat
|
|
17
|
+
* in-thread? Per Spike B's measurements (`rrule-rust` warm path =
|
|
18
|
+
* 0.6 ms / expansion), the in-thread cost is much lower than the
|
|
19
|
+
* spike-plan hypothesis suggested, so the auto-dispatch threshold
|
|
20
|
+
* lands at higher series counts than originally estimated.
|
|
21
|
+
*
|
|
22
|
+
* Wire format is the same in both modes; consumers swap engines by
|
|
23
|
+
* choosing which function to call. A higher-level
|
|
24
|
+
* `<CoarCalendar :recurrence-engine="...">` prop in Phase 1 will
|
|
25
|
+
* pick automatically based on `series.length` against the locked
|
|
26
|
+
* threshold.
|
|
27
|
+
*/
|
|
28
|
+
export interface RecurrenceRequest {
|
|
29
|
+
rules: ReadonlyArray<{
|
|
30
|
+
seriesId: string;
|
|
31
|
+
rruleString: string;
|
|
32
|
+
}>;
|
|
33
|
+
/** Window start as unix-ms (absolute timestamp). */
|
|
34
|
+
windowStart: number;
|
|
35
|
+
/** Window end as unix-ms (absolute timestamp), exclusive-ish. */
|
|
36
|
+
windowEnd: number;
|
|
37
|
+
}
|
|
38
|
+
export interface RecurrenceRuleResult {
|
|
39
|
+
seriesId: string;
|
|
40
|
+
/** Unix-ms timestamps of every occurrence inside the window. */
|
|
41
|
+
timestamps: Float64Array;
|
|
42
|
+
}
|
|
43
|
+
export interface RecurrenceResponse {
|
|
44
|
+
results: RecurrenceRuleResult[];
|
|
45
|
+
/** Time spent in actual expansion (ms). Excludes worker round-trip. */
|
|
46
|
+
expansionMs: number;
|
|
47
|
+
/** Per-rule errors; empty on full success. */
|
|
48
|
+
errors: Array<{
|
|
49
|
+
seriesId: string;
|
|
50
|
+
message: string;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Synchronous in-thread expansion. Runs in the caller's thread; for
|
|
55
|
+
* large workloads (≥ threshold), prefer `expandAsync`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function expandSync(req: RecurrenceRequest): RecurrenceResponse;
|
|
58
|
+
/**
|
|
59
|
+
* Asynchronous expansion via a long-lived worker. The worker is
|
|
60
|
+
* lazily created on first use and reused for the lifetime of the
|
|
61
|
+
* page. Cold-start (~ 175 ms WASM init) hits the first call; warm
|
|
62
|
+
* calls cost ~ 1-2 ms postMessage round-trip plus the expansion
|
|
63
|
+
* time.
|
|
64
|
+
*/
|
|
65
|
+
export declare function expandAsync(req: RecurrenceRequest): Promise<RecurrenceResponse>;
|
|
66
|
+
/**
|
|
67
|
+
* Tear down the worker. Useful for tests or for apps that know
|
|
68
|
+
* recurrence won't be needed any more.
|
|
69
|
+
*/
|
|
70
|
+
export declare function shutdownRecurrenceWorker(): void;
|
|
71
|
+
export interface RecurrenceEngine {
|
|
72
|
+
/**
|
|
73
|
+
* Expand a batch of recurring rules over a window. The engine
|
|
74
|
+
* decides whether to run sync (in-thread) or async (worker)
|
|
75
|
+
* per-call; consumers always await regardless.
|
|
76
|
+
*/
|
|
77
|
+
expand(request: RecurrenceRequest): Promise<RecurrenceResponse>;
|
|
78
|
+
}
|
|
79
|
+
export interface DefaultRecurrenceEngineOptions {
|
|
80
|
+
/**
|
|
81
|
+
* Auto-dispatch threshold. Rules >= threshold → worker. Default
|
|
82
|
+
* 200, locked empirically in Phase 0 Spike E (W1 sync stays
|
|
83
|
+
* under one frame, W2+ blocks UI).
|
|
84
|
+
*/
|
|
85
|
+
threshold?: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Default engine: rrule-rust with auto-dispatch at the locked
|
|
89
|
+
* threshold (200 rules by default, configurable).
|
|
90
|
+
*/
|
|
91
|
+
export declare class DefaultRecurrenceEngine implements RecurrenceEngine {
|
|
92
|
+
private threshold;
|
|
93
|
+
constructor(opts?: DefaultRecurrenceEngineOptions);
|
|
94
|
+
expand(request: RecurrenceRequest): Promise<RecurrenceResponse>;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Forces every expansion through the synchronous in-thread path.
|
|
98
|
+
* Useful for tests (no worker setup) and SSR (no Worker API).
|
|
99
|
+
*/
|
|
100
|
+
export declare class SyncOnlyRecurrenceEngine implements RecurrenceEngine {
|
|
101
|
+
expand(request: RecurrenceRequest): Promise<RecurrenceResponse>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Forces every expansion through the worker. Useful for diagnostic
|
|
105
|
+
* purposes — never blocks the main thread, even for tiny inputs.
|
|
106
|
+
* Production consumers should prefer `DefaultRecurrenceEngine` so
|
|
107
|
+
* the small-batch fast path stays sync.
|
|
108
|
+
*/
|
|
109
|
+
export declare class WorkerOnlyRecurrenceEngine implements RecurrenceEngine {
|
|
110
|
+
expand(request: RecurrenceRequest): Promise<RecurrenceResponse>;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=recurrence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.d.ts","sourceRoot":"","sources":["../../src/core/recurrence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,UAAU,EAAE,YAAY,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD;AAgCD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,iBAAiB,GAAG,kBAAkB,CAErE;AAsCD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAO/E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAO/C;AAoBD,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,8BAA8B;IAC7C;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,GAAE,8BAAmC;IAI/C,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAMtE;AAED;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IACzD,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAGtE;AAED;;;;;GAKG;AACH,qBAAa,0BAA2B,YAAW,gBAAgB;IAC3D,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAGtE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recurrence expansion worker — runs `rrule-rust` off the main
|
|
3
|
+
* thread. Imported via Vite's `?worker` syntax; only this file
|
|
4
|
+
* actually executes in the worker context.
|
|
5
|
+
*
|
|
6
|
+
* The worker pays ~ 175 ms WASM init on first instantiation (per
|
|
7
|
+
* Spike B browser cold-start measurement). Subsequent expansions
|
|
8
|
+
* are sub-millisecond. The main thread keeps this worker alive for
|
|
9
|
+
* the lifetime of the calendar; warm-path expansions cost only the
|
|
10
|
+
* postMessage round-trip.
|
|
11
|
+
*
|
|
12
|
+
* Wire format (request → response):
|
|
13
|
+
*
|
|
14
|
+
* self.postMessage({
|
|
15
|
+
* id: 7,
|
|
16
|
+
* rules: [{ seriesId: 'standup', rruleString: 'DTSTART:...\nRRULE:...' }, …],
|
|
17
|
+
* windowStart: 1717200000000,
|
|
18
|
+
* windowEnd: 1719792000000,
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* self.onmessage = (e) => {
|
|
22
|
+
* // e.data: {
|
|
23
|
+
* // id: 7,
|
|
24
|
+
* // results: [{ seriesId, timestamps: Float64Array }, …],
|
|
25
|
+
* // expansionMs: 0.6,
|
|
26
|
+
* // errors: [{ seriesId, message }, …] // empty on success
|
|
27
|
+
* // }
|
|
28
|
+
* // Transferred: the Float64Array buffers themselves.
|
|
29
|
+
* };
|
|
30
|
+
*
|
|
31
|
+
* Float64Array is a Transferable. Sending 7.000 timestamps as a
|
|
32
|
+
* 56 KB ArrayBuffer is roughly free; structured-cloning the same
|
|
33
|
+
* count of plain-object dates would cost milliseconds.
|
|
34
|
+
*/
|
|
35
|
+
export interface RecurrenceRequest {
|
|
36
|
+
id: number;
|
|
37
|
+
rules: ReadonlyArray<{
|
|
38
|
+
seriesId: string;
|
|
39
|
+
rruleString: string;
|
|
40
|
+
}>;
|
|
41
|
+
windowStart: number;
|
|
42
|
+
windowEnd: number;
|
|
43
|
+
}
|
|
44
|
+
export interface RecurrenceRuleResult {
|
|
45
|
+
seriesId: string;
|
|
46
|
+
/**
|
|
47
|
+
* Unix-ms timestamps of every occurrence in the window. Always
|
|
48
|
+
* sent as a Float64Array whose `.buffer` is in the transferList.
|
|
49
|
+
*/
|
|
50
|
+
timestamps: Float64Array;
|
|
51
|
+
}
|
|
52
|
+
export interface RecurrenceResponse {
|
|
53
|
+
id: number;
|
|
54
|
+
results: RecurrenceRuleResult[];
|
|
55
|
+
/** Worker-side time spent on actual expansion, in milliseconds. */
|
|
56
|
+
expansionMs: number;
|
|
57
|
+
errors: Array<{
|
|
58
|
+
seriesId: string;
|
|
59
|
+
message: string;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=recurrenceWorker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrenceWorker.d.ts","sourceRoot":"","sources":["../../src/core/recurrenceWorker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,UAAU,EAAE,YAAY,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
2
|
+
export { Temporal };
|
|
3
|
+
/** 0 = Sun … 6 = Sat. Matches `Date.prototype.getDay()`. */
|
|
4
|
+
export type DayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
5
|
+
/**
|
|
6
|
+
* Convert Temporal's 1..7 (Mon..Sun) to the 0..6 (Sun..Sat)
|
|
7
|
+
* convention the calendar uses publicly.
|
|
8
|
+
*/
|
|
9
|
+
export declare function temporalDowToCalendarDow(isoDow: number): DayOfWeek;
|
|
10
|
+
/**
|
|
11
|
+
* Convert calendar 0..6 (Sun..Sat) to Temporal's 1..7 (Mon..Sun).
|
|
12
|
+
*/
|
|
13
|
+
export declare function calendarDowToTemporalDow(calDow: DayOfWeek): 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
14
|
+
export declare function detectFirstDayOfWeekFromLocale(locale: string): DayOfWeek;
|
|
15
|
+
/**
|
|
16
|
+
* Detect 12-vs-24-hour preference for a locale via Intl. Returns
|
|
17
|
+
* `true` for 12-hour locales (en-US), `false` for 24-hour
|
|
18
|
+
* (de-DE, fr-FR).
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectHour12FromLocale(locale: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The browser's IANA timezone, e.g. `'Europe/Vienna'`. Falls back to
|
|
23
|
+
* `'UTC'` on environments without `Intl.DateTimeFormat` (SSR / locked
|
|
24
|
+
* runtimes / very old browsers).
|
|
25
|
+
*
|
|
26
|
+
* **The fallback is the article-4 anti-pattern.** A UTC display zone
|
|
27
|
+
* for a Vienna user makes 09:00 wall-clock render as 11:00 in summer.
|
|
28
|
+
* To make this loud, we `console.warn` ONCE per process when the
|
|
29
|
+
* fallback fires — including in production, because the data
|
|
30
|
+
* corruption risk is identical in dev and prod (Article 8: don't lie
|
|
31
|
+
* about what's stored). Consumers who really do live in UTC should
|
|
32
|
+
* pass `'UTC'` explicitly to `builder.timezone('UTC')` to silence
|
|
33
|
+
* the warning.
|
|
34
|
+
*/
|
|
35
|
+
export declare function detectBrowserTimezone(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Article-9 helper: merge consumer-set verbosity / clock overrides
|
|
38
|
+
* into a per-call `Intl.DateTimeFormatOptions` literal. Intl is strict
|
|
39
|
+
* about combinations — `dateStyle` excludes the field-level options
|
|
40
|
+
* (`weekday`/`day`/`month`/`year`/`era`), and `timeStyle` excludes
|
|
41
|
+
* `hour`/`minute`/`second`/`fractionalSecondDigits`. This helper
|
|
42
|
+
* applies the overrides AND prunes the conflicting fields so callers
|
|
43
|
+
* just hand it the natural literal.
|
|
44
|
+
*
|
|
45
|
+
* buildFormatOptions(
|
|
46
|
+
* { weekday: 'short', day: 'numeric', month: 'short', timeZone: tz },
|
|
47
|
+
* { dateStyle: 'long', hour12: false },
|
|
48
|
+
* )
|
|
49
|
+
* // → { dateStyle: 'long', hour12: false, timeZone: tz }
|
|
50
|
+
*/
|
|
51
|
+
export interface FormatOverrides {
|
|
52
|
+
dateStyle?: 'full' | 'long' | 'medium' | 'short';
|
|
53
|
+
timeStyle?: 'full' | 'long' | 'medium' | 'short';
|
|
54
|
+
hour12?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export declare function buildFormatOptions(base: Intl.DateTimeFormatOptions, overrides: FormatOverrides | undefined): Intl.DateTimeFormatOptions;
|
|
57
|
+
/**
|
|
58
|
+
* Move `date` backwards (or stay) until it lands on the configured
|
|
59
|
+
* `firstDayOfWeek`. Idempotent.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* startOfWeek(2026-04-15 (Wed), 1) → 2026-04-13 (Mon)
|
|
63
|
+
* startOfWeek(2026-04-15 (Wed), 0) → 2026-04-12 (Sun)
|
|
64
|
+
*/
|
|
65
|
+
export declare function startOfWeek(date: Temporal.PlainDate, firstDayOfWeek: DayOfWeek): Temporal.PlainDate;
|
|
66
|
+
/**
|
|
67
|
+
* Last day of the week (one day before the next firstDayOfWeek).
|
|
68
|
+
*/
|
|
69
|
+
export declare function endOfWeek(date: Temporal.PlainDate, firstDayOfWeek: DayOfWeek): Temporal.PlainDate;
|
|
70
|
+
/** First day of the month containing `date`. */
|
|
71
|
+
export declare function startOfMonth(date: Temporal.PlainDate): Temporal.PlainDate;
|
|
72
|
+
/** Last day of the month containing `date`. */
|
|
73
|
+
export declare function endOfMonth(date: Temporal.PlainDate): Temporal.PlainDate;
|
|
74
|
+
/**
|
|
75
|
+
* ISO 8601 week number (1..53). Week 1 is the week containing the
|
|
76
|
+
* first Thursday of the year.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isoWeekNumber(date: Temporal.PlainDate): number;
|
|
79
|
+
/**
|
|
80
|
+
* 7 dates of the week containing `date`, starting at firstDayOfWeek.
|
|
81
|
+
*
|
|
82
|
+
* Used by week / day views.
|
|
83
|
+
*/
|
|
84
|
+
export declare function weekDates(date: Temporal.PlainDate, firstDayOfWeek: DayOfWeek): Temporal.PlainDate[];
|
|
85
|
+
/**
|
|
86
|
+
* Fixed 6 × 7 = 42-cell month grid: leading days from the previous
|
|
87
|
+
* month + the month's days + trailing days from the next month.
|
|
88
|
+
*
|
|
89
|
+
* Always 42 cells so the month view doesn't reflow when the month
|
|
90
|
+
* changes (a month spanning 4, 5, or 6 visual rows; we always
|
|
91
|
+
* render 6).
|
|
92
|
+
*
|
|
93
|
+
* @param yearMonth — month to render
|
|
94
|
+
* @param firstDayOfWeek — 0..6 calendar convention
|
|
95
|
+
*/
|
|
96
|
+
export declare function monthGridDates(yearMonth: Temporal.PlainYearMonth, firstDayOfWeek: DayOfWeek): Temporal.PlainDate[];
|
|
97
|
+
/**
|
|
98
|
+
* Localized weekday names ('Sun', 'Mon', …) for headings, in the
|
|
99
|
+
* order dictated by `firstDayOfWeek`.
|
|
100
|
+
*
|
|
101
|
+
* @param locale BCP-47, e.g. 'de-AT'
|
|
102
|
+
* @param firstDayOfWeek 0..6
|
|
103
|
+
* @param format 'long' | 'short' | 'narrow' — Intl.DateTimeFormat options
|
|
104
|
+
*/
|
|
105
|
+
export declare function localizedWeekdayNames(locale: string, firstDayOfWeek: DayOfWeek, format?: 'long' | 'short' | 'narrow'): string[];
|
|
106
|
+
/**
|
|
107
|
+
* Stable `YYYY-MM-DD` key, suitable for use in a `Map` for the
|
|
108
|
+
* event index. Same shape as `Temporal.PlainDate.toString()`.
|
|
109
|
+
*/
|
|
110
|
+
export declare function dateKey(date: Temporal.PlainDate): string;
|
|
111
|
+
/**
|
|
112
|
+
* Resolve an event's start to a `Temporal.PlainDate` (the "day" the
|
|
113
|
+
* event lives on for indexing purposes), in the supplied DISPLAY zone.
|
|
114
|
+
*
|
|
115
|
+
* - `PlainDate` → returned as-is (all-day events have no zone).
|
|
116
|
+
* - `ZonedDateTime` → re-zoned into `displayZone`, then truncated to
|
|
117
|
+
* the calendar day. Cross-zone events are bucketed by what the
|
|
118
|
+
* viewer actually sees.
|
|
119
|
+
*
|
|
120
|
+
* Used by the EventIndex to bucket events by day key.
|
|
121
|
+
*/
|
|
122
|
+
export declare function eventStartDateInZone(start: Temporal.ZonedDateTime | Temporal.PlainDate, displayZone: string): Temporal.PlainDate;
|
|
123
|
+
/** Today's date in the given IANA zone. */
|
|
124
|
+
export declare function todayInZone(zone: string): Temporal.PlainDate;
|
|
125
|
+
/** Current ZonedDateTime in the given IANA zone. */
|
|
126
|
+
export declare function nowInZone(zone: string): Temporal.ZonedDateTime;
|
|
127
|
+
/**
|
|
128
|
+
* DST policy mirror of the type in `dnd/move-math`. Re-declared here
|
|
129
|
+
* so `core/temporal.ts` stays import-graph-clean (move-math is
|
|
130
|
+
* downstream of temporal helpers, not the other way around).
|
|
131
|
+
*
|
|
132
|
+
* The values + semantics are identical; both files compile against
|
|
133
|
+
* the same Temporal `disambiguation` option.
|
|
134
|
+
*/
|
|
135
|
+
export type DstPolicy = 'compatible' | 'reject' | 'earlier' | 'later';
|
|
136
|
+
/**
|
|
137
|
+
* Wire shape for a scheduled time. Mirrors Article 8's recommended
|
|
138
|
+
* API contract: store the human's intent (`local + timeZoneId`)
|
|
139
|
+
* separately from the derived UTC instant (which the backend
|
|
140
|
+
* computes per Article 4's "store intent, derive math" rule).
|
|
141
|
+
*
|
|
142
|
+
* Field naming matches `Appointment.LocalStart` / `TimeZoneId`
|
|
143
|
+
* conventions used in Articles 6 + 7 (.NET / PostgreSQL chapters)
|
|
144
|
+
* so frontend ↔ backend DTOs line up without translation.
|
|
145
|
+
*/
|
|
146
|
+
export interface ScheduledTimeWire {
|
|
147
|
+
/**
|
|
148
|
+
* ISO-8601 local datetime, NO offset, NO `Z`:
|
|
149
|
+
* `'2026-06-05T10:00:00'`. The wall-clock value the user chose.
|
|
150
|
+
*/
|
|
151
|
+
local: string;
|
|
152
|
+
/** IANA timezone, e.g. `'Europe/Vienna'`. NOT an offset like `+02:00`
|
|
153
|
+
* (Article 4: offsets are snapshots, not meaning). */
|
|
154
|
+
timeZoneId: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Parse a wire `{ local, timeZoneId }` shape into a
|
|
158
|
+
* `Temporal.ZonedDateTime`, applying the caller's `dstPolicy` to
|
|
159
|
+
* resolve any DST gap or overlap on the local wall-time.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* const start = parseScheduledTime({
|
|
164
|
+
* local: '2026-06-05T10:00:00',
|
|
165
|
+
* timeZoneId: 'Europe/Vienna',
|
|
166
|
+
* });
|
|
167
|
+
* // → Temporal.ZonedDateTime in Europe/Vienna, intent preserved.
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* **Throws** `TypeError` if `timeZoneId` isn't a recognised IANA name
|
|
171
|
+
* (probes via `toInstant()` — same trick as `validateCalendarEvent`).
|
|
172
|
+
*
|
|
173
|
+
* **Throws** `RangeError` if `local` isn't a parseable ISO-8601
|
|
174
|
+
* datetime.
|
|
175
|
+
*
|
|
176
|
+
* **Throws** if `dstPolicy === 'reject'` and the local wall-time
|
|
177
|
+
* lands in a DST gap (Article 5 explicit-policy contract).
|
|
178
|
+
*/
|
|
179
|
+
export declare function parseScheduledTime(input: ScheduledTimeWire & {
|
|
180
|
+
dstPolicy?: DstPolicy;
|
|
181
|
+
}): Temporal.ZonedDateTime;
|
|
182
|
+
/**
|
|
183
|
+
* Parse a wire `'YYYY-MM-DD'` ISO date string into a
|
|
184
|
+
* `Temporal.PlainDate` — the all-day counterpart to
|
|
185
|
+
* `parseScheduledTime`.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* const dob = parsePlainDate('1990-03-15');
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* **Throws** `RangeError` if `iso` isn't a parseable date.
|
|
193
|
+
*/
|
|
194
|
+
export declare function parsePlainDate(iso: string): Temporal.PlainDate;
|
|
195
|
+
/**
|
|
196
|
+
* Format a `Temporal.ZonedDateTime` back into the wire shape — the
|
|
197
|
+
* round-trip companion to `parseScheduledTime`. Use when shipping a
|
|
198
|
+
* `CalendarEvent.start` to a backend that expects the
|
|
199
|
+
* `{ local, timeZoneId }` contract.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* const wire = formatScheduledTime(event.start);
|
|
204
|
+
* // → { local: '2026-06-05T10:00:00', timeZoneId: 'Europe/Vienna' }
|
|
205
|
+
* await fetch('/appointments', { method: 'POST', body: JSON.stringify({ start: wire }) });
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* **Round-trip property** (tested):
|
|
209
|
+
* `formatScheduledTime(parseScheduledTime(wire)) === wire` for any
|
|
210
|
+
* non-DST-edge wire input. DST-edge inputs round-trip into the
|
|
211
|
+
* unambiguous-after-policy value the engine resolved them to.
|
|
212
|
+
*/
|
|
213
|
+
export declare function formatScheduledTime(zdt: Temporal.ZonedDateTime): ScheduledTimeWire;
|
|
214
|
+
//# sourceMappingURL=temporal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/core/temporal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { CalendarEvent } from './types';
|
|
2
|
+
import { Temporal } from './temporal';
|
|
3
|
+
export interface PositionedEvent<TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
4
|
+
/** The event itself (flyweight; consumer can render it). */
|
|
5
|
+
event: CalendarEvent<TMeta>;
|
|
6
|
+
/** Lane within the day column. 0 is leftmost. */
|
|
7
|
+
lane: number;
|
|
8
|
+
/** Total lanes used in this day. width per lane = 1 / laneCount. */
|
|
9
|
+
laneCount: number;
|
|
10
|
+
/**
|
|
11
|
+
* Minutes from `dayStartHour * 60` to the event's visible start.
|
|
12
|
+
* `0` = event begins at the top of the time range.
|
|
13
|
+
*/
|
|
14
|
+
startMinutes: number;
|
|
15
|
+
/**
|
|
16
|
+
* Minutes from `dayStartHour * 60` to the event's visible end.
|
|
17
|
+
* Strictly greater than `startMinutes`. Always within
|
|
18
|
+
* `[0, (dayEndHour - dayStartHour) * 60]`.
|
|
19
|
+
*/
|
|
20
|
+
endMinutes: number;
|
|
21
|
+
/**
|
|
22
|
+
* True when the event was clipped at the top of the day range
|
|
23
|
+
* (its real start is before `dayStartHour`).
|
|
24
|
+
*/
|
|
25
|
+
clippedTop: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* True when the event was clipped at the bottom (real end is past
|
|
28
|
+
* `dayEndHour`).
|
|
29
|
+
*/
|
|
30
|
+
clippedBottom: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface DayLayoutOptions {
|
|
33
|
+
/** The day this layout is for. */
|
|
34
|
+
day: Temporal.PlainDate;
|
|
35
|
+
/** Visible hour range. `[6, 22]` = 6 AM to 10 PM. */
|
|
36
|
+
timeRange: [number, number];
|
|
37
|
+
/** IANA timezone for resolving timed events. */
|
|
38
|
+
timezone: string;
|
|
39
|
+
/**
|
|
40
|
+
* Optional event id that should always be placed on the
|
|
41
|
+
* RIGHTMOST lane (`laneCount - 1`) within its overlap component.
|
|
42
|
+
* Used during drag-preview so the dragged ghost stays anchored
|
|
43
|
+
* on the trailing edge regardless of which other events it
|
|
44
|
+
* transitively overlaps — keeps it from jumping side-to-side as
|
|
45
|
+
* the user moves the mouse across slots with different overlap
|
|
46
|
+
* shapes. Other events in the same component shift down by one
|
|
47
|
+
* lane to preserve the no-conflict invariant; events in
|
|
48
|
+
* unrelated components are untouched.
|
|
49
|
+
*/
|
|
50
|
+
priorityId?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Layout all timed events for a single day. Returns one
|
|
54
|
+
* `PositionedEvent` per event that intersects the visible time
|
|
55
|
+
* range, with lane assignments for overlap resolution.
|
|
56
|
+
*
|
|
57
|
+
* All-day events and events outside the time range are excluded;
|
|
58
|
+
* those belong to a separate all-day band, rendered above the time
|
|
59
|
+
* grid by week / day views.
|
|
60
|
+
*/
|
|
61
|
+
export declare function layoutDayEvents<TMeta extends Record<string, unknown> = Record<string, unknown>>(events: ReadonlyArray<CalendarEvent<TMeta>>, opts: DayLayoutOptions): PositionedEvent<TMeta>[];
|
|
62
|
+
/**
|
|
63
|
+
* An all-day event positioned within a visible-day-range. Used by
|
|
64
|
+
* the time grid's all-day band (above the hour grid) to render
|
|
65
|
+
* multi-day events as horizontal bars spanning multiple day-columns.
|
|
66
|
+
*/
|
|
67
|
+
export interface AllDayBar<TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
68
|
+
event: CalendarEvent<TMeta>;
|
|
69
|
+
/** Lane (vertical row inside the band). 0 = topmost. */
|
|
70
|
+
lane: number;
|
|
71
|
+
/** Total lanes used. Caller picks the band height from this. */
|
|
72
|
+
laneCount: number;
|
|
73
|
+
/** First column the bar covers, 0-indexed. Inclusive. */
|
|
74
|
+
startCol: number;
|
|
75
|
+
/** Last column the bar covers, 0-indexed. Inclusive. */
|
|
76
|
+
endCol: number;
|
|
77
|
+
/** True when the event extends earlier than `days[0]`. */
|
|
78
|
+
clippedStart: boolean;
|
|
79
|
+
/** True when the event extends later than `days[days.length-1]`. */
|
|
80
|
+
clippedEnd: boolean;
|
|
81
|
+
}
|
|
82
|
+
export interface AllDayBandOptions {
|
|
83
|
+
/** Days to render (one column each). Length = number of columns. */
|
|
84
|
+
days: ReadonlyArray<Temporal.PlainDate>;
|
|
85
|
+
/**
|
|
86
|
+
* Timezone used to bucket date-time events by local day. Date-only
|
|
87
|
+
* events are timezone-independent.
|
|
88
|
+
*/
|
|
89
|
+
timezone: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Lay out all-day + multi-day events for a week / day view's
|
|
93
|
+
* all-day band.
|
|
94
|
+
*
|
|
95
|
+
* Includes:
|
|
96
|
+
* - Events with `allDay: true`
|
|
97
|
+
* - Events with date-only `start` (no time component)
|
|
98
|
+
*
|
|
99
|
+
* Excludes (these go in the time grid):
|
|
100
|
+
* - Timed events that start AND end within a single visible day
|
|
101
|
+
* - Timed events with end-after-midnight (handled per-column by
|
|
102
|
+
* the time grid via clipping)
|
|
103
|
+
*
|
|
104
|
+
* For each included event, computes `[startCol, endCol]` clipped to
|
|
105
|
+
* the visible day range, runs `layoutOverlappingIntervals`, returns
|
|
106
|
+
* one `AllDayBar` per event.
|
|
107
|
+
*/
|
|
108
|
+
export declare function layoutAllDayBand<TMeta extends Record<string, unknown> = Record<string, unknown>>(events: ReadonlyArray<CalendarEvent<TMeta>>, opts: AllDayBandOptions): AllDayBar<TMeta>[];
|
|
109
|
+
//# sourceMappingURL=timeGridLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeGridLayout.d.ts","sourceRoot":"","sources":["../../src/core/timeGridLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAM7C,OAAO,EAAE,QAAQ,EAAW,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,eAAe,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC9F,4DAA4D;IAC5D,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,GAAG,EAAE,QAAQ,CAAC,SAAS,CAAC;IACxB,qDAAqD;IACrD,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7F,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAC3C,IAAI,EAAE,gBAAgB,GACrB,eAAe,CAAC,KAAK,CAAC,EAAE,CAyJ1B;AAMD;;;;GAIG;AACH,MAAM,WAAW,SAAS,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxF,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,YAAY,EAAE,OAAO,CAAC;IACtB,oEAAoE;IACpE,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACxC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9F,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAC3C,IAAI,EAAE,iBAAiB,GACtB,SAAS,CAAC,KAAK,CAAC,EAAE,CAiGpB"}
|