@primeui/scheduler-core 0.0.1-alpha.1

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.
Files changed (63) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +1 -0
  3. package/dist/calendar/index.d.mts +57 -0
  4. package/dist/calendar/index.mjs +1 -0
  5. package/dist/chunk-2B3YLWHA.mjs +196 -0
  6. package/dist/chunk-2THQAZ26.mjs +1669 -0
  7. package/dist/chunk-5KORIWDT.mjs +41 -0
  8. package/dist/chunk-5N4ZOBJV.mjs +866 -0
  9. package/dist/chunk-6OZAPQZ5.mjs +229 -0
  10. package/dist/chunk-6PK5WSKT.mjs +369 -0
  11. package/dist/chunk-6VYWVIGM.mjs +1170 -0
  12. package/dist/chunk-AAVM7UCG.mjs +100 -0
  13. package/dist/chunk-C7ADJGNV.mjs +157 -0
  14. package/dist/chunk-DYW6WUHE.mjs +277 -0
  15. package/dist/chunk-F5W5HD7S.mjs +285 -0
  16. package/dist/chunk-FIBAZFC4.mjs +871 -0
  17. package/dist/chunk-HPC5B3AR.mjs +558 -0
  18. package/dist/chunk-KQGRXTP5.mjs +650 -0
  19. package/dist/chunk-NMX4BW42.mjs +672 -0
  20. package/dist/chunk-NX46LPLF.mjs +440 -0
  21. package/dist/chunk-NZGJN7HG.mjs +314 -0
  22. package/dist/chunk-QDMZBJDV.mjs +251 -0
  23. package/dist/chunk-QR2SVYAD.mjs +1144 -0
  24. package/dist/chunk-SYJ5O4KH.mjs +136 -0
  25. package/dist/chunk-TNKJPFGI.mjs +569 -0
  26. package/dist/chunk-UMAMDBU4.mjs +1 -0
  27. package/dist/chunk-W2SJW3QQ.mjs +3925 -0
  28. package/dist/chunk-WFUJWDST.mjs +352 -0
  29. package/dist/chunk-XUBQ2IQS.mjs +1 -0
  30. package/dist/chunk-ZUKUKGNK.mjs +613 -0
  31. package/dist/controllers/index.d.mts +384 -0
  32. package/dist/controllers/index.mjs +13 -0
  33. package/dist/date-D_CjQPmM.d.mts +74 -0
  34. package/dist/display-format-CLVvRt4I.d.mts +57 -0
  35. package/dist/event/index.d.mts +267 -0
  36. package/dist/event/index.mjs +8 -0
  37. package/dist/event-surface-_R_LHD95.d.mts +21 -0
  38. package/dist/event.positioning-BdzAVPk7.d.mts +51 -0
  39. package/dist/event.utils-QSNdd-3W.d.mts +35 -0
  40. package/dist/index.d.mts +1128 -0
  41. package/dist/index.mjs +1022 -0
  42. package/dist/interaction/index.d.mts +442 -0
  43. package/dist/interaction/index.mjs +9 -0
  44. package/dist/month/index.d.mts +104 -0
  45. package/dist/month/index.mjs +6 -0
  46. package/dist/overlay-BYM9B6nC.d.mts +64 -0
  47. package/dist/resource/index.d.mts +172 -0
  48. package/dist/resource/index.mjs +1 -0
  49. package/dist/selection-CO_98HdS.d.mts +56 -0
  50. package/dist/time-grid/index.d.mts +92 -0
  51. package/dist/time-grid/index.mjs +13 -0
  52. package/dist/timeline/index.d.mts +165 -0
  53. package/dist/timeline/index.mjs +6 -0
  54. package/dist/touch-BhsMWsjf.d.mts +69 -0
  55. package/dist/utils/index.d.mts +494 -0
  56. package/dist/utils/index.mjs +17 -0
  57. package/dist/views/index.d.mts +51 -0
  58. package/dist/views/index.mjs +8 -0
  59. package/dist/views/timeline/index.d.mts +37 -0
  60. package/dist/views/timeline/index.mjs +4 -0
  61. package/dist/year/index.d.mts +70 -0
  62. package/dist/year/index.mjs +6 -0
  63. package/package.json +58 -0
