@gobrand/calendar-core 0.0.17 → 0.0.19
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/index.cjs +42 -26
- package/dist/index.d.cts +124 -33
- package/dist/index.d.ts +124 -33
- package/dist/index.js +42 -26
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -82,16 +82,6 @@ function goToToday() {
|
|
|
82
82
|
const today = import_polyfill.Temporal.Now.plainDateISO();
|
|
83
83
|
return { year: today.year, month: today.month };
|
|
84
84
|
}
|
|
85
|
-
function getWeekdays(weekStartsOn = 1, locale = "en-US", format = "short") {
|
|
86
|
-
const referenceDate = import_polyfill.Temporal.PlainDate.from("2023-01-02");
|
|
87
|
-
const days = [];
|
|
88
|
-
for (let i = 0; i < 7; i++) {
|
|
89
|
-
const offset = (weekStartsOn - 1 + i + 7) % 7;
|
|
90
|
-
const date = referenceDate.add({ days: offset });
|
|
91
|
-
days.push(date.toLocaleString(locale, { weekday: format }));
|
|
92
|
-
}
|
|
93
|
-
return days;
|
|
94
|
-
}
|
|
95
85
|
function getMonthName(month, locale = "en-US") {
|
|
96
86
|
return month.toPlainDate({ day: 1 }).toLocaleString(locale, { month: "long" });
|
|
97
87
|
}
|
|
@@ -187,6 +177,7 @@ function buildMonth(year, month, options) {
|
|
|
187
177
|
}
|
|
188
178
|
const dateKey = currentDate.toString();
|
|
189
179
|
weeks[weeks.length - 1].push({
|
|
180
|
+
id: `${yearMonth.toString()}-${dateKey}`,
|
|
190
181
|
date: currentDate,
|
|
191
182
|
isCurrentMonth: currentDate.month === month,
|
|
192
183
|
isToday: import_polyfill2.Temporal.PlainDate.compare(currentDate, today) === 0,
|
|
@@ -214,7 +205,7 @@ var import_polyfill3 = require("@js-temporal/polyfill");
|
|
|
214
205
|
function buildDay(date, options) {
|
|
215
206
|
const startHour = options?.startHour ?? 0;
|
|
216
207
|
const endHour = options?.endHour ?? 24;
|
|
217
|
-
const slotDuration = options?.slotDuration ??
|
|
208
|
+
const slotDuration = options?.slotDuration ?? 60;
|
|
218
209
|
const today = options?.today ?? import_polyfill3.Temporal.Now.plainDateISO();
|
|
219
210
|
const data = options?.data ?? [];
|
|
220
211
|
const accessor = options?.accessor;
|
|
@@ -228,6 +219,7 @@ function buildDay(date, options) {
|
|
|
228
219
|
}
|
|
229
220
|
}
|
|
230
221
|
const timeSlots = [];
|
|
222
|
+
const dateStr = date.toString();
|
|
231
223
|
let currentHour = startHour;
|
|
232
224
|
let currentMinute = 0;
|
|
233
225
|
while (currentHour < endHour) {
|
|
@@ -254,6 +246,7 @@ function buildDay(date, options) {
|
|
|
254
246
|
}
|
|
255
247
|
}
|
|
256
248
|
timeSlots.push({
|
|
249
|
+
id: `${dateStr}-${String(currentHour).padStart(2, "0")}:${String(currentMinute).padStart(2, "0")}`,
|
|
257
250
|
hour: currentHour,
|
|
258
251
|
minute: currentMinute,
|
|
259
252
|
time: slotStart,
|
|
@@ -266,6 +259,7 @@ function buildDay(date, options) {
|
|
|
266
259
|
}
|
|
267
260
|
}
|
|
268
261
|
return {
|
|
262
|
+
id: dateStr,
|
|
269
263
|
date,
|
|
270
264
|
isToday: import_polyfill3.Temporal.PlainDate.compare(date, today) === 0,
|
|
271
265
|
timeSlots,
|
|
@@ -312,6 +306,7 @@ function buildWeek(date, options) {
|
|
|
312
306
|
timeSlots = dayView.timeSlots;
|
|
313
307
|
}
|
|
314
308
|
days.push({
|
|
309
|
+
id: `${weekStart.toString()}-${dateKey}`,
|
|
315
310
|
date: currentDate,
|
|
316
311
|
isToday: import_polyfill4.Temporal.PlainDate.compare(currentDate, today) === 0,
|
|
317
312
|
items: itemsByDate.get(dateKey) ?? [],
|
|
@@ -384,8 +379,20 @@ function getDayDateRange(date, timeZone) {
|
|
|
384
379
|
return { start: startZoned, end: endZoned };
|
|
385
380
|
}
|
|
386
381
|
|
|
387
|
-
// src/
|
|
382
|
+
// src/utils/getWeekdays.ts
|
|
388
383
|
var import_polyfill6 = require("@js-temporal/polyfill");
|
|
384
|
+
function getWeekdays(weekStartsOn = 1, locale = "en-US", format = "short") {
|
|
385
|
+
const sunday = import_polyfill6.Temporal.PlainDate.from("2023-01-01");
|
|
386
|
+
const days = [];
|
|
387
|
+
for (let i = 0; i < 7; i++) {
|
|
388
|
+
const date = sunday.add({ days: (weekStartsOn + i) % 7 });
|
|
389
|
+
days.push(date.toLocaleString(locale, { weekday: format }));
|
|
390
|
+
}
|
|
391
|
+
return days;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// src/core/calendar.ts
|
|
395
|
+
var import_polyfill7 = require("@js-temporal/polyfill");
|
|
389
396
|
var import_store = require("@tanstack/store");
|
|
390
397
|
function computeDateRange(view, referenceDate, timeZone, weekStartsOn = 1) {
|
|
391
398
|
let start;
|
|
@@ -410,22 +417,22 @@ function computeDateRange(view, referenceDate, timeZone, weekStartsOn = 1) {
|
|
|
410
417
|
}
|
|
411
418
|
const startZoned = start.toZonedDateTime({
|
|
412
419
|
timeZone,
|
|
413
|
-
plainTime:
|
|
420
|
+
plainTime: import_polyfill7.Temporal.PlainTime.from("00:00:00")
|
|
414
421
|
});
|
|
415
422
|
const endZoned = end.toZonedDateTime({
|
|
416
423
|
timeZone,
|
|
417
|
-
plainTime:
|
|
424
|
+
plainTime: import_polyfill7.Temporal.PlainTime.from("23:59:59.999")
|
|
418
425
|
});
|
|
419
426
|
return { start: startZoned, end: endZoned };
|
|
420
427
|
}
|
|
421
428
|
function createCalendar(options) {
|
|
422
429
|
const configuredViews = Object.keys(options.views);
|
|
423
430
|
const defaultView = configuredViews[0];
|
|
424
|
-
const timeZone = options.timeZone ||
|
|
431
|
+
const timeZone = options.timeZone || import_polyfill7.Temporal.Now.timeZoneId();
|
|
425
432
|
const monthView = options.views.month;
|
|
426
433
|
const weekView = options.views.week;
|
|
427
434
|
const weekStartsOn = monthView?.weekStartsOn ?? weekView?.weekStartsOn ?? 1;
|
|
428
|
-
const initialReferenceDate = options.state?.referenceDate ||
|
|
435
|
+
const initialReferenceDate = options.state?.referenceDate || import_polyfill7.Temporal.Now.plainDateISO();
|
|
429
436
|
const initialView = options.state?.currentView || defaultView;
|
|
430
437
|
const initialDateRange = computeDateRange(
|
|
431
438
|
initialView,
|
|
@@ -450,18 +457,18 @@ function createCalendar(options) {
|
|
|
450
457
|
dateRange: initialDateRange,
|
|
451
458
|
...resolvedOptions.state
|
|
452
459
|
});
|
|
453
|
-
const getMonthImpl = () => {
|
|
460
|
+
const getMonthImpl = (data = []) => {
|
|
454
461
|
const state = store.state;
|
|
455
462
|
const { year, month } = state.referenceDate;
|
|
456
463
|
const monthView2 = _options.views.month;
|
|
457
464
|
if (!monthView2) throw new Error("Month view not configured");
|
|
458
465
|
return buildMonth(year, month, {
|
|
459
466
|
weekStartsOn: monthView2.weekStartsOn,
|
|
460
|
-
data
|
|
467
|
+
data,
|
|
461
468
|
accessor: monthView2.accessor
|
|
462
469
|
});
|
|
463
470
|
};
|
|
464
|
-
const getWeekImpl = () => {
|
|
471
|
+
const getWeekImpl = (data = []) => {
|
|
465
472
|
const state = store.state;
|
|
466
473
|
const weekView2 = _options.views.week;
|
|
467
474
|
if (!weekView2) throw new Error("Week view not configured");
|
|
@@ -470,11 +477,11 @@ function createCalendar(options) {
|
|
|
470
477
|
startHour: weekView2.startHour,
|
|
471
478
|
endHour: weekView2.endHour,
|
|
472
479
|
slotDuration: weekView2.slotDuration,
|
|
473
|
-
data
|
|
480
|
+
data,
|
|
474
481
|
accessor: weekView2.accessor
|
|
475
482
|
});
|
|
476
483
|
};
|
|
477
|
-
const getDayImpl = () => {
|
|
484
|
+
const getDayImpl = (data = []) => {
|
|
478
485
|
const state = store.state;
|
|
479
486
|
const dayView = _options.views.day;
|
|
480
487
|
if (!dayView) throw new Error("Day view not configured");
|
|
@@ -482,7 +489,7 @@ function createCalendar(options) {
|
|
|
482
489
|
startHour: dayView.startHour,
|
|
483
490
|
endHour: dayView.endHour,
|
|
484
491
|
slotDuration: dayView.slotDuration,
|
|
485
|
-
data
|
|
492
|
+
data,
|
|
486
493
|
accessor: dayView.accessor
|
|
487
494
|
});
|
|
488
495
|
};
|
|
@@ -510,7 +517,7 @@ function createCalendar(options) {
|
|
|
510
517
|
};
|
|
511
518
|
const nextMonthImpl = () => {
|
|
512
519
|
setStateImpl((old) => {
|
|
513
|
-
const current =
|
|
520
|
+
const current = import_polyfill7.Temporal.PlainYearMonth.from({
|
|
514
521
|
year: old.referenceDate.year,
|
|
515
522
|
month: old.referenceDate.month
|
|
516
523
|
});
|
|
@@ -522,7 +529,7 @@ function createCalendar(options) {
|
|
|
522
529
|
};
|
|
523
530
|
const previousMonthImpl = () => {
|
|
524
531
|
setStateImpl((old) => {
|
|
525
|
-
const current =
|
|
532
|
+
const current = import_polyfill7.Temporal.PlainYearMonth.from({
|
|
526
533
|
year: old.referenceDate.year,
|
|
527
534
|
month: old.referenceDate.month
|
|
528
535
|
});
|
|
@@ -607,7 +614,7 @@ function createCalendar(options) {
|
|
|
607
614
|
previousMonth: previousMonthImpl,
|
|
608
615
|
goToMonth(year, month) {
|
|
609
616
|
setStateImpl(() => ({
|
|
610
|
-
referenceDate:
|
|
617
|
+
referenceDate: import_polyfill7.Temporal.PlainDate.from({ year, month, day: 1 })
|
|
611
618
|
}));
|
|
612
619
|
},
|
|
613
620
|
nextWeek: nextWeekImpl,
|
|
@@ -616,7 +623,7 @@ function createCalendar(options) {
|
|
|
616
623
|
previousDay: previousDayImpl,
|
|
617
624
|
goToToday() {
|
|
618
625
|
setStateImpl(() => ({
|
|
619
|
-
referenceDate:
|
|
626
|
+
referenceDate: import_polyfill7.Temporal.Now.plainDateISO()
|
|
620
627
|
}));
|
|
621
628
|
},
|
|
622
629
|
goToDate(date) {
|
|
@@ -667,6 +674,15 @@ function createCalendar(options) {
|
|
|
667
674
|
get dateRange() {
|
|
668
675
|
return store.state.dateRange;
|
|
669
676
|
},
|
|
677
|
+
getDateRange(view) {
|
|
678
|
+
const effectiveView = view ?? store.state.currentView ?? defaultView;
|
|
679
|
+
return computeDateRange(
|
|
680
|
+
effectiveView,
|
|
681
|
+
store.state.referenceDate,
|
|
682
|
+
timeZone,
|
|
683
|
+
weekStartsOn
|
|
684
|
+
);
|
|
685
|
+
},
|
|
670
686
|
get options() {
|
|
671
687
|
return _options;
|
|
672
688
|
},
|
package/dist/index.d.cts
CHANGED
|
@@ -7,6 +7,8 @@ type CalendarAccessor<TItem> = {
|
|
|
7
7
|
getEnd?: (item: TItem) => Temporal.ZonedDateTime;
|
|
8
8
|
};
|
|
9
9
|
type CalendarDay<TItem = unknown> = {
|
|
10
|
+
/** Unique identifier for this day within the view context. Use as React/Vue key. */
|
|
11
|
+
id: string;
|
|
10
12
|
date: Temporal.PlainDate;
|
|
11
13
|
isCurrentMonth: boolean;
|
|
12
14
|
isToday: boolean;
|
|
@@ -18,6 +20,8 @@ type CalendarMonth<TItem = unknown> = {
|
|
|
18
20
|
month: Temporal.PlainYearMonth;
|
|
19
21
|
};
|
|
20
22
|
type WeekDay<TItem = unknown> = {
|
|
23
|
+
/** Unique identifier for this day within the view context. Use as React/Vue key. */
|
|
24
|
+
id: string;
|
|
21
25
|
date: Temporal.PlainDate;
|
|
22
26
|
isToday: boolean;
|
|
23
27
|
items: TItem[];
|
|
@@ -29,12 +33,16 @@ type CalendarWeekView<TItem = unknown> = {
|
|
|
29
33
|
weekEnd: Temporal.PlainDate;
|
|
30
34
|
};
|
|
31
35
|
type TimeSlot<TItem = unknown> = {
|
|
36
|
+
/** Unique identifier for this time slot. Use as React/Vue key. */
|
|
37
|
+
id: string;
|
|
32
38
|
hour: number;
|
|
33
39
|
minute: number;
|
|
34
40
|
time: Temporal.PlainTime;
|
|
35
41
|
items: TItem[];
|
|
36
42
|
};
|
|
37
43
|
type CalendarDayView<TItem = unknown> = {
|
|
44
|
+
/** Unique identifier for this day view. Use as React/Vue key. */
|
|
45
|
+
id: string;
|
|
38
46
|
date: Temporal.PlainDate;
|
|
39
47
|
isToday: boolean;
|
|
40
48
|
timeSlots: TimeSlot<TItem>[];
|
|
@@ -73,17 +81,16 @@ type CalendarViewOptions<TItem> = {
|
|
|
73
81
|
day?: DayViewOptions<TItem>;
|
|
74
82
|
};
|
|
75
83
|
type CalendarOptions<TItem> = {
|
|
76
|
-
data: TItem[];
|
|
77
84
|
views: CalendarViewOptions<TItem>;
|
|
78
85
|
timeZone?: 'UTC' | string;
|
|
79
86
|
state?: Partial<CalendarState>;
|
|
80
|
-
onStateChange?: (
|
|
87
|
+
onStateChange?: (state: CalendarState) => void;
|
|
81
88
|
};
|
|
82
89
|
type HasView<Options, View extends 'month' | 'week' | 'day'> = Options extends {
|
|
83
90
|
views: infer V;
|
|
84
91
|
} ? V extends Record<View, unknown> ? V[View] extends undefined ? false : true : false : false;
|
|
85
92
|
type MonthMethods<TItem, TOptions> = HasView<TOptions, 'month'> extends true ? {
|
|
86
|
-
getMonth(): CalendarMonth<TItem>;
|
|
93
|
+
getMonth(data?: TItem[]): CalendarMonth<TItem>;
|
|
87
94
|
nextMonth(): void;
|
|
88
95
|
previousMonth(): void;
|
|
89
96
|
goToMonth(year: number, month: number): void;
|
|
@@ -94,7 +101,7 @@ type MonthMethods<TItem, TOptions> = HasView<TOptions, 'month'> extends true ? {
|
|
|
94
101
|
goToMonth?: never;
|
|
95
102
|
};
|
|
96
103
|
type WeekMethods<TItem, TOptions> = HasView<TOptions, 'week'> extends true ? {
|
|
97
|
-
getWeek(): CalendarWeekView<TItem>;
|
|
104
|
+
getWeek(data?: TItem[]): CalendarWeekView<TItem>;
|
|
98
105
|
nextWeek(): void;
|
|
99
106
|
previousWeek(): void;
|
|
100
107
|
} : {
|
|
@@ -103,7 +110,7 @@ type WeekMethods<TItem, TOptions> = HasView<TOptions, 'week'> extends true ? {
|
|
|
103
110
|
previousWeek?: never;
|
|
104
111
|
};
|
|
105
112
|
type DayMethods<TItem, TOptions> = HasView<TOptions, 'day'> extends true ? {
|
|
106
|
-
getDay(): CalendarDayView<TItem>;
|
|
113
|
+
getDay(data?: TItem[]): CalendarDayView<TItem>;
|
|
107
114
|
nextDay(): void;
|
|
108
115
|
previousDay(): void;
|
|
109
116
|
} : {
|
|
@@ -126,6 +133,7 @@ type BaseCalendarMethods<Options> = {
|
|
|
126
133
|
currentView: ValidViews<Options>;
|
|
127
134
|
setCurrentView(view: ValidViews<Options>): void;
|
|
128
135
|
dateRange: DateRange;
|
|
136
|
+
getDateRange(view?: ValidViews<Options>): DateRange;
|
|
129
137
|
options: Options;
|
|
130
138
|
setOptions(updater: (old: Options) => Options): void;
|
|
131
139
|
store: _tanstack_store.Store<CalendarState>;
|
|
@@ -133,71 +141,145 @@ type BaseCalendarMethods<Options> = {
|
|
|
133
141
|
hasWeekView(): boolean;
|
|
134
142
|
hasDayView(): boolean;
|
|
135
143
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Unified calendar type with conditional methods based on configured views.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* // Calendar with specific options - methods are conditional
|
|
149
|
+
* const calendar = createCalendar<Post, typeof options>(options);
|
|
150
|
+
* calendar.getMonth([]); // Only available if month view configured
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* // Generic calendar type - all methods available
|
|
154
|
+
* type AnyPostCalendar = Calendar<Post>;
|
|
155
|
+
*/
|
|
156
|
+
type Calendar<TItem, TOptions extends CalendarOptions<TItem> = CalendarOptions<TItem>> = BaseCalendarMethods<TOptions> & MonthMethods<TItem, TOptions> & WeekMethods<TItem, TOptions> & DayMethods<TItem, TOptions>;
|
|
157
|
+
/**
|
|
158
|
+
* Calendar instance with all view methods available and typed items.
|
|
159
|
+
* Use this for contexts where the specific view configuration is unknown at compile time,
|
|
160
|
+
* but you still want type-safe item data.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* // In React context - store with unknown, consume with specific type
|
|
164
|
+
* const context = createContext<CalendarInstance<unknown> | null>(null);
|
|
165
|
+
*
|
|
166
|
+
* // Consumer gets typed data
|
|
167
|
+
* function useCalendar<TItem>(): CalendarInstance<TItem> {
|
|
168
|
+
* return useContext(context) as CalendarInstance<TItem>;
|
|
169
|
+
* }
|
|
170
|
+
*/
|
|
171
|
+
type CalendarInstance<TItem = unknown> = {
|
|
172
|
+
getMonth(data?: TItem[]): CalendarMonth<TItem>;
|
|
173
|
+
getWeek(data?: TItem[]): CalendarWeekView<TItem>;
|
|
174
|
+
getDay(data?: TItem[]): CalendarDayView<TItem>;
|
|
175
|
+
getTitle(view?: ViewType, locales?: Temporal.LocalesArgument, options?: globalThis.Intl.DateTimeFormatOptions): string;
|
|
176
|
+
getState(): CalendarState;
|
|
177
|
+
setState(updater: CalendarState | ((old: CalendarState) => Partial<CalendarState>)): void;
|
|
178
|
+
goToToday(): void;
|
|
179
|
+
goToDate(date: Temporal.PlainDate): void;
|
|
180
|
+
next(view?: ViewType): void;
|
|
181
|
+
previous(view?: ViewType): void;
|
|
182
|
+
views: ReadonlyArray<string>;
|
|
183
|
+
currentView: string;
|
|
184
|
+
setCurrentView(view: string): void;
|
|
185
|
+
dateRange: DateRange;
|
|
186
|
+
getDateRange(view?: ViewType): DateRange;
|
|
187
|
+
options: CalendarOptions<TItem>;
|
|
188
|
+
setOptions(updater: (old: CalendarOptions<TItem>) => CalendarOptions<TItem>): void;
|
|
189
|
+
store: _tanstack_store.Store<CalendarState>;
|
|
190
|
+
nextMonth(): void;
|
|
191
|
+
previousMonth(): void;
|
|
192
|
+
goToMonth(year: number, month: number): void;
|
|
193
|
+
nextWeek(): void;
|
|
194
|
+
previousWeek(): void;
|
|
195
|
+
nextDay(): void;
|
|
196
|
+
previousDay(): void;
|
|
197
|
+
hasMonthView(): boolean;
|
|
198
|
+
hasWeekView(): boolean;
|
|
199
|
+
hasDayView(): boolean;
|
|
139
200
|
};
|
|
140
|
-
type Calendar<TItem, TOptionsOrViews = CalendarOptions<TItem>> = TOptionsOrViews extends CalendarOptions<TItem> ? BaseCalendarMethods<TOptionsOrViews> & MonthMethods<TItem, TOptionsOrViews> & WeekMethods<TItem, TOptionsOrViews> & DayMethods<TItem, TOptionsOrViews> : TOptionsOrViews extends CalendarViewOptions<TItem> ? BaseCalendarMethods<ViewsToOptions<TItem, TOptionsOrViews>> & MonthMethods<TItem, ViewsToOptions<TItem, TOptionsOrViews>> & WeekMethods<TItem, ViewsToOptions<TItem, TOptionsOrViews>> & DayMethods<TItem, ViewsToOptions<TItem, TOptionsOrViews>> : BaseCalendarMethods<CalendarOptions<TItem>> & MonthMethods<TItem, CalendarOptions<TItem>> & WeekMethods<TItem, CalendarOptions<TItem>> & DayMethods<TItem, CalendarOptions<TItem>>;
|
|
141
|
-
type InferViewNames<V extends CalendarViewOptions<unknown>> = keyof V & string;
|
|
142
|
-
type InferViewConfig<V extends CalendarViewOptions<unknown>, Name extends keyof V> = V[Name] extends infer Config ? {
|
|
143
|
-
name: Name;
|
|
144
|
-
config: Config;
|
|
145
|
-
} : never;
|
|
146
201
|
/**
|
|
147
|
-
* Extract the item type from a Calendar
|
|
202
|
+
* Extract the item type from a Calendar's options
|
|
148
203
|
* @example type Item = CalendarItemType<typeof calendar>; // Post
|
|
149
204
|
*/
|
|
150
|
-
type CalendarItemType<C extends
|
|
205
|
+
type CalendarItemType<C extends CalendarInstance> = C['options'] extends CalendarOptions<infer TItem> ? TItem : never;
|
|
151
206
|
/**
|
|
152
207
|
* Extract the views configuration from a Calendar type
|
|
153
208
|
* @example type Views = CalendarViewsConfig<typeof calendar>;
|
|
154
209
|
*/
|
|
155
|
-
type CalendarViewsConfig<C extends
|
|
210
|
+
type CalendarViewsConfig<C extends CalendarInstance> = C['options'] extends {
|
|
156
211
|
views: infer V;
|
|
157
|
-
} ? V :
|
|
212
|
+
} ? V : never;
|
|
158
213
|
/**
|
|
159
214
|
* Check if a Calendar has a specific view configured
|
|
160
215
|
* @example type HasMonth = HasViewType<typeof calendar, 'month'>; // true | false
|
|
161
216
|
*/
|
|
162
|
-
type HasViewType<C extends
|
|
217
|
+
type HasViewType<C extends CalendarInstance, V extends 'month' | 'week' | 'day'> = C['options'] extends CalendarOptions<infer TItem> ? HasView<C['options'], V> : false;
|
|
163
218
|
/**
|
|
164
219
|
* Extract valid view names as a union from a Calendar
|
|
165
220
|
* @example type Views = ValidViewNames<typeof calendar>; // 'month' | 'week'
|
|
166
221
|
*/
|
|
167
|
-
type ValidViewNames<C extends
|
|
168
|
-
/**
|
|
169
|
-
* Extract the item type from CalendarOptions before creating a calendar
|
|
170
|
-
* @example type Item = ItemTypeFromOptions<typeof options>; // Post
|
|
171
|
-
*/
|
|
172
|
-
type ItemTypeFromOptions<O extends CalendarOptions<any>> = O extends CalendarOptions<infer TItem> ? TItem : never;
|
|
222
|
+
type ValidViewNames<C extends CalendarInstance> = C['options'] extends CalendarOptions<infer TItem> ? ValidViews<C['options']> : never;
|
|
173
223
|
/**
|
|
174
224
|
* Base props for components that receive a Calendar
|
|
175
225
|
* @example
|
|
176
|
-
* function MyComponent<C extends
|
|
226
|
+
* function MyComponent<C extends CalendarInstance>(
|
|
177
227
|
* props: CalendarComponentProps<C>
|
|
178
228
|
* ) { ... }
|
|
179
229
|
*/
|
|
180
|
-
type CalendarComponentProps<C extends
|
|
230
|
+
type CalendarComponentProps<C extends CalendarInstance> = {
|
|
181
231
|
calendar: C;
|
|
182
232
|
};
|
|
183
233
|
/**
|
|
184
234
|
* Require that a Calendar has month view configured
|
|
185
235
|
* @example
|
|
186
|
-
* function MonthView<C extends
|
|
236
|
+
* function MonthView<C extends CalendarInstance>(
|
|
187
237
|
* props: { calendar: RequireMonthView<C> }
|
|
188
238
|
* ) {
|
|
189
239
|
* // calendar.getMonth() is guaranteed to exist
|
|
190
240
|
* }
|
|
191
241
|
*/
|
|
192
|
-
type RequireMonthView<C extends
|
|
242
|
+
type RequireMonthView<C extends CalendarInstance> = HasViewType<C, 'month'> extends true ? C : never;
|
|
193
243
|
/**
|
|
194
244
|
* Require that a Calendar has week view configured
|
|
195
245
|
*/
|
|
196
|
-
type RequireWeekView<C extends
|
|
246
|
+
type RequireWeekView<C extends CalendarInstance> = HasViewType<C, 'week'> extends true ? C : never;
|
|
197
247
|
/**
|
|
198
248
|
* Require that a Calendar has day view configured
|
|
199
249
|
*/
|
|
200
|
-
type RequireDayView<C extends
|
|
250
|
+
type RequireDayView<C extends CalendarInstance> = HasViewType<C, 'day'> extends true ? C : never;
|
|
251
|
+
/**
|
|
252
|
+
* Built-in view types
|
|
253
|
+
*/
|
|
254
|
+
type ViewType = 'month' | 'week' | 'day';
|
|
255
|
+
/**
|
|
256
|
+
* Discriminated union of all view results
|
|
257
|
+
*/
|
|
258
|
+
type ViewResult<TItem> = {
|
|
259
|
+
type: 'month';
|
|
260
|
+
data: CalendarMonth<TItem>;
|
|
261
|
+
} | {
|
|
262
|
+
type: 'week';
|
|
263
|
+
data: CalendarWeekView<TItem>;
|
|
264
|
+
} | {
|
|
265
|
+
type: 'day';
|
|
266
|
+
data: CalendarDayView<TItem>;
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Conditional type that narrows ViewResult based on view name
|
|
270
|
+
* - If V is a specific view type, returns that specific result
|
|
271
|
+
* - If V is undefined, returns the full discriminated union
|
|
272
|
+
*/
|
|
273
|
+
type ViewResultFor<TItem, V extends ViewType | undefined> = V extends 'month' ? {
|
|
274
|
+
type: 'month';
|
|
275
|
+
data: CalendarMonth<TItem>;
|
|
276
|
+
} : V extends 'week' ? {
|
|
277
|
+
type: 'week';
|
|
278
|
+
data: CalendarWeekView<TItem>;
|
|
279
|
+
} : V extends 'day' ? {
|
|
280
|
+
type: 'day';
|
|
281
|
+
data: CalendarDayView<TItem>;
|
|
282
|
+
} : ViewResult<TItem>;
|
|
201
283
|
|
|
202
284
|
declare function functionalUpdate<T>(updater: T | ((old: T) => T), input: T): T;
|
|
203
285
|
declare function createCalendarAccessor<T, A extends CalendarAccessor<T> = CalendarAccessor<T>>(accessor: A): A;
|
|
@@ -211,7 +293,6 @@ declare function goToToday(): {
|
|
|
211
293
|
year: number;
|
|
212
294
|
month: number;
|
|
213
295
|
};
|
|
214
|
-
declare function getWeekdays(weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6, locale?: string | string[], format?: 'short' | 'long' | 'narrow'): string[];
|
|
215
296
|
declare function getMonthName(month: Temporal.PlainYearMonth, locale?: string): string;
|
|
216
297
|
declare function formatTime(time: Temporal.PlainTime, locale?: string): string;
|
|
217
298
|
declare function getTimeSlotHeight(slotDuration: number, hourHeight: number): number;
|
|
@@ -292,6 +373,16 @@ declare function getWeekDateRange(date: Temporal.PlainDate, timeZone: string, op
|
|
|
292
373
|
*/
|
|
293
374
|
declare function getDayDateRange(date: Temporal.PlainDate, timeZone: string): DateRange;
|
|
294
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Returns an array of weekday names starting from the specified day.
|
|
378
|
+
*
|
|
379
|
+
* @param weekStartsOn - Day the week starts on (0=Sunday, 1=Monday, ..., 6=Saturday). Defaults to 1 (Monday).
|
|
380
|
+
* @param locale - Locale for formatting weekday names. Defaults to 'en-US'.
|
|
381
|
+
* @param format - Format for weekday names: 'short' (Mon), 'long' (Monday), or 'narrow' (M). Defaults to 'short'.
|
|
382
|
+
* @returns Array of 7 weekday names starting from weekStartsOn.
|
|
383
|
+
*/
|
|
384
|
+
declare function getWeekdays(weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6, locale?: string | string[], format?: 'short' | 'long' | 'narrow'): string[];
|
|
385
|
+
|
|
295
386
|
declare function createCalendar<TItem, TOptions extends CalendarOptions<TItem>>(options: TOptions): Calendar<TItem, TOptions>;
|
|
296
387
|
|
|
297
388
|
declare function createCalendarViews<TItem>(): <const TViews extends {
|
|
@@ -300,4 +391,4 @@ declare function createCalendarViews<TItem>(): <const TViews extends {
|
|
|
300
391
|
day?: DayViewOptions<TItem>;
|
|
301
392
|
}>(views: TViews) => TViews;
|
|
302
393
|
|
|
303
|
-
export { type Calendar, type CalendarAccessor, type CalendarComponentProps, type CalendarDay, type CalendarDayView, type CalendarItemType, type CalendarMonth, type CalendarOptions, type CalendarState, type CalendarViewOptions, type CalendarViewsConfig, type CalendarWeek, type CalendarWeekView, type DateRange, type DateRangeBounds, type DayViewOptions, type HasViewType, type
|
|
394
|
+
export { type Calendar, type CalendarAccessor, type CalendarComponentProps, type CalendarDay, type CalendarDayView, type CalendarInstance, type CalendarItemType, type CalendarMonth, type CalendarOptions, type CalendarState, type CalendarViewOptions, type CalendarViewsConfig, type CalendarWeek, type CalendarWeekView, type DateRange, type DateRangeBounds, type DayViewOptions, type HasViewType, type MonthViewOptions, type RequireDayView, type RequireMonthView, type RequireWeekView, type TimeSlot, type Updater, type ValidViewNames, type ViewResult, type ViewResultFor, type ViewType, type WeekDay, type WeekViewOptions, buildDay, buildMonth, buildWeek, convertToTimezone, createCalendar, createCalendarAccessor, createCalendarViews, createZonedDateTime, formatTime, functionalUpdate, getCurrentTimeZone, getDayDateRange, getDayRange, getEventPosition, getMonthDateRange, getMonthName, getMonthRange, getTimeSlotHeight, getTimezoneOffset, getWeekDateRange, getWeekRange, getWeekdays, goToToday, nextDay, nextMonth, nextWeek, previousDay, previousMonth, previousWeek };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ type CalendarAccessor<TItem> = {
|
|
|
7
7
|
getEnd?: (item: TItem) => Temporal.ZonedDateTime;
|
|
8
8
|
};
|
|
9
9
|
type CalendarDay<TItem = unknown> = {
|
|
10
|
+
/** Unique identifier for this day within the view context. Use as React/Vue key. */
|
|
11
|
+
id: string;
|
|
10
12
|
date: Temporal.PlainDate;
|
|
11
13
|
isCurrentMonth: boolean;
|
|
12
14
|
isToday: boolean;
|
|
@@ -18,6 +20,8 @@ type CalendarMonth<TItem = unknown> = {
|
|
|
18
20
|
month: Temporal.PlainYearMonth;
|
|
19
21
|
};
|
|
20
22
|
type WeekDay<TItem = unknown> = {
|
|
23
|
+
/** Unique identifier for this day within the view context. Use as React/Vue key. */
|
|
24
|
+
id: string;
|
|
21
25
|
date: Temporal.PlainDate;
|
|
22
26
|
isToday: boolean;
|
|
23
27
|
items: TItem[];
|
|
@@ -29,12 +33,16 @@ type CalendarWeekView<TItem = unknown> = {
|
|
|
29
33
|
weekEnd: Temporal.PlainDate;
|
|
30
34
|
};
|
|
31
35
|
type TimeSlot<TItem = unknown> = {
|
|
36
|
+
/** Unique identifier for this time slot. Use as React/Vue key. */
|
|
37
|
+
id: string;
|
|
32
38
|
hour: number;
|
|
33
39
|
minute: number;
|
|
34
40
|
time: Temporal.PlainTime;
|
|
35
41
|
items: TItem[];
|
|
36
42
|
};
|
|
37
43
|
type CalendarDayView<TItem = unknown> = {
|
|
44
|
+
/** Unique identifier for this day view. Use as React/Vue key. */
|
|
45
|
+
id: string;
|
|
38
46
|
date: Temporal.PlainDate;
|
|
39
47
|
isToday: boolean;
|
|
40
48
|
timeSlots: TimeSlot<TItem>[];
|
|
@@ -73,17 +81,16 @@ type CalendarViewOptions<TItem> = {
|
|
|
73
81
|
day?: DayViewOptions<TItem>;
|
|
74
82
|
};
|
|
75
83
|
type CalendarOptions<TItem> = {
|
|
76
|
-
data: TItem[];
|
|
77
84
|
views: CalendarViewOptions<TItem>;
|
|
78
85
|
timeZone?: 'UTC' | string;
|
|
79
86
|
state?: Partial<CalendarState>;
|
|
80
|
-
onStateChange?: (
|
|
87
|
+
onStateChange?: (state: CalendarState) => void;
|
|
81
88
|
};
|
|
82
89
|
type HasView<Options, View extends 'month' | 'week' | 'day'> = Options extends {
|
|
83
90
|
views: infer V;
|
|
84
91
|
} ? V extends Record<View, unknown> ? V[View] extends undefined ? false : true : false : false;
|
|
85
92
|
type MonthMethods<TItem, TOptions> = HasView<TOptions, 'month'> extends true ? {
|
|
86
|
-
getMonth(): CalendarMonth<TItem>;
|
|
93
|
+
getMonth(data?: TItem[]): CalendarMonth<TItem>;
|
|
87
94
|
nextMonth(): void;
|
|
88
95
|
previousMonth(): void;
|
|
89
96
|
goToMonth(year: number, month: number): void;
|
|
@@ -94,7 +101,7 @@ type MonthMethods<TItem, TOptions> = HasView<TOptions, 'month'> extends true ? {
|
|
|
94
101
|
goToMonth?: never;
|
|
95
102
|
};
|
|
96
103
|
type WeekMethods<TItem, TOptions> = HasView<TOptions, 'week'> extends true ? {
|
|
97
|
-
getWeek(): CalendarWeekView<TItem>;
|
|
104
|
+
getWeek(data?: TItem[]): CalendarWeekView<TItem>;
|
|
98
105
|
nextWeek(): void;
|
|
99
106
|
previousWeek(): void;
|
|
100
107
|
} : {
|
|
@@ -103,7 +110,7 @@ type WeekMethods<TItem, TOptions> = HasView<TOptions, 'week'> extends true ? {
|
|
|
103
110
|
previousWeek?: never;
|
|
104
111
|
};
|
|
105
112
|
type DayMethods<TItem, TOptions> = HasView<TOptions, 'day'> extends true ? {
|
|
106
|
-
getDay(): CalendarDayView<TItem>;
|
|
113
|
+
getDay(data?: TItem[]): CalendarDayView<TItem>;
|
|
107
114
|
nextDay(): void;
|
|
108
115
|
previousDay(): void;
|
|
109
116
|
} : {
|
|
@@ -126,6 +133,7 @@ type BaseCalendarMethods<Options> = {
|
|
|
126
133
|
currentView: ValidViews<Options>;
|
|
127
134
|
setCurrentView(view: ValidViews<Options>): void;
|
|
128
135
|
dateRange: DateRange;
|
|
136
|
+
getDateRange(view?: ValidViews<Options>): DateRange;
|
|
129
137
|
options: Options;
|
|
130
138
|
setOptions(updater: (old: Options) => Options): void;
|
|
131
139
|
store: _tanstack_store.Store<CalendarState>;
|
|
@@ -133,71 +141,145 @@ type BaseCalendarMethods<Options> = {
|
|
|
133
141
|
hasWeekView(): boolean;
|
|
134
142
|
hasDayView(): boolean;
|
|
135
143
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Unified calendar type with conditional methods based on configured views.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* // Calendar with specific options - methods are conditional
|
|
149
|
+
* const calendar = createCalendar<Post, typeof options>(options);
|
|
150
|
+
* calendar.getMonth([]); // Only available if month view configured
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* // Generic calendar type - all methods available
|
|
154
|
+
* type AnyPostCalendar = Calendar<Post>;
|
|
155
|
+
*/
|
|
156
|
+
type Calendar<TItem, TOptions extends CalendarOptions<TItem> = CalendarOptions<TItem>> = BaseCalendarMethods<TOptions> & MonthMethods<TItem, TOptions> & WeekMethods<TItem, TOptions> & DayMethods<TItem, TOptions>;
|
|
157
|
+
/**
|
|
158
|
+
* Calendar instance with all view methods available and typed items.
|
|
159
|
+
* Use this for contexts where the specific view configuration is unknown at compile time,
|
|
160
|
+
* but you still want type-safe item data.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* // In React context - store with unknown, consume with specific type
|
|
164
|
+
* const context = createContext<CalendarInstance<unknown> | null>(null);
|
|
165
|
+
*
|
|
166
|
+
* // Consumer gets typed data
|
|
167
|
+
* function useCalendar<TItem>(): CalendarInstance<TItem> {
|
|
168
|
+
* return useContext(context) as CalendarInstance<TItem>;
|
|
169
|
+
* }
|
|
170
|
+
*/
|
|
171
|
+
type CalendarInstance<TItem = unknown> = {
|
|
172
|
+
getMonth(data?: TItem[]): CalendarMonth<TItem>;
|
|
173
|
+
getWeek(data?: TItem[]): CalendarWeekView<TItem>;
|
|
174
|
+
getDay(data?: TItem[]): CalendarDayView<TItem>;
|
|
175
|
+
getTitle(view?: ViewType, locales?: Temporal.LocalesArgument, options?: globalThis.Intl.DateTimeFormatOptions): string;
|
|
176
|
+
getState(): CalendarState;
|
|
177
|
+
setState(updater: CalendarState | ((old: CalendarState) => Partial<CalendarState>)): void;
|
|
178
|
+
goToToday(): void;
|
|
179
|
+
goToDate(date: Temporal.PlainDate): void;
|
|
180
|
+
next(view?: ViewType): void;
|
|
181
|
+
previous(view?: ViewType): void;
|
|
182
|
+
views: ReadonlyArray<string>;
|
|
183
|
+
currentView: string;
|
|
184
|
+
setCurrentView(view: string): void;
|
|
185
|
+
dateRange: DateRange;
|
|
186
|
+
getDateRange(view?: ViewType): DateRange;
|
|
187
|
+
options: CalendarOptions<TItem>;
|
|
188
|
+
setOptions(updater: (old: CalendarOptions<TItem>) => CalendarOptions<TItem>): void;
|
|
189
|
+
store: _tanstack_store.Store<CalendarState>;
|
|
190
|
+
nextMonth(): void;
|
|
191
|
+
previousMonth(): void;
|
|
192
|
+
goToMonth(year: number, month: number): void;
|
|
193
|
+
nextWeek(): void;
|
|
194
|
+
previousWeek(): void;
|
|
195
|
+
nextDay(): void;
|
|
196
|
+
previousDay(): void;
|
|
197
|
+
hasMonthView(): boolean;
|
|
198
|
+
hasWeekView(): boolean;
|
|
199
|
+
hasDayView(): boolean;
|
|
139
200
|
};
|
|
140
|
-
type Calendar<TItem, TOptionsOrViews = CalendarOptions<TItem>> = TOptionsOrViews extends CalendarOptions<TItem> ? BaseCalendarMethods<TOptionsOrViews> & MonthMethods<TItem, TOptionsOrViews> & WeekMethods<TItem, TOptionsOrViews> & DayMethods<TItem, TOptionsOrViews> : TOptionsOrViews extends CalendarViewOptions<TItem> ? BaseCalendarMethods<ViewsToOptions<TItem, TOptionsOrViews>> & MonthMethods<TItem, ViewsToOptions<TItem, TOptionsOrViews>> & WeekMethods<TItem, ViewsToOptions<TItem, TOptionsOrViews>> & DayMethods<TItem, ViewsToOptions<TItem, TOptionsOrViews>> : BaseCalendarMethods<CalendarOptions<TItem>> & MonthMethods<TItem, CalendarOptions<TItem>> & WeekMethods<TItem, CalendarOptions<TItem>> & DayMethods<TItem, CalendarOptions<TItem>>;
|
|
141
|
-
type InferViewNames<V extends CalendarViewOptions<unknown>> = keyof V & string;
|
|
142
|
-
type InferViewConfig<V extends CalendarViewOptions<unknown>, Name extends keyof V> = V[Name] extends infer Config ? {
|
|
143
|
-
name: Name;
|
|
144
|
-
config: Config;
|
|
145
|
-
} : never;
|
|
146
201
|
/**
|
|
147
|
-
* Extract the item type from a Calendar
|
|
202
|
+
* Extract the item type from a Calendar's options
|
|
148
203
|
* @example type Item = CalendarItemType<typeof calendar>; // Post
|
|
149
204
|
*/
|
|
150
|
-
type CalendarItemType<C extends
|
|
205
|
+
type CalendarItemType<C extends CalendarInstance> = C['options'] extends CalendarOptions<infer TItem> ? TItem : never;
|
|
151
206
|
/**
|
|
152
207
|
* Extract the views configuration from a Calendar type
|
|
153
208
|
* @example type Views = CalendarViewsConfig<typeof calendar>;
|
|
154
209
|
*/
|
|
155
|
-
type CalendarViewsConfig<C extends
|
|
210
|
+
type CalendarViewsConfig<C extends CalendarInstance> = C['options'] extends {
|
|
156
211
|
views: infer V;
|
|
157
|
-
} ? V :
|
|
212
|
+
} ? V : never;
|
|
158
213
|
/**
|
|
159
214
|
* Check if a Calendar has a specific view configured
|
|
160
215
|
* @example type HasMonth = HasViewType<typeof calendar, 'month'>; // true | false
|
|
161
216
|
*/
|
|
162
|
-
type HasViewType<C extends
|
|
217
|
+
type HasViewType<C extends CalendarInstance, V extends 'month' | 'week' | 'day'> = C['options'] extends CalendarOptions<infer TItem> ? HasView<C['options'], V> : false;
|
|
163
218
|
/**
|
|
164
219
|
* Extract valid view names as a union from a Calendar
|
|
165
220
|
* @example type Views = ValidViewNames<typeof calendar>; // 'month' | 'week'
|
|
166
221
|
*/
|
|
167
|
-
type ValidViewNames<C extends
|
|
168
|
-
/**
|
|
169
|
-
* Extract the item type from CalendarOptions before creating a calendar
|
|
170
|
-
* @example type Item = ItemTypeFromOptions<typeof options>; // Post
|
|
171
|
-
*/
|
|
172
|
-
type ItemTypeFromOptions<O extends CalendarOptions<any>> = O extends CalendarOptions<infer TItem> ? TItem : never;
|
|
222
|
+
type ValidViewNames<C extends CalendarInstance> = C['options'] extends CalendarOptions<infer TItem> ? ValidViews<C['options']> : never;
|
|
173
223
|
/**
|
|
174
224
|
* Base props for components that receive a Calendar
|
|
175
225
|
* @example
|
|
176
|
-
* function MyComponent<C extends
|
|
226
|
+
* function MyComponent<C extends CalendarInstance>(
|
|
177
227
|
* props: CalendarComponentProps<C>
|
|
178
228
|
* ) { ... }
|
|
179
229
|
*/
|
|
180
|
-
type CalendarComponentProps<C extends
|
|
230
|
+
type CalendarComponentProps<C extends CalendarInstance> = {
|
|
181
231
|
calendar: C;
|
|
182
232
|
};
|
|
183
233
|
/**
|
|
184
234
|
* Require that a Calendar has month view configured
|
|
185
235
|
* @example
|
|
186
|
-
* function MonthView<C extends
|
|
236
|
+
* function MonthView<C extends CalendarInstance>(
|
|
187
237
|
* props: { calendar: RequireMonthView<C> }
|
|
188
238
|
* ) {
|
|
189
239
|
* // calendar.getMonth() is guaranteed to exist
|
|
190
240
|
* }
|
|
191
241
|
*/
|
|
192
|
-
type RequireMonthView<C extends
|
|
242
|
+
type RequireMonthView<C extends CalendarInstance> = HasViewType<C, 'month'> extends true ? C : never;
|
|
193
243
|
/**
|
|
194
244
|
* Require that a Calendar has week view configured
|
|
195
245
|
*/
|
|
196
|
-
type RequireWeekView<C extends
|
|
246
|
+
type RequireWeekView<C extends CalendarInstance> = HasViewType<C, 'week'> extends true ? C : never;
|
|
197
247
|
/**
|
|
198
248
|
* Require that a Calendar has day view configured
|
|
199
249
|
*/
|
|
200
|
-
type RequireDayView<C extends
|
|
250
|
+
type RequireDayView<C extends CalendarInstance> = HasViewType<C, 'day'> extends true ? C : never;
|
|
251
|
+
/**
|
|
252
|
+
* Built-in view types
|
|
253
|
+
*/
|
|
254
|
+
type ViewType = 'month' | 'week' | 'day';
|
|
255
|
+
/**
|
|
256
|
+
* Discriminated union of all view results
|
|
257
|
+
*/
|
|
258
|
+
type ViewResult<TItem> = {
|
|
259
|
+
type: 'month';
|
|
260
|
+
data: CalendarMonth<TItem>;
|
|
261
|
+
} | {
|
|
262
|
+
type: 'week';
|
|
263
|
+
data: CalendarWeekView<TItem>;
|
|
264
|
+
} | {
|
|
265
|
+
type: 'day';
|
|
266
|
+
data: CalendarDayView<TItem>;
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Conditional type that narrows ViewResult based on view name
|
|
270
|
+
* - If V is a specific view type, returns that specific result
|
|
271
|
+
* - If V is undefined, returns the full discriminated union
|
|
272
|
+
*/
|
|
273
|
+
type ViewResultFor<TItem, V extends ViewType | undefined> = V extends 'month' ? {
|
|
274
|
+
type: 'month';
|
|
275
|
+
data: CalendarMonth<TItem>;
|
|
276
|
+
} : V extends 'week' ? {
|
|
277
|
+
type: 'week';
|
|
278
|
+
data: CalendarWeekView<TItem>;
|
|
279
|
+
} : V extends 'day' ? {
|
|
280
|
+
type: 'day';
|
|
281
|
+
data: CalendarDayView<TItem>;
|
|
282
|
+
} : ViewResult<TItem>;
|
|
201
283
|
|
|
202
284
|
declare function functionalUpdate<T>(updater: T | ((old: T) => T), input: T): T;
|
|
203
285
|
declare function createCalendarAccessor<T, A extends CalendarAccessor<T> = CalendarAccessor<T>>(accessor: A): A;
|
|
@@ -211,7 +293,6 @@ declare function goToToday(): {
|
|
|
211
293
|
year: number;
|
|
212
294
|
month: number;
|
|
213
295
|
};
|
|
214
|
-
declare function getWeekdays(weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6, locale?: string | string[], format?: 'short' | 'long' | 'narrow'): string[];
|
|
215
296
|
declare function getMonthName(month: Temporal.PlainYearMonth, locale?: string): string;
|
|
216
297
|
declare function formatTime(time: Temporal.PlainTime, locale?: string): string;
|
|
217
298
|
declare function getTimeSlotHeight(slotDuration: number, hourHeight: number): number;
|
|
@@ -292,6 +373,16 @@ declare function getWeekDateRange(date: Temporal.PlainDate, timeZone: string, op
|
|
|
292
373
|
*/
|
|
293
374
|
declare function getDayDateRange(date: Temporal.PlainDate, timeZone: string): DateRange;
|
|
294
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Returns an array of weekday names starting from the specified day.
|
|
378
|
+
*
|
|
379
|
+
* @param weekStartsOn - Day the week starts on (0=Sunday, 1=Monday, ..., 6=Saturday). Defaults to 1 (Monday).
|
|
380
|
+
* @param locale - Locale for formatting weekday names. Defaults to 'en-US'.
|
|
381
|
+
* @param format - Format for weekday names: 'short' (Mon), 'long' (Monday), or 'narrow' (M). Defaults to 'short'.
|
|
382
|
+
* @returns Array of 7 weekday names starting from weekStartsOn.
|
|
383
|
+
*/
|
|
384
|
+
declare function getWeekdays(weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6, locale?: string | string[], format?: 'short' | 'long' | 'narrow'): string[];
|
|
385
|
+
|
|
295
386
|
declare function createCalendar<TItem, TOptions extends CalendarOptions<TItem>>(options: TOptions): Calendar<TItem, TOptions>;
|
|
296
387
|
|
|
297
388
|
declare function createCalendarViews<TItem>(): <const TViews extends {
|
|
@@ -300,4 +391,4 @@ declare function createCalendarViews<TItem>(): <const TViews extends {
|
|
|
300
391
|
day?: DayViewOptions<TItem>;
|
|
301
392
|
}>(views: TViews) => TViews;
|
|
302
393
|
|
|
303
|
-
export { type Calendar, type CalendarAccessor, type CalendarComponentProps, type CalendarDay, type CalendarDayView, type CalendarItemType, type CalendarMonth, type CalendarOptions, type CalendarState, type CalendarViewOptions, type CalendarViewsConfig, type CalendarWeek, type CalendarWeekView, type DateRange, type DateRangeBounds, type DayViewOptions, type HasViewType, type
|
|
394
|
+
export { type Calendar, type CalendarAccessor, type CalendarComponentProps, type CalendarDay, type CalendarDayView, type CalendarInstance, type CalendarItemType, type CalendarMonth, type CalendarOptions, type CalendarState, type CalendarViewOptions, type CalendarViewsConfig, type CalendarWeek, type CalendarWeekView, type DateRange, type DateRangeBounds, type DayViewOptions, type HasViewType, type MonthViewOptions, type RequireDayView, type RequireMonthView, type RequireWeekView, type TimeSlot, type Updater, type ValidViewNames, type ViewResult, type ViewResultFor, type ViewType, type WeekDay, type WeekViewOptions, buildDay, buildMonth, buildWeek, convertToTimezone, createCalendar, createCalendarAccessor, createCalendarViews, createZonedDateTime, formatTime, functionalUpdate, getCurrentTimeZone, getDayDateRange, getDayRange, getEventPosition, getMonthDateRange, getMonthName, getMonthRange, getTimeSlotHeight, getTimezoneOffset, getWeekDateRange, getWeekRange, getWeekdays, goToToday, nextDay, nextMonth, nextWeek, previousDay, previousMonth, previousWeek };
|
package/dist/index.js
CHANGED
|
@@ -28,16 +28,6 @@ function goToToday() {
|
|
|
28
28
|
const today = Temporal.Now.plainDateISO();
|
|
29
29
|
return { year: today.year, month: today.month };
|
|
30
30
|
}
|
|
31
|
-
function getWeekdays(weekStartsOn = 1, locale = "en-US", format = "short") {
|
|
32
|
-
const referenceDate = Temporal.PlainDate.from("2023-01-02");
|
|
33
|
-
const days = [];
|
|
34
|
-
for (let i = 0; i < 7; i++) {
|
|
35
|
-
const offset = (weekStartsOn - 1 + i + 7) % 7;
|
|
36
|
-
const date = referenceDate.add({ days: offset });
|
|
37
|
-
days.push(date.toLocaleString(locale, { weekday: format }));
|
|
38
|
-
}
|
|
39
|
-
return days;
|
|
40
|
-
}
|
|
41
31
|
function getMonthName(month, locale = "en-US") {
|
|
42
32
|
return month.toPlainDate({ day: 1 }).toLocaleString(locale, { month: "long" });
|
|
43
33
|
}
|
|
@@ -133,6 +123,7 @@ function buildMonth(year, month, options) {
|
|
|
133
123
|
}
|
|
134
124
|
const dateKey = currentDate.toString();
|
|
135
125
|
weeks[weeks.length - 1].push({
|
|
126
|
+
id: `${yearMonth.toString()}-${dateKey}`,
|
|
136
127
|
date: currentDate,
|
|
137
128
|
isCurrentMonth: currentDate.month === month,
|
|
138
129
|
isToday: Temporal2.PlainDate.compare(currentDate, today) === 0,
|
|
@@ -160,7 +151,7 @@ import { Temporal as Temporal3 } from "@js-temporal/polyfill";
|
|
|
160
151
|
function buildDay(date, options) {
|
|
161
152
|
const startHour = options?.startHour ?? 0;
|
|
162
153
|
const endHour = options?.endHour ?? 24;
|
|
163
|
-
const slotDuration = options?.slotDuration ??
|
|
154
|
+
const slotDuration = options?.slotDuration ?? 60;
|
|
164
155
|
const today = options?.today ?? Temporal3.Now.plainDateISO();
|
|
165
156
|
const data = options?.data ?? [];
|
|
166
157
|
const accessor = options?.accessor;
|
|
@@ -174,6 +165,7 @@ function buildDay(date, options) {
|
|
|
174
165
|
}
|
|
175
166
|
}
|
|
176
167
|
const timeSlots = [];
|
|
168
|
+
const dateStr = date.toString();
|
|
177
169
|
let currentHour = startHour;
|
|
178
170
|
let currentMinute = 0;
|
|
179
171
|
while (currentHour < endHour) {
|
|
@@ -200,6 +192,7 @@ function buildDay(date, options) {
|
|
|
200
192
|
}
|
|
201
193
|
}
|
|
202
194
|
timeSlots.push({
|
|
195
|
+
id: `${dateStr}-${String(currentHour).padStart(2, "0")}:${String(currentMinute).padStart(2, "0")}`,
|
|
203
196
|
hour: currentHour,
|
|
204
197
|
minute: currentMinute,
|
|
205
198
|
time: slotStart,
|
|
@@ -212,6 +205,7 @@ function buildDay(date, options) {
|
|
|
212
205
|
}
|
|
213
206
|
}
|
|
214
207
|
return {
|
|
208
|
+
id: dateStr,
|
|
215
209
|
date,
|
|
216
210
|
isToday: Temporal3.PlainDate.compare(date, today) === 0,
|
|
217
211
|
timeSlots,
|
|
@@ -258,6 +252,7 @@ function buildWeek(date, options) {
|
|
|
258
252
|
timeSlots = dayView.timeSlots;
|
|
259
253
|
}
|
|
260
254
|
days.push({
|
|
255
|
+
id: `${weekStart.toString()}-${dateKey}`,
|
|
261
256
|
date: currentDate,
|
|
262
257
|
isToday: Temporal4.PlainDate.compare(currentDate, today) === 0,
|
|
263
258
|
items: itemsByDate.get(dateKey) ?? [],
|
|
@@ -330,8 +325,20 @@ function getDayDateRange(date, timeZone) {
|
|
|
330
325
|
return { start: startZoned, end: endZoned };
|
|
331
326
|
}
|
|
332
327
|
|
|
333
|
-
// src/
|
|
328
|
+
// src/utils/getWeekdays.ts
|
|
334
329
|
import { Temporal as Temporal6 } from "@js-temporal/polyfill";
|
|
330
|
+
function getWeekdays(weekStartsOn = 1, locale = "en-US", format = "short") {
|
|
331
|
+
const sunday = Temporal6.PlainDate.from("2023-01-01");
|
|
332
|
+
const days = [];
|
|
333
|
+
for (let i = 0; i < 7; i++) {
|
|
334
|
+
const date = sunday.add({ days: (weekStartsOn + i) % 7 });
|
|
335
|
+
days.push(date.toLocaleString(locale, { weekday: format }));
|
|
336
|
+
}
|
|
337
|
+
return days;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/core/calendar.ts
|
|
341
|
+
import { Temporal as Temporal7 } from "@js-temporal/polyfill";
|
|
335
342
|
import { Store } from "@tanstack/store";
|
|
336
343
|
function computeDateRange(view, referenceDate, timeZone, weekStartsOn = 1) {
|
|
337
344
|
let start;
|
|
@@ -356,22 +363,22 @@ function computeDateRange(view, referenceDate, timeZone, weekStartsOn = 1) {
|
|
|
356
363
|
}
|
|
357
364
|
const startZoned = start.toZonedDateTime({
|
|
358
365
|
timeZone,
|
|
359
|
-
plainTime:
|
|
366
|
+
plainTime: Temporal7.PlainTime.from("00:00:00")
|
|
360
367
|
});
|
|
361
368
|
const endZoned = end.toZonedDateTime({
|
|
362
369
|
timeZone,
|
|
363
|
-
plainTime:
|
|
370
|
+
plainTime: Temporal7.PlainTime.from("23:59:59.999")
|
|
364
371
|
});
|
|
365
372
|
return { start: startZoned, end: endZoned };
|
|
366
373
|
}
|
|
367
374
|
function createCalendar(options) {
|
|
368
375
|
const configuredViews = Object.keys(options.views);
|
|
369
376
|
const defaultView = configuredViews[0];
|
|
370
|
-
const timeZone = options.timeZone ||
|
|
377
|
+
const timeZone = options.timeZone || Temporal7.Now.timeZoneId();
|
|
371
378
|
const monthView = options.views.month;
|
|
372
379
|
const weekView = options.views.week;
|
|
373
380
|
const weekStartsOn = monthView?.weekStartsOn ?? weekView?.weekStartsOn ?? 1;
|
|
374
|
-
const initialReferenceDate = options.state?.referenceDate ||
|
|
381
|
+
const initialReferenceDate = options.state?.referenceDate || Temporal7.Now.plainDateISO();
|
|
375
382
|
const initialView = options.state?.currentView || defaultView;
|
|
376
383
|
const initialDateRange = computeDateRange(
|
|
377
384
|
initialView,
|
|
@@ -396,18 +403,18 @@ function createCalendar(options) {
|
|
|
396
403
|
dateRange: initialDateRange,
|
|
397
404
|
...resolvedOptions.state
|
|
398
405
|
});
|
|
399
|
-
const getMonthImpl = () => {
|
|
406
|
+
const getMonthImpl = (data = []) => {
|
|
400
407
|
const state = store.state;
|
|
401
408
|
const { year, month } = state.referenceDate;
|
|
402
409
|
const monthView2 = _options.views.month;
|
|
403
410
|
if (!monthView2) throw new Error("Month view not configured");
|
|
404
411
|
return buildMonth(year, month, {
|
|
405
412
|
weekStartsOn: monthView2.weekStartsOn,
|
|
406
|
-
data
|
|
413
|
+
data,
|
|
407
414
|
accessor: monthView2.accessor
|
|
408
415
|
});
|
|
409
416
|
};
|
|
410
|
-
const getWeekImpl = () => {
|
|
417
|
+
const getWeekImpl = (data = []) => {
|
|
411
418
|
const state = store.state;
|
|
412
419
|
const weekView2 = _options.views.week;
|
|
413
420
|
if (!weekView2) throw new Error("Week view not configured");
|
|
@@ -416,11 +423,11 @@ function createCalendar(options) {
|
|
|
416
423
|
startHour: weekView2.startHour,
|
|
417
424
|
endHour: weekView2.endHour,
|
|
418
425
|
slotDuration: weekView2.slotDuration,
|
|
419
|
-
data
|
|
426
|
+
data,
|
|
420
427
|
accessor: weekView2.accessor
|
|
421
428
|
});
|
|
422
429
|
};
|
|
423
|
-
const getDayImpl = () => {
|
|
430
|
+
const getDayImpl = (data = []) => {
|
|
424
431
|
const state = store.state;
|
|
425
432
|
const dayView = _options.views.day;
|
|
426
433
|
if (!dayView) throw new Error("Day view not configured");
|
|
@@ -428,7 +435,7 @@ function createCalendar(options) {
|
|
|
428
435
|
startHour: dayView.startHour,
|
|
429
436
|
endHour: dayView.endHour,
|
|
430
437
|
slotDuration: dayView.slotDuration,
|
|
431
|
-
data
|
|
438
|
+
data,
|
|
432
439
|
accessor: dayView.accessor
|
|
433
440
|
});
|
|
434
441
|
};
|
|
@@ -456,7 +463,7 @@ function createCalendar(options) {
|
|
|
456
463
|
};
|
|
457
464
|
const nextMonthImpl = () => {
|
|
458
465
|
setStateImpl((old) => {
|
|
459
|
-
const current =
|
|
466
|
+
const current = Temporal7.PlainYearMonth.from({
|
|
460
467
|
year: old.referenceDate.year,
|
|
461
468
|
month: old.referenceDate.month
|
|
462
469
|
});
|
|
@@ -468,7 +475,7 @@ function createCalendar(options) {
|
|
|
468
475
|
};
|
|
469
476
|
const previousMonthImpl = () => {
|
|
470
477
|
setStateImpl((old) => {
|
|
471
|
-
const current =
|
|
478
|
+
const current = Temporal7.PlainYearMonth.from({
|
|
472
479
|
year: old.referenceDate.year,
|
|
473
480
|
month: old.referenceDate.month
|
|
474
481
|
});
|
|
@@ -553,7 +560,7 @@ function createCalendar(options) {
|
|
|
553
560
|
previousMonth: previousMonthImpl,
|
|
554
561
|
goToMonth(year, month) {
|
|
555
562
|
setStateImpl(() => ({
|
|
556
|
-
referenceDate:
|
|
563
|
+
referenceDate: Temporal7.PlainDate.from({ year, month, day: 1 })
|
|
557
564
|
}));
|
|
558
565
|
},
|
|
559
566
|
nextWeek: nextWeekImpl,
|
|
@@ -562,7 +569,7 @@ function createCalendar(options) {
|
|
|
562
569
|
previousDay: previousDayImpl,
|
|
563
570
|
goToToday() {
|
|
564
571
|
setStateImpl(() => ({
|
|
565
|
-
referenceDate:
|
|
572
|
+
referenceDate: Temporal7.Now.plainDateISO()
|
|
566
573
|
}));
|
|
567
574
|
},
|
|
568
575
|
goToDate(date) {
|
|
@@ -613,6 +620,15 @@ function createCalendar(options) {
|
|
|
613
620
|
get dateRange() {
|
|
614
621
|
return store.state.dateRange;
|
|
615
622
|
},
|
|
623
|
+
getDateRange(view) {
|
|
624
|
+
const effectiveView = view ?? store.state.currentView ?? defaultView;
|
|
625
|
+
return computeDateRange(
|
|
626
|
+
effectiveView,
|
|
627
|
+
store.state.referenceDate,
|
|
628
|
+
timeZone,
|
|
629
|
+
weekStartsOn
|
|
630
|
+
);
|
|
631
|
+
},
|
|
616
632
|
get options() {
|
|
617
633
|
return _options;
|
|
618
634
|
},
|