kalendly 0.1.7 → 0.2.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.
Files changed (38) hide show
  1. package/README.md +317 -681
  2. package/dist/core/index.js +3 -3
  3. package/dist/index.d.mts +48 -602
  4. package/dist/index.d.ts +48 -602
  5. package/dist/index.js +753 -2359
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +727 -2348
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/{vanilla/index.umd.js → index.umd.js} +218 -218
  10. package/dist/index.umd.js.map +1 -0
  11. package/package.json +41 -91
  12. package/dist/react/index.d.mts +0 -251
  13. package/dist/react/index.d.ts +0 -251
  14. package/dist/react/index.js +0 -969
  15. package/dist/react/index.js.map +0 -1
  16. package/dist/react/index.mjs +0 -924
  17. package/dist/react/index.mjs.map +0 -1
  18. package/dist/react-native/index.d.mts +0 -642
  19. package/dist/react-native/index.d.ts +0 -642
  20. package/dist/react-native/index.js +0 -1649
  21. package/dist/react-native/index.js.map +0 -1
  22. package/dist/react-native/index.mjs +0 -1615
  23. package/dist/react-native/index.mjs.map +0 -1
  24. package/dist/vanilla/index.d.mts +0 -271
  25. package/dist/vanilla/index.d.ts +0 -271
  26. package/dist/vanilla/index.js +0 -1064
  27. package/dist/vanilla/index.js.map +0 -1
  28. package/dist/vanilla/index.mjs +0 -1013
  29. package/dist/vanilla/index.mjs.map +0 -1
  30. package/dist/vanilla/index.umd.js.map +0 -1
  31. package/dist/vue/components/Calendar.vue.d.ts +0 -43
  32. package/dist/vue/components/Calendar.vue.d.ts.map +0 -1
  33. package/dist/vue/index.d.ts +0 -134
  34. package/dist/vue/index.d.ts.map +0 -1
  35. package/dist/vue/index.js +0 -1
  36. package/dist/vue/index.mjs +0 -717
  37. package/dist/vue/types.d.ts +0 -21
  38. package/dist/vue/types.d.ts.map +0 -1