@@ -0,0 +1,871 @@
1
+ import { createSchedulerDateFormatter } from './chunk-TNKJPFGI.mjs';
2
+
3
+ // src/event/recurrence.ts
4
+ var WEEKDAY_MAP = {
5
+ SU: 0,
6
+ MO: 1,
7
+ TU: 2,
8
+ WE: 3,
9
+ TH: 4,
10
+ FR: 5,
11
+ SA: 6
12
+ };
13
+ var WEEKDAY_REVERSE = {
14
+ 0: "SU",
15
+ 1: "MO",
16
+ 2: "TU",
17
+ 3: "WE",
18
+ 4: "TH",
19
+ 5: "FR",
20
+ 6: "SA"
21
+ };
22
+ function getDisplayConfigView(displayConfig) {
23
+ return displayConfig && "view" in displayConfig ? displayConfig.view : void 0;
24
+ }
25
+ function createRecurrenceDescriptionFormatter(localeOrOptions = "en", displayOptions = {}) {
26
+ const directOptions = typeof localeOrOptions === "string" ? displayOptions : localeOrOptions;
27
+ const displayConfig = directOptions.calendarDisplayConfig;
28
+ const formatter = createSchedulerDateFormatter({
29
+ locale: directOptions.locale ?? displayConfig?.locale ?? (typeof localeOrOptions === "string" ? localeOrOptions : "en"),
30
+ calendar: directOptions.calendar ?? displayConfig?.calendar,
31
+ numberingSystem: directOptions.numberingSystem ?? displayConfig?.numberingSystem,
32
+ timeZone: directOptions.timeZone ?? displayConfig?.timeZone,
33
+ view: directOptions.view ?? getDisplayConfigView(displayConfig)
34
+ });
35
+ return {
36
+ formatter,
37
+ formatNumber: (value) => formatter.formatNumber(value)
38
+ };
39
+ }
40
+ function getWeekdayDisplayDate(weekday) {
41
+ const weekdayIndex = WEEKDAY_MAP[weekday];
42
+ return new Date(2024, 0, weekdayIndex === 0 ? 7 : weekdayIndex, 12);
43
+ }
44
+ function getMonthDisplayDate(month) {
45
+ return new Date(2024, month - 1, 1, 12);
46
+ }
47
+ function formatWeekdayName(weekday, formatter) {
48
+ return formatter.formatWeekday(getWeekdayDisplayDate(weekday), "long");
49
+ }
50
+ function formatMonthName(month, formatter) {
51
+ return formatter.formatMonth(getMonthDisplayDate(month), "long");
52
+ }
53
+ function formatNumberList(values, formatNumber) {
54
+ return values.map((value) => formatNumber(value)).join(", ");
55
+ }
56
+ function parseRRule(rruleString) {
57
+ if (!rruleString || typeof rruleString !== "string") return null;
58
+ const cleaned = rruleString.replace(/^RRULE:/i, "").trim();
59
+ const parts = cleaned.split(";");
60
+ const options = {};
61
+ for (const part of parts) {
62
+ const [key, value] = part.split("=");
63
+ if (!key || !value) continue;
64
+ const upperKey = key.toUpperCase();
65
+ switch (upperKey) {
66
+ case "FREQ":
67
+ options.freq = value.toUpperCase();
68
+ break;
69
+ case "INTERVAL":
70
+ options.interval = parseInt(value, 10);
71
+ break;
72
+ case "COUNT":
73
+ options.count = parseInt(value, 10);
74
+ break;
75
+ case "UNTIL":
76
+ options.until = parseRRuleDate(value);
77
+ break;
78
+ case "BYDAY":
79
+ options.byday = value.split(",").map((d) => d.toUpperCase());
80
+ break;
81
+ case "BYMONTHDAY":
82
+ options.bymonthday = value.split(",").map((d) => parseInt(d, 10));
83
+ break;
84
+ case "BYMONTH":
85
+ options.bymonth = value.split(",").map((m) => parseInt(m, 10));
86
+ break;
87
+ case "BYWEEKNO":
88
+ options.byweekno = value.split(",").map((w) => parseInt(w, 10));
89
+ break;
90
+ case "BYYEARDAY":
91
+ options.byyearday = value.split(",").map((d) => parseInt(d, 10));
92
+ break;
93
+ case "BYHOUR":
94
+ options.byhour = value.split(",").map((h) => parseInt(h, 10));
95
+ break;
96
+ case "BYMINUTE":
97
+ options.byminute = value.split(",").map((m) => parseInt(m, 10));
98
+ break;
99
+ case "BYSECOND":
100
+ options.bysecond = value.split(",").map((s) => parseInt(s, 10));
101
+ break;
102
+ case "BYSETPOS":
103
+ options.bysetpos = value.split(",").map((p) => parseInt(p, 10));
104
+ break;
105
+ case "WKST":
106
+ options.wkst = value.toUpperCase();
107
+ break;
108
+ }
109
+ }
110
+ if (!options.freq) return null;
111
+ return options;
112
+ }
113
+ function serializeRRule(options) {
114
+ const parts = [];
115
+ parts.push(`FREQ=${options.freq}`);
116
+ if (options.interval && options.interval > 1) {
117
+ parts.push(`INTERVAL=${options.interval}`);
118
+ }
119
+ if (options.count !== void 0) {
120
+ parts.push(`COUNT=${options.count}`);
121
+ }
122
+ if (options.until) {
123
+ parts.push(`UNTIL=${formatRRuleDate(options.until)}`);
124
+ }
125
+ if (options.byday && options.byday.length > 0) {
126
+ parts.push(`BYDAY=${options.byday.join(",")}`);
127
+ }
128
+ if (options.bymonthday && options.bymonthday.length > 0) {
129
+ parts.push(`BYMONTHDAY=${options.bymonthday.join(",")}`);
130
+ }
131
+ if (options.bymonth && options.bymonth.length > 0) {
132
+ parts.push(`BYMONTH=${options.bymonth.join(",")}`);
133
+ }
134
+ if (options.byweekno && options.byweekno.length > 0) {
135
+ parts.push(`BYWEEKNO=${options.byweekno.join(",")}`);
136
+ }
137
+ if (options.byyearday && options.byyearday.length > 0) {
138
+ parts.push(`BYYEARDAY=${options.byyearday.join(",")}`);
139
+ }
140
+ if (options.byhour && options.byhour.length > 0) {
141
+ parts.push(`BYHOUR=${options.byhour.join(",")}`);
142
+ }
143
+ if (options.byminute && options.byminute.length > 0) {
144
+ parts.push(`BYMINUTE=${options.byminute.join(",")}`);
145
+ }
146
+ if (options.bysecond && options.bysecond.length > 0) {
147
+ parts.push(`BYSECOND=${options.bysecond.join(",")}`);
148
+ }
149
+ if (options.bysetpos && options.bysetpos.length > 0) {
150
+ parts.push(`BYSETPOS=${options.bysetpos.join(",")}`);
151
+ }
152
+ if (options.wkst) {
153
+ parts.push(`WKST=${options.wkst}`);
154
+ }
155
+ return parts.join(";");
156
+ }
157
+ function parseRRuleDate(dateStr) {
158
+ if (dateStr.length === 8) {
159
+ const year = parseInt(dateStr.slice(0, 4), 10);
160
+ const month = parseInt(dateStr.slice(4, 6), 10) - 1;
161
+ const day = parseInt(dateStr.slice(6, 8), 10);
162
+ return new Date(year, month, day);
163
+ }
164
+ if (dateStr.includes("T")) {
165
+ const datePart = dateStr.slice(0, 8);
166
+ const timePart = dateStr.slice(9, 15);
167
+ const year = parseInt(datePart.slice(0, 4), 10);
168
+ const month = parseInt(datePart.slice(4, 6), 10) - 1;
169
+ const day = parseInt(datePart.slice(6, 8), 10);
170
+ const hour = parseInt(timePart.slice(0, 2), 10);
171
+ const minute = parseInt(timePart.slice(2, 4), 10);
172
+ const second = parseInt(timePart.slice(4, 6), 10);
173
+ if (dateStr.endsWith("Z")) {
174
+ return new Date(Date.UTC(year, month, day, hour, minute, second));
175
+ }
176
+ return new Date(year, month, day, hour, minute, second);
177
+ }
178
+ return new Date(dateStr);
179
+ }
180
+ function formatRRuleDate(date) {
181
+ const d = typeof date === "string" ? new Date(date) : date;
182
+ const year = d.getFullYear();
183
+ const month = String(d.getMonth() + 1).padStart(2, "0");
184
+ const day = String(d.getDate()).padStart(2, "0");
185
+ return `${year}${month}${day}`;
186
+ }
187
+ function addDays(date, days) {
188
+ const result = new Date(date);
189
+ result.setDate(result.getDate() + days);
190
+ return result;
191
+ }
192
+ function addMonths(date, months) {
193
+ const result = new Date(date);
194
+ const targetMonth = result.getMonth() + months;
195
+ result.setMonth(targetMonth);
196
+ if (result.getMonth() !== (targetMonth % 12 + 12) % 12) {
197
+ result.setDate(0);
198
+ }
199
+ return result;
200
+ }
201
+ function addYears(date, years) {
202
+ const result = new Date(date);
203
+ result.setFullYear(result.getFullYear() + years);
204
+ return result;
205
+ }
206
+ function getDaysInMonth(year, month) {
207
+ return new Date(year, month + 1, 0).getDate();
208
+ }
209
+ function getDaysInYear(year) {
210
+ return isLeapYear(year) ? 366 : 365;
211
+ }
212
+ function isLeapYear(year) {
213
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
214
+ }
215
+ function getDateFromYearDay(year, yearDay) {
216
+ const daysInYear = getDaysInYear(year);
217
+ let actualDay = yearDay;
218
+ if (yearDay < 0) {
219
+ actualDay = daysInYear + yearDay + 1;
220
+ }
221
+ if (actualDay < 1 || actualDay > daysInYear) {
222
+ return /* @__PURE__ */ new Date(NaN);
223
+ }
224
+ const date = new Date(year, 0, actualDay);
225
+ return date;
226
+ }
227
+ function getWeekNumber(date) {
228
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
229
+ const dayNum = d.getUTCDay() || 7;
230
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
231
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
232
+ return Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
233
+ }
234
+ function getDatesByWeekNumber(year, weekNumbers, wkst) {
235
+ const dates = [];
236
+ for (const weekNo of weekNumbers) {
237
+ let actualWeek = weekNo;
238
+ if (weekNo < 0) {
239
+ const lastWeek = getWeekNumber(new Date(year, 11, 28));
240
+ actualWeek = lastWeek + weekNo + 1;
241
+ }
242
+ if (actualWeek < 1 || actualWeek > 53) continue;
243
+ const jan4 = new Date(year, 0, 4);
244
+ const jan4Day = jan4.getDay() || 7;
245
+ const week1Start = new Date(year, 0, 4 - jan4Day + wkst);
246
+ if (week1Start.getDay() !== wkst) {
247
+ week1Start.setDate(week1Start.getDate() - 7);
248
+ }
249
+ const targetWeekStart = new Date(week1Start);
250
+ targetWeekStart.setDate(targetWeekStart.getDate() + (actualWeek - 1) * 7);
251
+ for (let i = 0; i < 7; i++) {
252
+ const dayInWeek = new Date(targetWeekStart);
253
+ dayInWeek.setDate(dayInWeek.getDate() + i);
254
+ if (dayInWeek.getFullYear() === year) {
255
+ dates.push(dayInWeek);
256
+ }
257
+ }
258
+ }
259
+ return dates;
260
+ }
261
+ function getWeekdayOfMonth(date, weekday, position) {
262
+ const year = date.getFullYear();
263
+ const month = date.getMonth();
264
+ const daysInMonth = getDaysInMonth(year, month);
265
+ if (position > 0) {
266
+ let count = 0;
267
+ for (let day = 1; day <= daysInMonth; day++) {
268
+ const d = new Date(year, month, day);
269
+ if (d.getDay() === weekday) {
270
+ count++;
271
+ if (count === position) return d;
272
+ }
273
+ }
274
+ } else if (position < 0) {
275
+ let count = 0;
276
+ for (let day = daysInMonth; day >= 1; day--) {
277
+ const d = new Date(year, month, day);
278
+ if (d.getDay() === weekday) {
279
+ count--;
280
+ if (count === position) return d;
281
+ }
282
+ }
283
+ }
284
+ return null;
285
+ }
286
+ function parsePositionalWeekday(byday) {
287
+ const match = byday.match(/^(-?\d+)?([A-Z]{2})$/);
288
+ if (!match) return null;
289
+ const position = match[1] ? parseInt(match[1], 10) : void 0;
290
+ const weekday = match[2];
291
+ return { weekday, position };
292
+ }
293
+ function expandRRule(event, rangeStart, rangeEnd, maxOccurrences = 365) {
294
+ const rrule = typeof event.rrule === "string" ? parseRRule(event.rrule) : event.rrule;
295
+ if (!rrule) return [];
296
+ const eventStart = typeof event.start === "string" ? new Date(event.start) : new Date(event.start);
297
+ let eventEnd;
298
+ if (event.end) {
299
+ eventEnd = typeof event.end === "string" ? new Date(event.end) : new Date(event.end);
300
+ } else if (event.duration) {
301
+ eventEnd = new Date(eventStart.getTime() + event.duration * 60 * 1e3);
302
+ } else if (event.allDay) {
303
+ eventEnd = new Date(eventStart);
304
+ eventEnd.setHours(23, 59, 59, 999);
305
+ } else {
306
+ eventEnd = new Date(eventStart.getTime() + 60 * 60 * 1e3);
307
+ }
308
+ const duration = eventEnd.getTime() - eventStart.getTime();
309
+ const exdates = /* @__PURE__ */ new Set();
310
+ if (event.exdate) {
311
+ for (const exd of event.exdate) {
312
+ const d = typeof exd === "string" ? new Date(exd) : exd;
313
+ exdates.add(dateToKey(d));
314
+ }
315
+ }
316
+ const interval = rrule.interval || 1;
317
+ const until = rrule.until ? typeof rrule.until === "string" ? new Date(rrule.until) : rrule.until : null;
318
+ const count = rrule.count;
319
+ const wkst = rrule.wkst ? WEEKDAY_MAP[rrule.wkst] : 1;
320
+ const occurrences = [];
321
+ let current = new Date(eventStart);
322
+ let totalCount = 0;
323
+ const effectiveEnd = until && until < rangeEnd ? until : rangeEnd;
324
+ while (current <= effectiveEnd && totalCount < maxOccurrences) {
325
+ if (count !== void 0 && totalCount >= count) break;
326
+ const matchingDates = getMatchingDatesForFrequency(current, rrule, eventStart, wkst);
327
+ for (const date of matchingDates) {
328
+ if (count !== void 0 && totalCount >= count) break;
329
+ if (date > effectiveEnd) continue;
330
+ if (date < eventStart) continue;
331
+ const dateKey = dateToKey(date);
332
+ if (exdates.has(dateKey)) continue;
333
+ const occurrenceEnd = new Date(date.getTime() + duration);
334
+ if (occurrenceEnd >= rangeStart && date <= rangeEnd) {
335
+ occurrences.push(new Date(date));
336
+ }
337
+ totalCount++;
338
+ }
339
+ current = advanceToNextPeriod(current, rrule.freq, interval);
340
+ }
341
+ return occurrences.map((occStart) => {
342
+ const occEnd = new Date(occStart.getTime() + duration);
343
+ return {
344
+ id: `${event.id}_${occStart.getTime()}`,
345
+ originalId: event.id,
346
+ title: event.title,
347
+ start: occStart,
348
+ end: occEnd,
349
+ allDay: event.allDay,
350
+ color: event.color,
351
+ textColor: event.textColor,
352
+ className: event.className,
353
+ editable: event.editable,
354
+ draggable: event.draggable,
355
+ resizable: event.resizable,
356
+ metadata: event.metadata,
357
+ isRecurring: true,
358
+ recurringEventId: event.id,
359
+ recurrenceId: occStart,
360
+ originalStart: occStart,
361
+ timezone: event.timezone,
362
+ resourceId: event.resourceId,
363
+ resourceIds: event.resourceIds,
364
+ categoryId: event.categoryId,
365
+ categoryIds: event.categoryIds
366
+ };
367
+ });
368
+ }
369
+ function dateToKey(date) {
370
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
371
+ }
372
+ function expandRecurringSeries(series, rangeStart, rangeEnd, maxOccurrences = 365) {
373
+ const rrule = typeof series.rrule === "string" ? parseRRule(series.rrule) : series.rrule;
374
+ if (!rrule) return [];
375
+ const seriesStart = typeof series.start === "string" ? new Date(series.start) : new Date(series.start);
376
+ let seriesEnd;
377
+ if (series.end) {
378
+ seriesEnd = typeof series.end === "string" ? new Date(series.end) : new Date(series.end);
379
+ } else if (series.duration) {
380
+ seriesEnd = new Date(seriesStart.getTime() + series.duration * 60 * 1e3);
381
+ } else if (series.allDay) {
382
+ seriesEnd = new Date(seriesStart);
383
+ seriesEnd.setHours(23, 59, 59, 999);
384
+ } else {
385
+ seriesEnd = new Date(seriesStart.getTime() + 60 * 60 * 1e3);
386
+ }
387
+ const duration = seriesEnd.getTime() - seriesStart.getTime();
388
+ const exdates = /* @__PURE__ */ new Set();
389
+ if (series.exdate) {
390
+ for (const exd of series.exdate) {
391
+ const d = typeof exd === "string" ? new Date(exd) : exd;
392
+ exdates.add(dateToKey(d));
393
+ }
394
+ }
395
+ const exceptionsMap = /* @__PURE__ */ new Map();
396
+ if (series.exceptions) {
397
+ for (const exc of series.exceptions) {
398
+ const d = typeof exc.originalStart === "string" ? new Date(exc.originalStart) : exc.originalStart;
399
+ exceptionsMap.set(dateToKey(d), exc);
400
+ }
401
+ }
402
+ const rdates = [];
403
+ if (series.rdate) {
404
+ for (const rd of series.rdate) {
405
+ const d = typeof rd === "string" ? new Date(rd) : rd;
406
+ if (d >= rangeStart && d <= rangeEnd && !exdates.has(dateToKey(d))) {
407
+ rdates.push(d);
408
+ }
409
+ }
410
+ }
411
+ const interval = rrule.interval || 1;
412
+ const until = rrule.until ? typeof rrule.until === "string" ? new Date(rrule.until) : rrule.until : null;
413
+ const count = rrule.count;
414
+ const wkst = rrule.wkst ? WEEKDAY_MAP[rrule.wkst] : 1;
415
+ const occurrences = [];
416
+ let current = new Date(seriesStart);
417
+ let totalCount = 0;
418
+ const effectiveEnd = until && until < rangeEnd ? until : rangeEnd;
419
+ while (current <= effectiveEnd && totalCount < maxOccurrences) {
420
+ if (count !== void 0 && totalCount >= count) break;
421
+ const matchingDates = getMatchingDatesForFrequency(current, rrule, seriesStart, wkst);
422
+ for (const date of matchingDates) {
423
+ if (count !== void 0 && totalCount >= count) break;
424
+ if (date > effectiveEnd) continue;
425
+ if (date < seriesStart) continue;
426
+ const dateKey = dateToKey(date);
427
+ if (exdates.has(dateKey)) continue;
428
+ const occurrenceEnd = new Date(date.getTime() + duration);
429
+ if (occurrenceEnd >= rangeStart && date <= rangeEnd) {
430
+ occurrences.push(new Date(date));
431
+ }
432
+ totalCount++;
433
+ }
434
+ current = advanceToNextPeriod(current, rrule.freq, interval);
435
+ }
436
+ for (const rdate of rdates) {
437
+ const dateKey = dateToKey(rdate);
438
+ const alreadyExists = occurrences.some((occ) => dateToKey(occ) === dateKey);
439
+ if (!alreadyExists) {
440
+ occurrences.push(rdate);
441
+ }
442
+ }
443
+ occurrences.sort((a, b) => a.getTime() - b.getTime());
444
+ return occurrences.map((occStart) => {
445
+ const dateKey = dateToKey(occStart);
446
+ const exception = exceptionsMap.get(dateKey);
447
+ if (exception && exception.event) {
448
+ const excEvent = exception.event;
449
+ const excStart = excEvent.start ? typeof excEvent.start === "string" ? new Date(excEvent.start) : new Date(excEvent.start) : occStart;
450
+ let excEnd;
451
+ if (excEvent.end) {
452
+ excEnd = typeof excEvent.end === "string" ? new Date(excEvent.end) : new Date(excEvent.end);
453
+ } else if (excEvent.duration) {
454
+ excEnd = new Date(excStart.getTime() + excEvent.duration * 60 * 1e3);
455
+ } else {
456
+ excEnd = new Date(excStart.getTime() + duration);
457
+ }
458
+ return {
459
+ id: `${series.id}_${occStart.getTime()}`,
460
+ originalId: series.id,
461
+ title: excEvent.title ?? series.title,
462
+ start: excStart,
463
+ end: excEnd,
464
+ allDay: excEvent.allDay ?? series.allDay,
465
+ color: excEvent.color ?? series.color,
466
+ textColor: excEvent.textColor ?? series.textColor,
467
+ className: excEvent.className ?? series.className,
468
+ editable: excEvent.editable ?? series.editable,
469
+ draggable: excEvent.draggable ?? series.draggable,
470
+ resizable: excEvent.resizable ?? series.resizable,
471
+ metadata: { ...series.metadata, ...excEvent.metadata },
472
+ isRecurring: true,
473
+ recurringEventId: series.id,
474
+ recurrenceId: exception.recurrenceId,
475
+ isException: true,
476
+ originalStart: occStart,
477
+ timezone: excEvent.timezone ?? series.timezone,
478
+ resourceId: excEvent.resourceId ?? series.resourceId,
479
+ resourceIds: excEvent.resourceIds ?? series.resourceIds,
480
+ categoryId: excEvent.categoryId ?? series.categoryId,
481
+ categoryIds: excEvent.categoryIds ?? series.categoryIds
482
+ };
483
+ }
484
+ const occEnd = new Date(occStart.getTime() + duration);
485
+ return {
486
+ id: `${series.id}_${occStart.getTime()}`,
487
+ originalId: series.id,
488
+ title: series.title,
489
+ start: occStart,
490
+ end: occEnd,
491
+ allDay: series.allDay,
492
+ color: series.color,
493
+ textColor: series.textColor,
494
+ className: series.className,
495
+ editable: series.editable,
496
+ draggable: series.draggable,
497
+ resizable: series.resizable,
498
+ metadata: series.metadata,
499
+ isRecurring: true,
500
+ recurringEventId: series.id,
501
+ originalStart: occStart,
502
+ timezone: series.timezone,
503
+ resourceId: series.resourceId,
504
+ resourceIds: series.resourceIds,
505
+ categoryId: series.categoryId,
506
+ categoryIds: series.categoryIds
507
+ };
508
+ });
509
+ }
510
+ function getMatchingDatesForFrequency(current, rrule, eventStart, wkst) {
511
+ const dates = [];
512
+ const { freq, byday, bymonthday, bymonth, byweekno, byyearday, byhour, byminute, bysecond, bysetpos } = rrule;
513
+ switch (freq) {
514
+ case "DAILY": {
515
+ if (bymonth && bymonth.length > 0) {
516
+ if (!bymonth.includes(current.getMonth() + 1)) return [];
517
+ }
518
+ dates.push(new Date(current));
519
+ break;
520
+ }
521
+ case "WEEKLY": {
522
+ if (byday && byday.length > 0) {
523
+ const weekStart = getWeekStart(current, wkst);
524
+ for (let i = 0; i < 7; i++) {
525
+ const dayDate = addDays(weekStart, i);
526
+ const dayName = WEEKDAY_REVERSE[dayDate.getDay()];
527
+ if (byday.includes(dayName)) {
528
+ const occurrence = new Date(dayDate);
529
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
530
+ dates.push(occurrence);
531
+ }
532
+ }
533
+ } else {
534
+ dates.push(new Date(current));
535
+ }
536
+ break;
537
+ }
538
+ case "MONTHLY": {
539
+ if (bymonth && bymonth.length > 0) {
540
+ if (!bymonth.includes(current.getMonth() + 1)) return [];
541
+ }
542
+ if (byday && byday.length > 0) {
543
+ for (const day of byday) {
544
+ const parsed = parsePositionalWeekday(day);
545
+ if (!parsed) continue;
546
+ const weekday = WEEKDAY_MAP[parsed.weekday];
547
+ if (parsed.position !== void 0) {
548
+ const matchDate = getWeekdayOfMonth(current, weekday, parsed.position);
549
+ if (matchDate) {
550
+ matchDate.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
551
+ dates.push(matchDate);
552
+ }
553
+ } else {
554
+ const daysInMonth = getDaysInMonth(current.getFullYear(), current.getMonth());
555
+ for (let d = 1; d <= daysInMonth; d++) {
556
+ const testDate = new Date(current.getFullYear(), current.getMonth(), d);
557
+ if (testDate.getDay() === weekday) {
558
+ testDate.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
559
+ dates.push(testDate);
560
+ }
561
+ }
562
+ }
563
+ }
564
+ } else if (bymonthday && bymonthday.length > 0) {
565
+ const daysInMonth = getDaysInMonth(current.getFullYear(), current.getMonth());
566
+ for (const day of bymonthday) {
567
+ let actualDay = day;
568
+ if (day < 0) {
569
+ actualDay = daysInMonth + day + 1;
570
+ }
571
+ if (actualDay >= 1 && actualDay <= daysInMonth) {
572
+ const occurrence = new Date(current.getFullYear(), current.getMonth(), actualDay);
573
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
574
+ dates.push(occurrence);
575
+ }
576
+ }
577
+ } else {
578
+ const dayOfMonth = eventStart.getDate();
579
+ const daysInMonth = getDaysInMonth(current.getFullYear(), current.getMonth());
580
+ const actualDay = Math.min(dayOfMonth, daysInMonth);
581
+ const occurrence = new Date(current.getFullYear(), current.getMonth(), actualDay);
582
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
583
+ dates.push(occurrence);
584
+ }
585
+ break;
586
+ }
587
+ case "YEARLY": {
588
+ const year = current.getFullYear();
589
+ if (byyearday && byyearday.length > 0) {
590
+ for (const yearDay of byyearday) {
591
+ const occurrence = getDateFromYearDay(year, yearDay);
592
+ if (!isNaN(occurrence.getTime())) {
593
+ if (bymonth && bymonth.length > 0 && !bymonth.includes(occurrence.getMonth() + 1)) {
594
+ continue;
595
+ }
596
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
597
+ dates.push(occurrence);
598
+ }
599
+ }
600
+ } else if (byweekno && byweekno.length > 0) {
601
+ const weekDates = getDatesByWeekNumber(year, byweekno, wkst);
602
+ for (const weekDate of weekDates) {
603
+ if (byday && byday.length > 0) {
604
+ const dayName = WEEKDAY_REVERSE[weekDate.getDay()];
605
+ if (!byday.includes(dayName)) continue;
606
+ }
607
+ if (bymonth && bymonth.length > 0 && !bymonth.includes(weekDate.getMonth() + 1)) {
608
+ continue;
609
+ }
610
+ const occurrence = new Date(weekDate);
611
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
612
+ dates.push(occurrence);
613
+ }
614
+ } else if (bymonth && bymonth.length > 0) {
615
+ for (const month of bymonth) {
616
+ const testMonth = month - 1;
617
+ if (byday && byday.length > 0) {
618
+ for (const day of byday) {
619
+ const parsed = parsePositionalWeekday(day);
620
+ if (!parsed) continue;
621
+ const weekday = WEEKDAY_MAP[parsed.weekday];
622
+ if (parsed.position !== void 0) {
623
+ const testDate = new Date(year, testMonth, 1);
624
+ const matchDate = getWeekdayOfMonth(testDate, weekday, parsed.position);
625
+ if (matchDate) {
626
+ matchDate.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
627
+ dates.push(matchDate);
628
+ }
629
+ }
630
+ }
631
+ } else if (bymonthday && bymonthday.length > 0) {
632
+ for (const day of bymonthday) {
633
+ const daysInMonth = getDaysInMonth(year, testMonth);
634
+ let actualDay = day;
635
+ if (day < 0) {
636
+ actualDay = daysInMonth + day + 1;
637
+ }
638
+ if (actualDay >= 1 && actualDay <= daysInMonth) {
639
+ const occurrence = new Date(year, testMonth, actualDay);
640
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
641
+ dates.push(occurrence);
642
+ }
643
+ }
644
+ } else {
645
+ const dayOfMonth = eventStart.getDate();
646
+ const daysInMonth = getDaysInMonth(year, testMonth);
647
+ const actualDay = Math.min(dayOfMonth, daysInMonth);
648
+ const occurrence = new Date(year, testMonth, actualDay);
649
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
650
+ dates.push(occurrence);
651
+ }
652
+ }
653
+ } else {
654
+ const occurrence = new Date(year, eventStart.getMonth(), eventStart.getDate());
655
+ occurrence.setHours(eventStart.getHours(), eventStart.getMinutes(), eventStart.getSeconds(), eventStart.getMilliseconds());
656
+ dates.push(occurrence);
657
+ }
658
+ break;
659
+ }
660
+ }
661
+ if (bysetpos && bysetpos.length > 0 && dates.length > 0) {
662
+ dates.sort((a, b) => a.getTime() - b.getTime());
663
+ const filtered = [];
664
+ for (const pos of bysetpos) {
665
+ let index;
666
+ if (pos > 0) {
667
+ index = pos - 1;
668
+ } else {
669
+ index = dates.length + pos;
670
+ }
671
+ if (index >= 0 && index < dates.length) {
672
+ filtered.push(dates[index]);
673
+ }
674
+ }
675
+ return applyTimeFilters(filtered, byhour, byminute, bysecond);
676
+ }
677
+ return applyTimeFilters(dates, byhour, byminute, bysecond);
678
+ }
679
+ function applyTimeFilters(dates, byhour, byminute, bysecond) {
680
+ if ((!byhour || byhour.length === 0) && (!byminute || byminute.length === 0) && (!bysecond || bysecond.length === 0)) {
681
+ return dates;
682
+ }
683
+ const result = [];
684
+ const hours = byhour && byhour.length > 0 ? byhour : [dates[0]?.getHours() ?? 0];
685
+ const minutes = byminute && byminute.length > 0 ? byminute : [dates[0]?.getMinutes() ?? 0];
686
+ const seconds = bysecond && bysecond.length > 0 ? bysecond : [dates[0]?.getSeconds() ?? 0];
687
+ for (const date of dates) {
688
+ for (const hour of hours) {
689
+ for (const minute of minutes) {
690
+ for (const second of seconds) {
691
+ const occurrence = new Date(date);
692
+ occurrence.setHours(hour, minute, second, 0);
693
+ result.push(occurrence);
694
+ }
695
+ }
696
+ }
697
+ }
698
+ return result;
699
+ }
700
+ function getWeekStart(date, wkst) {
701
+ const d = new Date(date);
702
+ const day = d.getDay();
703
+ const diff = (day - wkst + 7) % 7;
704
+ d.setDate(d.getDate() - diff);
705
+ d.setHours(0, 0, 0, 0);
706
+ return d;
707
+ }
708
+ function advanceToNextPeriod(date, freq, interval) {
709
+ switch (freq) {
710
+ case "DAILY":
711
+ return addDays(date, interval);
712
+ case "WEEKLY":
713
+ return addDays(date, 7 * interval);
714
+ case "MONTHLY":
715
+ return addMonths(date, interval);
716
+ case "YEARLY":
717
+ return addYears(date, interval);
718
+ default:
719
+ return addDays(date, 1);
720
+ }
721
+ }
722
+ function createRRule(options) {
723
+ return {
724
+ freq: options.freq,
725
+ interval: options.interval || 1,
726
+ count: options.count,
727
+ until: options.until,
728
+ byday: options.byday,
729
+ bymonthday: options.bymonthday,
730
+ bymonth: options.bymonth,
731
+ byweekno: options.byweekno,
732
+ byyearday: options.byyearday,
733
+ byhour: options.byhour,
734
+ byminute: options.byminute,
735
+ bysecond: options.bysecond,
736
+ bysetpos: options.bysetpos,
737
+ wkst: options.wkst || "MO"
738
+ };
739
+ }
740
+ function daily(interval = 1) {
741
+ return createRRule({ freq: "DAILY", interval });
742
+ }
743
+ function weekly(interval = 1, weekdays2) {
744
+ return createRRule({ freq: "WEEKLY", interval, byday: weekdays2 });
745
+ }
746
+ function monthly(interval = 1, options) {
747
+ return createRRule({
748
+ freq: "MONTHLY",
749
+ interval,
750
+ bymonthday: options?.bymonthday,
751
+ byday: options?.byday
752
+ });
753
+ }
754
+ function yearly(interval = 1, options) {
755
+ return createRRule({
756
+ freq: "YEARLY",
757
+ interval,
758
+ bymonth: options?.bymonth,
759
+ bymonthday: options?.bymonthday
760
+ });
761
+ }
762
+ function weekdays() {
763
+ return weekly(1, ["MO", "TU", "WE", "TH", "FR"]);
764
+ }
765
+ function everyNthWeekday(n, weekday) {
766
+ return createRRule({
767
+ freq: "MONTHLY",
768
+ byday: [`${n}${weekday}`]
769
+ });
770
+ }
771
+ function lastWeekdayOfMonth(weekday) {
772
+ return createRRule({
773
+ freq: "MONTHLY",
774
+ byday: [`-1${weekday}`]
775
+ });
776
+ }
777
+ function describeRRule(rrule, localeOrOptions = "en", displayOptions) {
778
+ const options = typeof rrule === "string" ? parseRRule(rrule) : rrule;
779
+ if (!options) return "";
780
+ const interval = options.interval || 1;
781
+ const { formatter, formatNumber } = createRecurrenceDescriptionFormatter(localeOrOptions, displayOptions);
782
+ const formattedInterval = formatNumber(interval);
783
+ const parts = [];
784
+ switch (options.freq) {
785
+ case "DAILY":
786
+ parts.push(interval === 1 ? "Daily" : `Every ${formattedInterval} days`);
787
+ break;
788
+ case "WEEKLY":
789
+ if (options.byday && options.byday.length > 0) {
790
+ const dayNames = options.byday.map((d) => formatWeekdayName(d, formatter));
791
+ if (interval === 1) {
792
+ parts.push(`Weekly on ${dayNames.join(", ")}`);
793
+ } else {
794
+ parts.push(`Every ${formattedInterval} weeks on ${dayNames.join(", ")}`);
795
+ }
796
+ } else {
797
+ parts.push(interval === 1 ? "Weekly" : `Every ${formattedInterval} weeks`);
798
+ }
799
+ break;
800
+ case "MONTHLY":
801
+ if (options.byday && options.byday.length > 0) {
802
+ const descriptions = options.byday.map((d) => {
803
+ const parsed = parsePositionalWeekday(d);
804
+ if (!parsed) return d;
805
+ const dayName = formatWeekdayName(parsed.weekday, formatter);
806
+ if (parsed.position === 1) return `first ${dayName}`;
807
+ if (parsed.position === 2) return `second ${dayName}`;
808
+ if (parsed.position === 3) return `third ${dayName}`;
809
+ if (parsed.position === 4) return `fourth ${dayName}`;
810
+ if (parsed.position === -1) return `last ${dayName}`;
811
+ return dayName;
812
+ });
813
+ parts.push(interval === 1 ? `Monthly on the ${descriptions.join(", ")}` : `Every ${formattedInterval} months on the ${descriptions.join(", ")}`);
814
+ } else if (options.bymonthday && options.bymonthday.length > 0) {
815
+ const days = formatNumberList(options.bymonthday, formatNumber);
816
+ parts.push(interval === 1 ? `Monthly on day ${days}` : `Every ${formattedInterval} months on day ${days}`);
817
+ } else {
818
+ parts.push(interval === 1 ? "Monthly" : `Every ${formattedInterval} months`);
819
+ }
820
+ break;
821
+ case "YEARLY": {
822
+ let yearlyDesc = interval === 1 ? "Yearly" : `Every ${formattedInterval} years`;
823
+ if (options.byyearday && options.byyearday.length > 0) {
824
+ const dayDescs = options.byyearday.map((d) => d < 0 ? `${formatNumber(d)} from end` : `day ${formatNumber(d)}`);
825
+ yearlyDesc += ` on ${dayDescs.join(", ")}`;
826
+ } else if (options.byweekno && options.byweekno.length > 0) {
827
+ const weekDescs = options.byweekno.map((w) => w < 0 ? `${formatNumber(w)} from end` : `week ${formatNumber(w)}`);
828
+ yearlyDesc += ` in ${weekDescs.join(", ")}`;
829
+ if (options.byday && options.byday.length > 0) {
830
+ const dayNames = options.byday.map((d) => formatWeekdayName(d, formatter));
831
+ yearlyDesc += ` on ${dayNames.join(", ")}`;
832
+ }
833
+ } else if (options.bymonth && options.bymonth.length > 0) {
834
+ const monthNames = options.bymonth.map((m) => formatMonthName(m, formatter));
835
+ yearlyDesc += ` in ${monthNames.join(", ")}`;
836
+ if (options.byday && options.byday.length > 0) {
837
+ const descriptions = options.byday.map((d) => {
838
+ const parsed = parsePositionalWeekday(d);
839
+ if (!parsed) return d;
840
+ const dayName = formatWeekdayName(parsed.weekday, formatter);
841
+ if (parsed.position === 1) return `first ${dayName}`;
842
+ if (parsed.position === 2) return `second ${dayName}`;
843
+ if (parsed.position === 3) return `third ${dayName}`;
844
+ if (parsed.position === 4) return `fourth ${dayName}`;
845
+ if (parsed.position === -1) return `last ${dayName}`;
846
+ return dayName;
847
+ });
848
+ yearlyDesc += ` on the ${descriptions.join(", ")}`;
849
+ } else if (options.bymonthday && options.bymonthday.length > 0) {
850
+ yearlyDesc += ` on day ${formatNumberList(options.bymonthday, formatNumber)}`;
851
+ }
852
+ }
853
+ parts.push(yearlyDesc);
854
+ break;
855
+ }
856
+ }
857
+ if (options.byhour && options.byhour.length > 0) {
858
+ const hourDescs = options.byhour.map((h) => `${formatNumber(h)}:00`);
859
+ parts.push(`at ${hourDescs.join(", ")}`);
860
+ }
861
+ if (options.count) {
862
+ parts.push(`${formatNumber(options.count)} times`);
863
+ } else if (options.until) {
864
+ const untilDate = typeof options.until === "string" ? new Date(options.until) : options.until;
865
+ const formatted = formatter.format(untilDate, { dateStyle: "medium" });
866
+ parts.push(`until ${formatted}`);
867
+ }
868
+ return parts.join(", ");
869
+ }
870
+
871
+ export { createRRule, daily, describeRRule, everyNthWeekday, expandRRule, expandRecurringSeries, lastWeekdayOfMonth, monthly, parseRRule, serializeRRule, weekdays, weekly, yearly };