@@ -1,1649 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/react-native/index.tsx
21
- var index_exports = {};
22
- __export(index_exports, {
23
- Calendar: () => Calendar,
24
- CalendarEngine: () => CalendarEngine,
25
- DAYS: () => DAYS,
26
- DEFAULT_CATEGORY_COLORS: () => DEFAULT_CATEGORY_COLORS,
27
- DatePopup: () => DatePopup,
28
- MONTHS: () => MONTHS,
29
- MONTHS_FULL: () => MONTHS_FULL,
30
- calendarStyles: () => calendarStyles,
31
- formatAttendees: () => formatAttendees,
32
- formatDateForDisplay: () => formatDateForDisplay,
33
- formatTimeRange: () => formatTimeRange,
34
- generateCalendarDates: () => generateCalendarDates,
35
- generateYears: () => generateYears,
36
- getCategoryColor: () => getCategoryColor,
37
- getCellClasses: () => getCellClasses,
38
- getDefaultEventColor: () => getDefaultEventColor,
39
- getEventsForDate: () => getEventsForDate,
40
- getMonthYearText: () => getMonthYearText,
41
- getPopupPositionClass: () => getPopupPositionClass,
42
- hasEvents: () => hasEvents,
43
- isSameDay: () => isSameDay,
44
- isToday: () => isToday,
45
- isValidHexColor: () => isValidHexColor,
46
- mergeCategoryColors: () => mergeCategoryColors,
47
- normalizeDate: () => normalizeDate,
48
- sortEventsByTime: () => sortEventsByTime
49
- });
50
- module.exports = __toCommonJS(index_exports);
51
-
52
- // src/react-native/components/Calendar.tsx
53
- var import_react = require("react");
54
- var import_react_native3 = require("react-native");
55
-
56
- // src/core/utils.ts
57
- var MONTHS = [
58
- "Jan",
59
- "Feb",
60
- "Mar",
61
- "Apr",
62
- "May",
63
- "Jun",
64
- "Jul",
65
- "Aug",
66
- "Sep",
67
- "Oct",
68
- "Nov",
69
- "Dec"
70
- ];
71
- var MONTHS_FULL = [
72
- "January",
73
- "February",
74
- "March",
75
- "April",
76
- "May",
77
- "June",
78
- "July",
79
- "August",
80
- "September",
81
- "October",
82
- "November",
83
- "December"
84
- ];
85
- var DAYS = [
86
- "Sunday",
87
- "Monday",
88
- "Tuesday",
89
- "Wednesday",
90
- "Thursday",
91
- "Friday",
92
- "Saturday"
93
- ];
94
- function normalizeDate(date) {
95
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
96
- }
97
- function isSameDay(date1, date2) {
98
- return normalizeDate(date1).getTime() === normalizeDate(date2).getTime();
99
- }
100
- function isToday(date) {
101
- return isSameDay(date, /* @__PURE__ */ new Date());
102
- }
103
- function generateYears(minYear, maxYear) {
104
- const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
105
- const min = minYear ?? currentYear - 30;
106
- const max = maxYear ?? currentYear + 10;
107
- return Array.from({ length: max - min + 1 }, (_, i) => min + i);
108
- }
109
- function getEventsForDate(events, date) {
110
- const normalizedTargetDate = normalizeDate(date);
111
- return events.filter((event) => {
112
- const eventDate = normalizeDate(new Date(event.date));
113
- return eventDate.getTime() === normalizedTargetDate.getTime();
114
- });
115
- }
116
- function hasEvents(events, date) {
117
- return getEventsForDate(events, date).length > 0;
118
- }
119
- function generateCalendarDates(year, month, events = [], weekStartsOn = 0) {
120
- const firstDay = new Date(year, month, 1);
121
- const lastDay = new Date(year, month + 1, 0);
122
- const daysInMonth = lastDay.getDate();
123
- const prevMonthLastDay = new Date(year, month, 0).getDate();
124
- let firstDayOfWeek = firstDay.getDay();
125
- if (weekStartsOn === 1) {
126
- firstDayOfWeek = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;
127
- }
128
- const dates = [];
129
- let day = 1;
130
- let nextMonthDay = 1;
131
- for (let week = 0; week < 6; week++) {
132
- const weekDates = [];
133
- for (let dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
134
- if (week === 0 && dayOfWeek < firstDayOfWeek) {
135
- const prevDay = prevMonthLastDay - firstDayOfWeek + dayOfWeek + 1;
136
- const prevDate = new Date(year, month - 1, prevDay);
137
- const dateEvents = getEventsForDate(events, prevDate);
138
- weekDates.push({
139
- date: prevDate,
140
- isCurrentMonth: false,
141
- isToday: isToday(prevDate),
142
- hasEvents: dateEvents.length > 0,
143
- events: dateEvents
144
- });
145
- } else if (day > daysInMonth) {
146
- const nextDate = new Date(year, month + 1, nextMonthDay);
147
- const dateEvents = getEventsForDate(events, nextDate);
148
- weekDates.push({
149
- date: nextDate,
150
- isCurrentMonth: false,
151
- isToday: isToday(nextDate),
152
- hasEvents: dateEvents.length > 0,
153
- events: dateEvents
154
- });
155
- nextMonthDay++;
156
- } else {
157
- const currentDate = new Date(year, month, day);
158
- const dateEvents = getEventsForDate(events, currentDate);
159
- weekDates.push({
160
- date: currentDate,
161
- isCurrentMonth: true,
162
- isToday: isToday(currentDate),
163
- hasEvents: dateEvents.length > 0,
164
- events: dateEvents
165
- });
166
- day++;
167
- }
168
- }
169
- dates.push(weekDates);
170
- }
171
- return dates;
172
- }
173
- function getPopupPositionClass(selectedDayIndex) {
174
- if (selectedDayIndex === null) return "popup-center-bottom";
175
- if (selectedDayIndex < 3) {
176
- return "popup-right";
177
- } else if (selectedDayIndex > 4) {
178
- return "popup-left";
179
- } else {
180
- return "popup-center-bottom";
181
- }
182
- }
183
- function getCellClasses(calendarDate) {
184
- const classes = [];
185
- if (!calendarDate.isCurrentMonth) {
186
- classes.push("other-month");
187
- }
188
- if (calendarDate.isToday) {
189
- classes.push("schedule--current--exam");
190
- }
191
- if (calendarDate.hasEvents) {
192
- classes.push("has--event");
193
- }
194
- return classes;
195
- }
196
- function formatDateForDisplay(date) {
197
- return `${DAYS[date.getDay()]} ${date.getDate()}`;
198
- }
199
- function getMonthYearText(year, month) {
200
- return `${MONTHS_FULL[month]} ${year}`;
201
- }
202
- function formatTimeRange(event) {
203
- if (event.allDay || !event.startTime && !event.endTime) {
204
- return "All day";
205
- }
206
- if (event.startTime && event.endTime) {
207
- return `${event.startTime} - ${event.endTime}`;
208
- }
209
- if (event.startTime) {
210
- return `${event.startTime}`;
211
- }
212
- return "";
213
- }
214
- function formatAttendees(attendees) {
215
- if (!attendees || attendees.length === 0) return "";
216
- if (attendees.length === 1) return attendees[0];
217
- if (attendees.length === 2) return attendees.join(" and ");
218
- return `${attendees.slice(0, -1).join(", ")}, and ${attendees[attendees.length - 1]}`;
219
- }
220
- function sortEventsByTime(events) {
221
- return [...events].sort((a, b) => {
222
- const aAllDay = a.allDay || !a.startTime && !a.endTime;
223
- const bAllDay = b.allDay || !b.startTime && !b.endTime;
224
- if (aAllDay && !bAllDay) return -1;
225
- if (!aAllDay && bAllDay) return 1;
226
- if (!a.startTime || !b.startTime) return 0;
227
- return a.startTime.localeCompare(b.startTime);
228
- });
229
- }
230
- var DEFAULT_CATEGORY_COLORS = {
231
- work: "#3b82f6",
232
- personal: "#8b5cf6",
233
- meeting: "#10b981",
234
- deadline: "#ef4444",
235
- appointment: "#f59e0b",
236
- other: "#6b7280"
237
- };
238
- function getDefaultEventColor(category, customColors) {
239
- const colorMap = customColors || DEFAULT_CATEGORY_COLORS;
240
- if (category && colorMap[category]) {
241
- return colorMap[category];
242
- }
243
- return "#fc8917";
244
- }
245
- function mergeCategoryColors(customColors) {
246
- return {
247
- ...DEFAULT_CATEGORY_COLORS,
248
- ...customColors
249
- };
250
- }
251
- function isValidHexColor(color) {
252
- return /^#([0-9A-F]{3}){1,2}$/i.test(color);
253
- }
254
- function getCategoryColor(category, customColors) {
255
- const colorMap = mergeCategoryColors(customColors);
256
- const color = colorMap[category] || colorMap.other || "#fc8917";
257
- return isValidHexColor(color) ? color : "#fc8917";
258
- }
259
-
260
- // src/core/calendar-engine.ts
261
- var CalendarEngine = class {
262
- constructor(config) {
263
- this.listeners = /* @__PURE__ */ new Set();
264
- this.config = config;
265
- this.categoryColors = mergeCategoryColors(config.categoryColors);
266
- const initialDate = config.initialDate || /* @__PURE__ */ new Date();
267
- this.state = {
268
- currentYear: initialDate.getFullYear(),
269
- currentMonth: initialDate.getMonth(),
270
- currentDate: initialDate.getDate(),
271
- selectedDate: null,
272
- selectedDayIndex: null,
273
- tasks: []
274
- };
275
- }
276
- /**
277
- * Subscribe to state changes
278
- */
279
- subscribe(listener) {
280
- this.listeners.add(listener);
281
- return () => this.listeners.delete(listener);
282
- }
283
- /**
284
- * Notify all listeners of state changes
285
- */
286
- notify() {
287
- this.listeners.forEach((listener) => listener());
288
- }
289
- /**
290
- * Get current state
291
- */
292
- getState() {
293
- return { ...this.state };
294
- }
295
- /**
296
- * Get view model with computed properties
297
- */
298
- getViewModel() {
299
- const calendarDates = generateCalendarDates(
300
- this.state.currentYear,
301
- this.state.currentMonth,
302
- this.config.events,
303
- this.config.weekStartsOn
304
- );
305
- return {
306
- ...this.state,
307
- months: MONTHS,
308
- days: DAYS,
309
- years: generateYears(this.config.minYear, this.config.maxYear),
310
- monthAndYearText: getMonthYearText(
311
- this.state.currentYear,
312
- this.state.currentMonth
313
- ),
314
- scheduleDay: this.state.selectedDate ? formatDateForDisplay(this.state.selectedDate) : "",
315
- calendarDates,
316
- popupPositionClass: getPopupPositionClass(this.state.selectedDayIndex)
317
- };
318
- }
319
- /**
320
- * Get actions object
321
- */
322
- getActions() {
323
- return {
324
- next: this.next.bind(this),
325
- previous: this.previous.bind(this),
326
- jump: this.jump.bind(this),
327
- goToToday: this.goToToday.bind(this),
328
- isCurrentMonth: this.isCurrentMonth.bind(this),
329
- selectDate: this.selectDate.bind(this),
330
- updateTasks: this.updateTasks.bind(this)
331
- };
332
- }
333
- /**
334
- * Navigate to next month
335
- */
336
- next() {
337
- if (this.state.currentMonth === 11) {
338
- this.state.currentMonth = 0;
339
- this.state.currentYear++;
340
- } else {
341
- this.state.currentMonth++;
342
- }
343
- this.state.selectedDate = null;
344
- this.state.selectedDayIndex = null;
345
- this.updateTasks();
346
- this.notify();
347
- }
348
- /**
349
- * Navigate to previous month
350
- */
351
- previous() {
352
- if (this.state.currentMonth === 0) {
353
- this.state.currentMonth = 11;
354
- this.state.currentYear--;
355
- } else {
356
- this.state.currentMonth--;
357
- }
358
- this.state.selectedDate = null;
359
- this.state.selectedDayIndex = null;
360
- this.updateTasks();
361
- this.notify();
362
- }
363
- /**
364
- * Jump to specific month and year
365
- */
366
- jump(year, month) {
367
- this.state.currentYear = year;
368
- this.state.currentMonth = month;
369
- this.state.selectedDate = null;
370
- this.state.selectedDayIndex = null;
371
- this.updateTasks();
372
- this.notify();
373
- }
374
- /**
375
- * Navigate to current month (today)
376
- */
377
- goToToday() {
378
- const today = /* @__PURE__ */ new Date();
379
- this.state.currentYear = today.getFullYear();
380
- this.state.currentMonth = today.getMonth();
381
- this.state.selectedDate = null;
382
- this.state.selectedDayIndex = null;
383
- this.updateTasks();
384
- this.notify();
385
- }
386
- /**
387
- * Check if currently viewing today's month
388
- */
389
- isCurrentMonth() {
390
- const today = /* @__PURE__ */ new Date();
391
- return this.state.currentYear === today.getFullYear() && this.state.currentMonth === today.getMonth();
392
- }
393
- /**
394
- * Select a specific date
395
- */
396
- selectDate(date, dayIndex) {
397
- this.state.selectedDate = date;
398
- this.state.selectedDayIndex = dayIndex ?? null;
399
- this.state.currentDate = date.getDate();
400
- this.state.currentMonth = date.getMonth();
401
- this.state.currentYear = date.getFullYear();
402
- this.updateTasks();
403
- this.notify();
404
- }
405
- /**
406
- * Update tasks for the currently selected date
407
- */
408
- updateTasks() {
409
- if (!this.state.selectedDate) {
410
- this.state.tasks = [];
411
- return;
412
- }
413
- this.state.tasks = getEventsForDate(
414
- this.config.events,
415
- this.state.selectedDate
416
- );
417
- }
418
- /**
419
- * Update events configuration
420
- */
421
- updateEvents(events) {
422
- this.config.events = events;
423
- this.updateTasks();
424
- this.notify();
425
- }
426
- /**
427
- * Handle date cell click
428
- */
429
- handleDateClick(date, dayIndex) {
430
- this.selectDate(date, dayIndex);
431
- }
432
- /**
433
- * Check if date has events
434
- */
435
- hasEventsForDate(date) {
436
- return getEventsForDate(this.config.events, date).length > 0;
437
- }
438
- /**
439
- * Get events for a specific date
440
- */
441
- getEventsForDate(date) {
442
- return getEventsForDate(this.config.events, date);
443
- }
444
- /**
445
- * Clear selected date
446
- */
447
- clearSelection() {
448
- this.state.selectedDate = null;
449
- this.state.selectedDayIndex = null;
450
- this.state.tasks = [];
451
- this.notify();
452
- }
453
- /**
454
- * Get category color (with custom colors support)
455
- */
456
- getCategoryColor(category) {
457
- if (!category) return "#fc8917";
458
- return getCategoryColor(category, this.categoryColors);
459
- }
460
- /**
461
- * Update category colors dynamically
462
- */
463
- updateCategoryColors(colors) {
464
- this.categoryColors = mergeCategoryColors(colors);
465
- this.notify();
466
- }
467
- /**
468
- * Get all category colors
469
- */
470
- getCategoryColors() {
471
- return { ...this.categoryColors };
472
- }
473
- /**
474
- * Register a new category with color
475
- */
476
- registerCategory(name, color) {
477
- this.categoryColors[name] = color;
478
- this.notify();
479
- }
480
- /**
481
- * Destroy the engine and cleanup listeners
482
- */
483
- destroy() {
484
- this.listeners.clear();
485
- }
486
- };
487
-
488
- // src/react-native/components/DatePopup.tsx
489
- var import_react_native2 = require("react-native");
490
-
491
- // src/styles/react-native-styles.ts
492
- var import_react_native = require("react-native");
493
- var defaultColors = {
494
- primary: "#fc8917",
495
- secondary: "#fca045",
496
- tertiary: "#fdb873",
497
- text: "#2c3e50",
498
- border: "#dee2e6",
499
- todayOutline: "#f7db04",
500
- eventIndicator: "#1890ff",
501
- background: "#fff",
502
- white: "#ffffff",
503
- scrollHint: "#fff3e0",
504
- scrollHintText: "#f59e0b"
505
- };
506
- var getResponsiveStyles = (width, height, customColors) => {
507
- const colors = { ...defaultColors, ...customColors };
508
- const isTablet = width >= 768;
509
- const isSmallPhone = width < 375;
510
- const isPhone = width < 768;
511
- const cellSize = (width - 60) / 7;
512
- const popupWidth = isTablet ? 500 : isPhone ? width * 0.95 : width * 0.9;
513
- const popupMaxWidth = isTablet ? 500 : isPhone ? width : 400;
514
- const popupMaxHeight = isTablet ? height * 0.8 : height * 0.85;
515
- const headerFontSize = isTablet ? 18 : isSmallPhone ? 15 : 16;
516
- const eventTitleSize = isTablet ? 16 : isSmallPhone ? 14 : 15;
517
- const eventDetailSize = isTablet ? 13 : isSmallPhone ? 11 : 12;
518
- const badgeFontSize = isTablet ? 10 : isSmallPhone ? 9 : 9;
519
- const eventCardPadding = isTablet ? 14 : isSmallPhone ? 10 : 12;
520
- const containerPadding = isTablet ? 15 : isSmallPhone ? 10 : 12;
521
- return import_react_native.StyleSheet.create({
522
- container: {
523
- flex: 1,
524
- backgroundColor: colors.background
525
- },
526
- titleContainer: {
527
- paddingVertical: 20,
528
- alignItems: "center"
529
- },
530
- title: {
531
- fontSize: 24,
532
- fontWeight: "600",
533
- color: colors.text
534
- },
535
- contentContainer: {
536
- marginHorizontal: 20,
537
- marginTop: 20
538
- },
539
- card: {
540
- backgroundColor: colors.background,
541
- borderRadius: 8,
542
- shadowColor: "#000",
543
- shadowOffset: {
544
- width: 0,
545
- height: 2
546
- },
547
- shadowOpacity: 0.1,
548
- shadowRadius: 3.84,
549
- elevation: 5,
550
- overflow: "hidden"
551
- },
552
- cardHeader: {
553
- backgroundColor: colors.tertiary,
554
- paddingVertical: 15,
555
- paddingHorizontal: 20,
556
- borderBottomWidth: 1,
557
- borderBottomColor: colors.border
558
- },
559
- cardHeaderText: {
560
- fontSize: 18,
561
- fontWeight: "500",
562
- color: colors.text,
563
- textAlign: "center"
564
- },
565
- table: {
566
- backgroundColor: colors.background
567
- },
568
- tableHeader: {
569
- flexDirection: "row",
570
- backgroundColor: "rgba(252, 137, 23, 0.1)",
571
- borderBottomWidth: 2,
572
- borderBottomColor: colors.border
573
- },
574
- tableHeaderCell: {
575
- flex: 1,
576
- paddingVertical: 12,
577
- borderRightWidth: 1,
578
- borderRightColor: colors.border,
579
- alignItems: "center",
580
- justifyContent: "center"
581
- },
582
- tableHeaderText: {
583
- fontSize: 14,
584
- fontWeight: "600",
585
- color: colors.text
586
- },
587
- tableRow: {
588
- flexDirection: "row",
589
- borderBottomWidth: 1,
590
- borderBottomColor: colors.border
591
- },
592
- tableCell: {
593
- flex: 1,
594
- height: cellSize,
595
- borderRightWidth: 1,
596
- borderRightColor: colors.border,
597
- alignItems: "center",
598
- justifyContent: "center",
599
- position: "relative"
600
- },
601
- tableCellText: {
602
- fontSize: 16,
603
- color: colors.text
604
- },
605
- cellToday: {
606
- borderWidth: 2,
607
- borderColor: colors.todayOutline
608
- },
609
- cellTodayText: {
610
- fontWeight: "bold"
611
- },
612
- cellWithEvents: {
613
- backgroundColor: "rgba(252, 160, 69, 0.3)"
614
- },
615
- eventIndicator: {
616
- position: "absolute",
617
- bottom: 2,
618
- width: 4,
619
- height: 4,
620
- backgroundColor: colors.eventIndicator,
621
- borderRadius: 2
622
- },
623
- navigationContainer: {
624
- flexDirection: "row",
625
- justifyContent: "space-between",
626
- paddingHorizontal: 20,
627
- paddingVertical: 20,
628
- gap: 15
629
- },
630
- navigationButton: {
631
- flex: 1,
632
- backgroundColor: "transparent",
633
- borderWidth: 1,
634
- borderColor: colors.primary,
635
- borderRadius: 6,
636
- paddingVertical: 12,
637
- paddingHorizontal: 16,
638
- alignItems: "center",
639
- justifyContent: "center"
640
- },
641
- navigationButtonText: {
642
- color: colors.primary,
643
- fontSize: 16,
644
- fontWeight: "500"
645
- },
646
- navigationButtonPressed: {
647
- backgroundColor: colors.primary
648
- },
649
- navigationButtonTextPressed: {
650
- color: colors.white
651
- },
652
- jumpForm: {
653
- flexDirection: "row",
654
- alignItems: "center",
655
- justifyContent: "center",
656
- paddingHorizontal: 20,
657
- paddingBottom: 20,
658
- gap: 10
659
- },
660
- jumpLabel: {
661
- fontSize: 18,
662
- fontWeight: "300",
663
- color: colors.text
664
- },
665
- jumpSelect: {
666
- borderWidth: 1,
667
- borderColor: colors.border,
668
- borderRadius: 6,
669
- paddingHorizontal: 12,
670
- paddingVertical: 8,
671
- backgroundColor: colors.background,
672
- minWidth: 80
673
- },
674
- jumpSelectText: {
675
- fontSize: 16,
676
- color: colors.text,
677
- textAlign: "center"
678
- },
679
- // RESPONSIVE POPUP STYLES
680
- popupOverlay: {
681
- position: "absolute",
682
- top: 0,
683
- left: 0,
684
- right: 0,
685
- bottom: 0,
686
- backgroundColor: "rgba(0, 0, 0, 0.5)",
687
- justifyContent: "center",
688
- alignItems: "center",
689
- zIndex: 1e3
690
- },
691
- popup: {
692
- backgroundColor: colors.white,
693
- borderRadius: 8,
694
- width: popupWidth,
695
- maxWidth: popupMaxWidth,
696
- maxHeight: popupMaxHeight,
697
- shadowColor: "#000",
698
- shadowOffset: {
699
- width: 0,
700
- height: 4
701
- },
702
- shadowOpacity: 0.3,
703
- shadowRadius: 6,
704
- elevation: 8,
705
- overflow: "hidden"
706
- },
707
- popupHeader: {
708
- backgroundColor: colors.primary,
709
- paddingVertical: isTablet ? 15 : 12,
710
- paddingHorizontal: isTablet ? 20 : 15,
711
- flexDirection: "row",
712
- justifyContent: "space-between",
713
- alignItems: "center"
714
- },
715
- popupHeaderText: {
716
- fontSize: headerFontSize,
717
- fontWeight: "600",
718
- color: colors.white,
719
- flex: 1
720
- },
721
- popupCloseButton: {
722
- width: isTablet ? 32 : isSmallPhone ? 26 : 28,
723
- height: isTablet ? 32 : isSmallPhone ? 26 : 28,
724
- backgroundColor: "rgba(255, 255, 255, 0.2)",
725
- borderRadius: 16,
726
- alignItems: "center",
727
- justifyContent: "center"
728
- },
729
- popupCloseText: {
730
- color: colors.white,
731
- fontSize: isTablet ? 20 : isSmallPhone ? 16 : 18,
732
- fontWeight: "bold"
733
- },
734
- scrollHint: {
735
- backgroundColor: colors.scrollHint,
736
- paddingVertical: isTablet ? 10 : 8,
737
- paddingHorizontal: containerPadding,
738
- alignItems: "center"
739
- },
740
- scrollHintText: {
741
- color: colors.scrollHintText,
742
- fontSize: isTablet ? 13 : isSmallPhone ? 11 : 12,
743
- fontWeight: "500"
744
- },
745
- eventsContainer: {
746
- maxHeight: popupMaxHeight - 150
747
- },
748
- eventsList: {
749
- padding: containerPadding,
750
- gap: isTablet ? 12 : 10
751
- },
752
- eventCard: {
753
- backgroundColor: colors.white,
754
- borderRadius: 6,
755
- padding: eventCardPadding,
756
- borderLeftWidth: 4,
757
- borderLeftColor: colors.primary,
758
- borderWidth: 1,
759
- borderColor: "#e5e7eb",
760
- shadowColor: "#000",
761
- shadowOffset: {
762
- width: 0,
763
- height: 1
764
- },
765
- shadowOpacity: 0.05,
766
- shadowRadius: 2,
767
- elevation: 1
768
- },
769
- eventHeader: {
770
- marginBottom: 10
771
- },
772
- eventTitle: {
773
- fontSize: eventTitleSize,
774
- color: "#1f2937",
775
- fontWeight: "600",
776
- marginBottom: 8
777
- },
778
- eventBadges: {
779
- flexDirection: "row",
780
- gap: 6,
781
- flexWrap: "wrap"
782
- },
783
- badge: {
784
- paddingHorizontal: isTablet ? 8 : 6,
785
- paddingVertical: isTablet ? 3 : 2,
786
- borderRadius: 10
787
- },
788
- badgeText: {
789
- fontSize: badgeFontSize,
790
- fontWeight: "600",
791
- textTransform: "uppercase",
792
- letterSpacing: 0.3
793
- },
794
- priorityBadgeHigh: {
795
- backgroundColor: "#fee2e2"
796
- },
797
- priorityBadgeMedium: {
798
- backgroundColor: "#fef3c7"
799
- },
800
- priorityBadgeLow: {
801
- backgroundColor: "#dcfce7"
802
- },
803
- statusBadgeCompleted: {
804
- backgroundColor: "#d1fae5"
805
- },
806
- statusBadgeCancelled: {
807
- backgroundColor: "#fee2e2"
808
- },
809
- statusBadgeTentative: {
810
- backgroundColor: "#e0e7ff"
811
- },
812
- categoryBadgeWork: {
813
- backgroundColor: "#dbeafe"
814
- },
815
- categoryBadgePersonal: {
816
- backgroundColor: "#fef3c7"
817
- },
818
- categoryBadgeMeeting: {
819
- backgroundColor: "#d1fae5"
820
- },
821
- categoryBadgeDeadline: {
822
- backgroundColor: "#fee2e2"
823
- },
824
- categoryBadgeAppointment: {
825
- backgroundColor: "#fef3c7"
826
- },
827
- categoryBadgeOther: {
828
- backgroundColor: "#f3f4f6"
829
- },
830
- eventTime: {
831
- flexDirection: isSmallPhone ? "column" : "row",
832
- gap: isSmallPhone ? 2 : 8,
833
- marginBottom: 6
834
- },
835
- eventTimeLabel: {
836
- fontSize: eventDetailSize,
837
- fontWeight: "600",
838
- color: "#6b7280",
839
- minWidth: isSmallPhone ? void 0 : isTablet ? 80 : 70,
840
- textAlign: "left"
841
- },
842
- eventTimeValue: {
843
- fontSize: eventDetailSize,
844
- color: "#374151",
845
- flex: 1
846
- },
847
- eventDescription: {
848
- color: "#4b5563",
849
- fontSize: eventDetailSize,
850
- lineHeight: isTablet ? 20 : 18,
851
- marginTop: 10,
852
- marginBottom: 10,
853
- paddingVertical: 8,
854
- paddingHorizontal: 12,
855
- backgroundColor: "#f9fafb",
856
- borderLeftWidth: 2,
857
- borderLeftColor: "#e5e7eb",
858
- borderRadius: 4,
859
- textAlign: "left"
860
- },
861
- eventUrlContainer: {
862
- marginTop: 8
863
- },
864
- eventLink: {
865
- color: "#2563eb",
866
- fontSize: eventDetailSize,
867
- fontWeight: "500"
868
- },
869
- eventTags: {
870
- flexDirection: "row",
871
- flexWrap: "wrap",
872
- gap: 6,
873
- marginTop: 8
874
- },
875
- eventTag: {
876
- paddingHorizontal: isTablet ? 10 : 8,
877
- paddingVertical: isTablet ? 3 : 2,
878
- backgroundColor: "#e0f2fe",
879
- borderRadius: 12
880
- },
881
- eventTagText: {
882
- fontSize: isTablet ? 11 : 10,
883
- color: "#0369a1",
884
- fontWeight: "500"
885
- },
886
- noEventsMessage: {
887
- padding: containerPadding,
888
- paddingVertical: isTablet ? 30 : 20,
889
- alignItems: "center"
890
- },
891
- noEventsText: {
892
- fontSize: isTablet ? 14 : 13,
893
- color: "#6b7280",
894
- textAlign: "center"
895
- }
896
- });
897
- };
898
- var calendarStyles = getResponsiveStyles(375, 667);
899
-
900
- // src/react-native/components/DatePopup.tsx
901
- var import_jsx_runtime = require("react/jsx-runtime");
902
- var PriorityBadge = ({
903
- priority,
904
- styles
905
- }) => {
906
- if (!priority) return null;
907
- const priorityConfig = {
908
- high: { label: "HIGH", style: styles.priorityBadgeHigh },
909
- medium: { label: "MEDIUM", style: styles.priorityBadgeMedium },
910
- low: { label: "LOW", style: styles.priorityBadgeLow }
911
- };
912
- const config = priorityConfig[priority];
913
- if (!config) return null;
914
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.badge, config.style], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.badgeText, children: config.label }) });
915
- };
916
- var StatusBadge = ({
917
- status,
918
- styles
919
- }) => {
920
- if (!status || status === "scheduled") return null;
921
- const statusConfig = {
922
- completed: { label: "COMPLETED", style: styles.statusBadgeCompleted },
923
- cancelled: { label: "CANCELLED", style: styles.statusBadgeCancelled },
924
- tentative: { label: "TENTATIVE", style: styles.statusBadgeTentative }
925
- };
926
- const config = statusConfig[status];
927
- if (!config) return null;
928
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.badge, config.style], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.badgeText, children: config.label }) });
929
- };
930
- var CategoryBadge = ({
931
- category,
932
- styles
933
- }) => {
934
- if (!category) return null;
935
- const categoryConfig = {
936
- work: { label: "WORK", style: styles.categoryBadgeWork },
937
- personal: { label: "PERSONAL", style: styles.categoryBadgePersonal },
938
- meeting: { label: "MEETING", style: styles.categoryBadgeMeeting },
939
- deadline: { label: "DEADLINE", style: styles.categoryBadgeDeadline },
940
- appointment: {
941
- label: "APPOINTMENT",
942
- style: styles.categoryBadgeAppointment
943
- },
944
- other: { label: "OTHER", style: styles.categoryBadgeOther }
945
- };
946
- const config = categoryConfig[category];
947
- if (!config) return null;
948
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.badge, config.style], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.badgeText, children: config.label }) });
949
- };
950
- var DatePopup = ({
951
- visible,
952
- selectedDate,
953
- events,
954
- scheduleDay,
955
- onClose,
956
- onEventClick,
957
- renderEvent,
958
- renderNoEvents,
959
- showCloseButton = true
960
- }) => {
961
- const { width, height } = (0, import_react_native2.useWindowDimensions)();
962
- const calendarStyles2 = getResponsiveStyles(width, height);
963
- if (!selectedDate) return null;
964
- const showScrollHint = events.length > 3;
965
- const handleEventClick = (event) => {
966
- onEventClick?.(event);
967
- };
968
- const defaultRenderEvent = (event) => {
969
- const timeRange = formatTimeRange(event);
970
- const attendeesList = formatAttendees(event.attendees);
971
- const handleUrlPress = () => {
972
- if (event.url) {
973
- import_react_native2.Linking.openURL(event.url).catch(
974
- (err) => console.error("Failed to open URL:", err)
975
- );
976
- }
977
- };
978
- const eventContent = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
979
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.eventHeader, children: [
980
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTitle, children: event.name }),
981
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.eventBadges, children: [
982
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CategoryBadge, { category: event.category, styles: calendarStyles2 }),
983
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PriorityBadge, { priority: event.priority, styles: calendarStyles2 }),
984
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, { status: event.status, styles: calendarStyles2 })
985
- ] })
986
- ] }),
987
- timeRange && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.eventTime, children: [
988
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeLabel, children: "Time:" }),
989
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeValue, children: timeRange })
990
- ] }),
991
- event.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventDescription, children: event.description }),
992
- event.location && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.eventTime, children: [
993
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeLabel, children: "Location:" }),
994
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeValue, children: event.location })
995
- ] }),
996
- attendeesList && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.eventTime, children: [
997
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeLabel, children: "Attendees:" }),
998
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeValue, children: attendeesList })
999
- ] }),
1000
- event.organizer && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.eventTime, children: [
1001
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeLabel, children: "Organizer:" }),
1002
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeValue, children: event.organizer })
1003
- ] }),
1004
- event.notes && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.eventTime, children: [
1005
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeLabel, children: "Notes:" }),
1006
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTimeValue, children: event.notes })
1007
- ] }),
1008
- event.url && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1009
- import_react_native2.TouchableOpacity,
1010
- {
1011
- onPress: handleUrlPress,
1012
- style: calendarStyles2.eventUrlContainer,
1013
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventLink, children: "View Details \u2192" })
1014
- }
1015
- ),
1016
- event.tags && event.tags.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: calendarStyles2.eventTags, children: event.tags.map((tag, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: calendarStyles2.eventTag, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.eventTagText, children: tag }) }, idx)) })
1017
- ] });
1018
- if (onEventClick) {
1019
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1020
- import_react_native2.TouchableOpacity,
1021
- {
1022
- style: [
1023
- calendarStyles2.eventCard,
1024
- event.color && { borderLeftColor: event.color }
1025
- ],
1026
- onPress: () => handleEventClick(event),
1027
- activeOpacity: 0.7,
1028
- children: eventContent
1029
- },
1030
- event.id || event.name
1031
- );
1032
- }
1033
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1034
- import_react_native2.View,
1035
- {
1036
- style: [
1037
- calendarStyles2.eventCard,
1038
- event.color && { borderLeftColor: event.color }
1039
- ],
1040
- children: eventContent
1041
- },
1042
- event.id || event.name
1043
- );
1044
- };
1045
- const defaultRenderNoEvents = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: calendarStyles2.noEventsMessage, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.noEventsText, children: "No events scheduled for this day." }) });
1046
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1047
- import_react_native2.Modal,
1048
- {
1049
- visible,
1050
- transparent: true,
1051
- animationType: "fade",
1052
- onRequestClose: onClose,
1053
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1054
- import_react_native2.TouchableOpacity,
1055
- {
1056
- style: calendarStyles2.popupOverlay,
1057
- activeOpacity: 1,
1058
- onPress: onClose,
1059
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1060
- import_react_native2.TouchableOpacity,
1061
- {
1062
- style: calendarStyles2.popup,
1063
- activeOpacity: 1,
1064
- onPress: (e) => e.stopPropagation(),
1065
- children: [
1066
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: calendarStyles2.popupHeader, children: [
1067
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.popupHeaderText, children: scheduleDay }),
1068
- showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1069
- import_react_native2.TouchableOpacity,
1070
- {
1071
- style: calendarStyles2.popupCloseButton,
1072
- onPress: onClose,
1073
- accessibilityLabel: "Close",
1074
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.popupCloseText, children: "\u2715" })
1075
- }
1076
- )
1077
- ] }),
1078
- showScrollHint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: calendarStyles2.scrollHint, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: calendarStyles2.scrollHintText, children: "\u2193 Scroll to see more events \u2193" }) }),
1079
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1080
- import_react_native2.ScrollView,
1081
- {
1082
- style: calendarStyles2.eventsContainer,
1083
- showsVerticalScrollIndicator: true,
1084
- children: events.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: calendarStyles2.eventsList, children: events.map(
1085
- (event) => renderEvent ? renderEvent(event) : defaultRenderEvent(event)
1086
- ) }) : renderNoEvents ? renderNoEvents() : defaultRenderNoEvents()
1087
- }
1088
- )
1089
- ]
1090
- }
1091
- )
1092
- }
1093
- )
1094
- }
1095
- );
1096
- };
1097
-
1098
- // src/react-native/components/Calendar.tsx
1099
- var import_jsx_runtime2 = require("react/jsx-runtime");
1100
- var Calendar = ({
1101
- events,
1102
- initialDate,
1103
- minYear,
1104
- maxYear,
1105
- weekStartsOn = 0,
1106
- useShortMonthNames = false,
1107
- onDateSelect,
1108
- onEventClick,
1109
- onMonthChange,
1110
- style,
1111
- containerStyle,
1112
- headerStyle,
1113
- headerTextStyle,
1114
- cellStyle,
1115
- cellTextStyle,
1116
- renderEvent,
1117
- renderNoEvents,
1118
- title,
1119
- showCloseButton = true,
1120
- theme
1121
- }) => {
1122
- const engine = (0, import_react.useMemo)(
1123
- () => new CalendarEngine({
1124
- events,
1125
- initialDate,
1126
- minYear,
1127
- maxYear,
1128
- weekStartsOn
1129
- }),
1130
- [events, initialDate, minYear, maxYear, weekStartsOn]
1131
- );
1132
- const themeColors = (0, import_react.useMemo)(() => {
1133
- if (!theme) return void 0;
1134
- return {
1135
- primary: theme.primary,
1136
- secondary: theme.secondary,
1137
- tertiary: theme.tertiary,
1138
- text: theme.textColor,
1139
- border: theme.borderColor,
1140
- todayOutline: theme.todayOutline,
1141
- eventIndicator: theme.eventIndicator,
1142
- background: theme.background
1143
- };
1144
- }, [theme]);
1145
- const calendarStyles2 = (0, import_react.useMemo)(() => {
1146
- const { width, height } = import_react_native3.Dimensions.get("window");
1147
- return getResponsiveStyles(width, height, themeColors);
1148
- }, [themeColors]);
1149
- const [, forceUpdate] = (0, import_react.useState)({});
1150
- const rerender = (0, import_react.useCallback)(() => forceUpdate({}), []);
1151
- const [pickerOpen, setPickerOpen] = (0, import_react.useState)(false);
1152
- const [yearInput, setYearInput] = (0, import_react.useState)("");
1153
- const [yearInputValid, setYearInputValid] = (0, import_react.useState)(true);
1154
- const today = /* @__PURE__ */ new Date();
1155
- const todayMonth = today.getMonth();
1156
- const todayYear = today.getFullYear();
1157
- const computedMinYear = minYear ?? todayYear - 30;
1158
- const computedMaxYear = maxYear ?? todayYear + 10;
1159
- (0, import_react.useEffect)(() => {
1160
- const unsubscribe = engine.subscribe(rerender);
1161
- return unsubscribe;
1162
- }, [engine, rerender]);
1163
- (0, import_react.useEffect)(() => {
1164
- engine.updateEvents(events);
1165
- }, [engine, events]);
1166
- (0, import_react.useEffect)(() => {
1167
- return () => {
1168
- engine.destroy();
1169
- };
1170
- }, [engine]);
1171
- const viewModel = engine.getViewModel();
1172
- const actions = engine.getActions();
1173
- const { selectedDate, tasks } = viewModel;
1174
- const isCurrentMonth = viewModel.currentYear === todayYear && viewModel.currentMonth === todayMonth;
1175
- const handleDatePress = (date, dayIndex) => {
1176
- engine.handleDateClick(date, dayIndex);
1177
- onDateSelect?.(date);
1178
- };
1179
- const handleNext = () => {
1180
- actions.next();
1181
- onMonthChange?.(viewModel.currentYear, viewModel.currentMonth);
1182
- };
1183
- const handlePrevious = () => {
1184
- actions.previous();
1185
- onMonthChange?.(viewModel.currentYear, viewModel.currentMonth);
1186
- };
1187
- const handleGoToToday = () => {
1188
- actions.goToToday();
1189
- setPickerOpen(false);
1190
- onMonthChange?.(todayYear, todayMonth);
1191
- };
1192
- const togglePicker = () => {
1193
- const newOpen = !pickerOpen;
1194
- setPickerOpen(newOpen);
1195
- if (newOpen) {
1196
- setYearInput(String(viewModel.currentYear));
1197
- setYearInputValid(true);
1198
- }
1199
- };
1200
- const handleYearInputChange = (value) => {
1201
- if (value === "" || /^\d+$/.test(value)) {
1202
- setYearInput(value);
1203
- const year = parseInt(value, 10);
1204
- setYearInputValid(
1205
- value === "" || year >= computedMinYear && year <= computedMaxYear
1206
- );
1207
- }
1208
- };
1209
- const handleYearInputSubmit = () => {
1210
- const year = parseInt(yearInput, 10);
1211
- if (isNaN(year) || year < computedMinYear || year > computedMaxYear) {
1212
- setYearInput(String(viewModel.currentYear));
1213
- setYearInputValid(true);
1214
- } else {
1215
- actions.jump(year, viewModel.currentMonth);
1216
- onMonthChange?.(year, viewModel.currentMonth);
1217
- }
1218
- };
1219
- const handleYearPrev = () => {
1220
- const newYear = viewModel.currentYear - 1;
1221
- if (newYear >= computedMinYear) {
1222
- actions.jump(newYear, viewModel.currentMonth);
1223
- setYearInput(String(newYear));
1224
- onMonthChange?.(newYear, viewModel.currentMonth);
1225
- }
1226
- };
1227
- const handleYearNext = () => {
1228
- const newYear = viewModel.currentYear + 1;
1229
- if (newYear <= computedMaxYear) {
1230
- actions.jump(newYear, viewModel.currentMonth);
1231
- setYearInput(String(newYear));
1232
- onMonthChange?.(newYear, viewModel.currentMonth);
1233
- }
1234
- };
1235
- const handleMonthSelect = (month) => {
1236
- actions.jump(viewModel.currentYear, month);
1237
- setPickerOpen(false);
1238
- onMonthChange?.(viewModel.currentYear, month);
1239
- };
1240
- const closePopup = () => {
1241
- engine.clearSelection();
1242
- };
1243
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.ScrollView, { style: [calendarStyles2.container, containerStyle], children: [
1244
- title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: calendarStyles2.titleContainer, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: calendarStyles2.title, children: title }) }),
1245
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [calendarStyles2.contentContainer, style], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: calendarStyles2.card, children: [
1246
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: [pickerStyles.navHeader, headerStyle], children: [
1247
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1248
- import_react_native3.TouchableOpacity,
1249
- {
1250
- style: pickerStyles.navArrow,
1251
- onPress: handlePrevious,
1252
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: pickerStyles.navArrowText, children: "\u2039" })
1253
- }
1254
- ),
1255
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1256
- import_react_native3.TouchableOpacity,
1257
- {
1258
- style: pickerStyles.pickerBtn,
1259
- onPress: togglePicker,
1260
- children: [
1261
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [pickerStyles.pickerBtnText, headerTextStyle], children: useShortMonthNames ? `${MONTHS[viewModel.currentMonth]} ${viewModel.currentYear}` : viewModel.monthAndYearText }),
1262
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: pickerStyles.chevron, children: "\u25BC" })
1263
- ]
1264
- }
1265
- ),
1266
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1267
- import_react_native3.TouchableOpacity,
1268
- {
1269
- style: [
1270
- pickerStyles.todayBtn,
1271
- isCurrentMonth && pickerStyles.todayBtnDisabled
1272
- ],
1273
- onPress: handleGoToToday,
1274
- disabled: isCurrentMonth,
1275
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1276
- import_react_native3.Text,
1277
- {
1278
- style: [
1279
- pickerStyles.todayBtnText,
1280
- isCurrentMonth && pickerStyles.todayBtnTextDisabled
1281
- ],
1282
- children: "Today"
1283
- }
1284
- )
1285
- }
1286
- ),
1287
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1288
- import_react_native3.TouchableOpacity,
1289
- {
1290
- style: pickerStyles.navArrow,
1291
- onPress: handleNext,
1292
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: pickerStyles.navArrowText, children: "\u203A" })
1293
- }
1294
- )
1295
- ] }),
1296
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1297
- import_react_native3.Modal,
1298
- {
1299
- visible: pickerOpen,
1300
- transparent: true,
1301
- animationType: "fade",
1302
- onRequestClose: () => setPickerOpen(false),
1303
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1304
- import_react_native3.Pressable,
1305
- {
1306
- style: pickerStyles.modalOverlay,
1307
- onPress: () => setPickerOpen(false),
1308
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1309
- import_react_native3.Pressable,
1310
- {
1311
- style: pickerStyles.pickerDropdown,
1312
- onPress: (e) => e.stopPropagation(),
1313
- children: [
1314
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: pickerStyles.yearRow, children: [
1315
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1316
- import_react_native3.TouchableOpacity,
1317
- {
1318
- style: pickerStyles.yearArrow,
1319
- onPress: handleYearPrev,
1320
- disabled: viewModel.currentYear <= computedMinYear,
1321
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1322
- import_react_native3.Text,
1323
- {
1324
- style: [
1325
- pickerStyles.yearArrowText,
1326
- viewModel.currentYear <= computedMinYear && pickerStyles.yearArrowDisabled
1327
- ],
1328
- children: "\u2039"
1329
- }
1330
- )
1331
- }
1332
- ),
1333
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1334
- import_react_native3.TextInput,
1335
- {
1336
- style: [
1337
- pickerStyles.yearInput,
1338
- !yearInputValid && pickerStyles.yearInputInvalid
1339
- ],
1340
- value: yearInput,
1341
- onChangeText: handleYearInputChange,
1342
- onSubmitEditing: handleYearInputSubmit,
1343
- onBlur: handleYearInputSubmit,
1344
- keyboardType: "number-pad",
1345
- maxLength: 4
1346
- }
1347
- ),
1348
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1349
- import_react_native3.TouchableOpacity,
1350
- {
1351
- style: pickerStyles.yearArrow,
1352
- onPress: handleYearNext,
1353
- disabled: viewModel.currentYear >= computedMaxYear,
1354
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1355
- import_react_native3.Text,
1356
- {
1357
- style: [
1358
- pickerStyles.yearArrowText,
1359
- viewModel.currentYear >= computedMaxYear && pickerStyles.yearArrowDisabled
1360
- ],
1361
- children: "\u203A"
1362
- }
1363
- )
1364
- }
1365
- )
1366
- ] }),
1367
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: pickerStyles.monthGrid, children: (useShortMonthNames ? MONTHS : MONTHS_FULL).map(
1368
- (month, index) => {
1369
- const isSelected = index === viewModel.currentMonth;
1370
- const isCurrent = index === todayMonth && viewModel.currentYear === todayYear;
1371
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1372
- import_react_native3.TouchableOpacity,
1373
- {
1374
- style: [
1375
- pickerStyles.monthBtn,
1376
- isSelected && pickerStyles.monthBtnSelected,
1377
- isCurrent && pickerStyles.monthBtnCurrent
1378
- ],
1379
- onPress: () => handleMonthSelect(index),
1380
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1381
- import_react_native3.Text,
1382
- {
1383
- style: [
1384
- pickerStyles.monthBtnText,
1385
- isSelected && pickerStyles.monthBtnTextSelected
1386
- ],
1387
- children: month
1388
- }
1389
- )
1390
- },
1391
- month
1392
- );
1393
- }
1394
- ) })
1395
- ]
1396
- }
1397
- )
1398
- }
1399
- )
1400
- }
1401
- ),
1402
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: calendarStyles2.table, children: [
1403
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: calendarStyles2.tableHeader, children: viewModel.days.map((day) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: calendarStyles2.tableHeaderCell, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: calendarStyles2.tableHeaderText, children: day.slice(0, 3) }) }, day)) }),
1404
- viewModel.calendarDates.map((week, weekIndex) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: calendarStyles2.tableRow, children: week.map((calendarDate, dayIndex) => {
1405
- const cellClasses = getCellClasses(calendarDate);
1406
- const isToday2 = cellClasses.includes(
1407
- "schedule--current--exam"
1408
- );
1409
- const hasEvents2 = cellClasses.includes("has--event");
1410
- const isOtherMonth = cellClasses.includes("other-month");
1411
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1412
- import_react_native3.TouchableOpacity,
1413
- {
1414
- style: [
1415
- calendarStyles2.tableCell,
1416
- cellStyle,
1417
- isToday2 && calendarStyles2.cellToday,
1418
- hasEvents2 && calendarStyles2.cellWithEvents,
1419
- isOtherMonth && pickerStyles.cellOtherMonth
1420
- ],
1421
- onPress: () => {
1422
- handleDatePress(calendarDate.date, dayIndex);
1423
- },
1424
- children: [
1425
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1426
- import_react_native3.Text,
1427
- {
1428
- style: [
1429
- calendarStyles2.tableCellText,
1430
- cellTextStyle,
1431
- isToday2 && calendarStyles2.cellTodayText,
1432
- isOtherMonth && pickerStyles.cellOtherMonthText
1433
- ],
1434
- children: calendarDate.date.getDate()
1435
- }
1436
- ),
1437
- hasEvents2 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: calendarStyles2.eventIndicator })
1438
- ]
1439
- },
1440
- `${weekIndex}-${dayIndex}`
1441
- );
1442
- }) }, weekIndex))
1443
- ] })
1444
- ] }) }),
1445
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1446
- DatePopup,
1447
- {
1448
- visible: !!selectedDate,
1449
- selectedDate,
1450
- events: tasks,
1451
- scheduleDay: viewModel.scheduleDay,
1452
- onClose: closePopup,
1453
- onEventClick,
1454
- renderEvent,
1455
- renderNoEvents,
1456
- showCloseButton
1457
- }
1458
- )
1459
- ] });
1460
- };
1461
- var pickerStyles = import_react_native3.StyleSheet.create({
1462
- navHeader: {
1463
- flexDirection: "row",
1464
- alignItems: "center",
1465
- justifyContent: "center",
1466
- paddingVertical: 12,
1467
- paddingHorizontal: 8,
1468
- backgroundColor: "#f8f9fa",
1469
- borderBottomWidth: 2,
1470
- borderBottomColor: "#dee2e6",
1471
- gap: 8
1472
- },
1473
- navArrow: {
1474
- width: 36,
1475
- height: 36,
1476
- borderRadius: 6,
1477
- borderWidth: 1,
1478
- borderColor: "#dee2e6",
1479
- backgroundColor: "#fff",
1480
- alignItems: "center",
1481
- justifyContent: "center"
1482
- },
1483
- navArrowText: {
1484
- fontSize: 20,
1485
- color: "#2c3e50"
1486
- },
1487
- pickerBtn: {
1488
- flexDirection: "row",
1489
- alignItems: "center",
1490
- paddingHorizontal: 16,
1491
- paddingVertical: 8,
1492
- borderRadius: 6,
1493
- borderWidth: 1,
1494
- borderColor: "#dee2e6",
1495
- backgroundColor: "#fff",
1496
- gap: 8
1497
- },
1498
- pickerBtnText: {
1499
- fontSize: 16,
1500
- fontWeight: "600",
1501
- color: "#2c3e50"
1502
- },
1503
- chevron: {
1504
- fontSize: 10,
1505
- color: "#2c3e50"
1506
- },
1507
- todayBtn: {
1508
- paddingHorizontal: 16,
1509
- paddingVertical: 8,
1510
- borderRadius: 6,
1511
- borderWidth: 1,
1512
- borderColor: "#dee2e6",
1513
- backgroundColor: "#fff"
1514
- },
1515
- todayBtnDisabled: {
1516
- opacity: 0.5
1517
- },
1518
- todayBtnText: {
1519
- fontSize: 14,
1520
- fontWeight: "500",
1521
- color: "#2c3e50"
1522
- },
1523
- todayBtnTextDisabled: {
1524
- color: "#9ca3af"
1525
- },
1526
- modalOverlay: {
1527
- flex: 1,
1528
- backgroundColor: "rgba(0, 0, 0, 0.3)",
1529
- justifyContent: "center",
1530
- alignItems: "center"
1531
- },
1532
- pickerDropdown: {
1533
- backgroundColor: "#fff",
1534
- borderRadius: 12,
1535
- padding: 16,
1536
- minWidth: 280,
1537
- shadowColor: "#000",
1538
- shadowOffset: { width: 0, height: 4 },
1539
- shadowOpacity: 0.15,
1540
- shadowRadius: 20,
1541
- elevation: 10
1542
- },
1543
- yearRow: {
1544
- flexDirection: "row",
1545
- alignItems: "center",
1546
- justifyContent: "center",
1547
- gap: 12,
1548
- marginBottom: 16,
1549
- paddingBottom: 12,
1550
- borderBottomWidth: 1,
1551
- borderBottomColor: "#dee2e6"
1552
- },
1553
- yearArrow: {
1554
- width: 32,
1555
- height: 32,
1556
- borderRadius: 6,
1557
- backgroundColor: "#f3f4f6",
1558
- alignItems: "center",
1559
- justifyContent: "center"
1560
- },
1561
- yearArrowText: {
1562
- fontSize: 18,
1563
- fontWeight: "600",
1564
- color: "#2c3e50"
1565
- },
1566
- yearArrowDisabled: {
1567
- opacity: 0.3
1568
- },
1569
- yearInput: {
1570
- width: 80,
1571
- paddingVertical: 6,
1572
- paddingHorizontal: 8,
1573
- borderRadius: 6,
1574
- borderWidth: 1,
1575
- borderColor: "#dee2e6",
1576
- textAlign: "center",
1577
- fontSize: 18,
1578
- fontWeight: "600",
1579
- color: "#2c3e50"
1580
- },
1581
- yearInputInvalid: {
1582
- borderColor: "#ef4444",
1583
- backgroundColor: "#fef2f2"
1584
- },
1585
- monthGrid: {
1586
- flexDirection: "row",
1587
- flexWrap: "wrap",
1588
- gap: 8
1589
- },
1590
- monthBtn: {
1591
- width: "30%",
1592
- paddingVertical: 10,
1593
- borderRadius: 6,
1594
- backgroundColor: "#f9fafb",
1595
- alignItems: "center"
1596
- },
1597
- monthBtnSelected: {
1598
- backgroundColor: "#fc8917"
1599
- },
1600
- monthBtnCurrent: {
1601
- borderWidth: 1,
1602
- borderColor: "#fc8917"
1603
- },
1604
- monthBtnText: {
1605
- fontSize: 14,
1606
- fontWeight: "500",
1607
- color: "#2c3e50"
1608
- },
1609
- monthBtnTextSelected: {
1610
- color: "#fff",
1611
- fontWeight: "600"
1612
- },
1613
- cellOtherMonth: {
1614
- backgroundColor: "#f9fafb"
1615
- },
1616
- cellOtherMonthText: {
1617
- color: "#9ca3af"
1618
- }
1619
- });
1620
- // Annotate the CommonJS export names for ESM import in node:
1621
- 0 && (module.exports = {
1622
- Calendar,
1623
- CalendarEngine,
1624
- DAYS,
1625
- DEFAULT_CATEGORY_COLORS,
1626
- DatePopup,
1627
- MONTHS,
1628
- MONTHS_FULL,
1629
- calendarStyles,
1630
- formatAttendees,
1631
- formatDateForDisplay,
1632
- formatTimeRange,
1633
- generateCalendarDates,
1634
- generateYears,
1635
- getCategoryColor,
1636
- getCellClasses,
1637
- getDefaultEventColor,
1638
- getEventsForDate,
1639
- getMonthYearText,
1640
- getPopupPositionClass,
1641
- hasEvents,
1642
- isSameDay,
1643
- isToday,
1644
- isValidHexColor,
1645
- mergeCategoryColors,
1646
- normalizeDate,
1647
- sortEventsByTime
1648
- });
1649
- //# sourceMappingURL=index.js.map