kalendly 0.1.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.
@@ -0,0 +1,851 @@
1
+ // src/react-native/components/Calendar.tsx
2
+ import { useEffect, useState, useCallback, useMemo } from "react";
3
+ import { View as View2, Text as Text2, TouchableOpacity as TouchableOpacity2, ScrollView as ScrollView2, Alert } from "react-native";
4
+
5
+ // src/core/utils.ts
6
+ var MONTHS = [
7
+ "Jan",
8
+ "Feb",
9
+ "Mar",
10
+ "Apr",
11
+ "May",
12
+ "Jun",
13
+ "Jul",
14
+ "Aug",
15
+ "Sep",
16
+ "Oct",
17
+ "Nov",
18
+ "Dec"
19
+ ];
20
+ var DAYS = [
21
+ "Sunday",
22
+ "Monday",
23
+ "Tuesday",
24
+ "Wednesday",
25
+ "Thursday",
26
+ "Friday",
27
+ "Saturday"
28
+ ];
29
+ function normalizeDate(date) {
30
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
31
+ }
32
+ function isSameDay(date1, date2) {
33
+ return normalizeDate(date1).getTime() === normalizeDate(date2).getTime();
34
+ }
35
+ function isToday(date) {
36
+ return isSameDay(date, /* @__PURE__ */ new Date());
37
+ }
38
+ function generateYears(minYear, maxYear) {
39
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
40
+ const min = minYear ?? currentYear - 30;
41
+ const max = maxYear ?? currentYear + 10;
42
+ return Array.from({ length: max - min + 1 }, (_, i) => min + i);
43
+ }
44
+ function getEventsForDate(events, date) {
45
+ const normalizedTargetDate = normalizeDate(date);
46
+ return events.filter((event) => {
47
+ const eventDate = normalizeDate(new Date(event.date));
48
+ return eventDate.getTime() === normalizedTargetDate.getTime();
49
+ });
50
+ }
51
+ function hasEvents(events, date) {
52
+ return getEventsForDate(events, date).length > 0;
53
+ }
54
+ function generateCalendarDates(year, month, events = [], weekStartsOn = 0) {
55
+ const firstDay = new Date(year, month, 1);
56
+ const lastDay = new Date(year, month + 1, 0);
57
+ const daysInMonth = lastDay.getDate();
58
+ let firstDayOfWeek = firstDay.getDay();
59
+ if (weekStartsOn === 1) {
60
+ firstDayOfWeek = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;
61
+ }
62
+ const dates = [];
63
+ let day = 1;
64
+ for (let week = 0; week < 6; week++) {
65
+ const weekDates = [];
66
+ for (let dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
67
+ if (week === 0 && dayOfWeek < firstDayOfWeek) {
68
+ weekDates.push(null);
69
+ } else if (day > daysInMonth) {
70
+ weekDates.push(null);
71
+ } else {
72
+ const currentDate = new Date(year, month, day);
73
+ const dateEvents = getEventsForDate(events, currentDate);
74
+ weekDates.push({
75
+ date: currentDate,
76
+ isCurrentMonth: true,
77
+ isToday: isToday(currentDate),
78
+ hasEvents: dateEvents.length > 0,
79
+ events: dateEvents
80
+ });
81
+ day++;
82
+ }
83
+ }
84
+ dates.push(weekDates);
85
+ if (day > daysInMonth && weekDates.every((date) => date === null)) {
86
+ break;
87
+ }
88
+ }
89
+ return dates;
90
+ }
91
+ function getPopupPositionClass(selectedDayIndex) {
92
+ if (selectedDayIndex === null) return "popup-center-bottom";
93
+ if (selectedDayIndex < 3) {
94
+ return "popup-right";
95
+ } else if (selectedDayIndex > 4) {
96
+ return "popup-left";
97
+ } else {
98
+ return "popup-center-bottom";
99
+ }
100
+ }
101
+ function getCellClasses(calendarDate) {
102
+ if (!calendarDate) return [];
103
+ const classes = [];
104
+ if (calendarDate.isToday) {
105
+ classes.push("schedule--current--exam");
106
+ }
107
+ if (calendarDate.hasEvents) {
108
+ classes.push("has--event");
109
+ }
110
+ return classes;
111
+ }
112
+ function formatDateForDisplay(date) {
113
+ return `${DAYS[date.getDay()]} ${date.getDate()}`;
114
+ }
115
+ function getMonthYearText(year, month) {
116
+ return `${MONTHS[month]} ${year}`;
117
+ }
118
+
119
+ // src/core/calendar-engine.ts
120
+ var CalendarEngine = class {
121
+ constructor(config) {
122
+ this.listeners = /* @__PURE__ */ new Set();
123
+ this.config = config;
124
+ const initialDate = config.initialDate || /* @__PURE__ */ new Date();
125
+ this.state = {
126
+ currentYear: initialDate.getFullYear(),
127
+ currentMonth: initialDate.getMonth(),
128
+ currentDate: initialDate.getDate(),
129
+ selectedDate: null,
130
+ selectedDayIndex: null,
131
+ tasks: []
132
+ };
133
+ }
134
+ /**
135
+ * Subscribe to state changes
136
+ */
137
+ subscribe(listener) {
138
+ this.listeners.add(listener);
139
+ return () => this.listeners.delete(listener);
140
+ }
141
+ /**
142
+ * Notify all listeners of state changes
143
+ */
144
+ notify() {
145
+ this.listeners.forEach((listener) => listener());
146
+ }
147
+ /**
148
+ * Get current state
149
+ */
150
+ getState() {
151
+ return { ...this.state };
152
+ }
153
+ /**
154
+ * Get view model with computed properties
155
+ */
156
+ getViewModel() {
157
+ const calendarDates = generateCalendarDates(
158
+ this.state.currentYear,
159
+ this.state.currentMonth,
160
+ this.config.events,
161
+ this.config.weekStartsOn
162
+ );
163
+ return {
164
+ ...this.state,
165
+ months: MONTHS,
166
+ days: DAYS,
167
+ years: generateYears(this.config.minYear, this.config.maxYear),
168
+ monthAndYearText: getMonthYearText(
169
+ this.state.currentYear,
170
+ this.state.currentMonth
171
+ ),
172
+ scheduleDay: this.state.selectedDate ? formatDateForDisplay(this.state.selectedDate) : "",
173
+ calendarDates,
174
+ popupPositionClass: getPopupPositionClass(this.state.selectedDayIndex)
175
+ };
176
+ }
177
+ /**
178
+ * Get actions object
179
+ */
180
+ getActions() {
181
+ return {
182
+ next: this.next.bind(this),
183
+ previous: this.previous.bind(this),
184
+ jump: this.jump.bind(this),
185
+ selectDate: this.selectDate.bind(this),
186
+ updateTasks: this.updateTasks.bind(this)
187
+ };
188
+ }
189
+ /**
190
+ * Navigate to next month
191
+ */
192
+ next() {
193
+ if (this.state.currentMonth === 11) {
194
+ this.state.currentMonth = 0;
195
+ this.state.currentYear++;
196
+ } else {
197
+ this.state.currentMonth++;
198
+ }
199
+ this.state.selectedDate = null;
200
+ this.state.selectedDayIndex = null;
201
+ this.updateTasks();
202
+ this.notify();
203
+ }
204
+ /**
205
+ * Navigate to previous month
206
+ */
207
+ previous() {
208
+ if (this.state.currentMonth === 0) {
209
+ this.state.currentMonth = 11;
210
+ this.state.currentYear--;
211
+ } else {
212
+ this.state.currentMonth--;
213
+ }
214
+ this.state.selectedDate = null;
215
+ this.state.selectedDayIndex = null;
216
+ this.updateTasks();
217
+ this.notify();
218
+ }
219
+ /**
220
+ * Jump to specific month and year
221
+ */
222
+ jump(year, month) {
223
+ this.state.currentYear = year;
224
+ this.state.currentMonth = month;
225
+ this.state.selectedDate = null;
226
+ this.state.selectedDayIndex = null;
227
+ this.updateTasks();
228
+ this.notify();
229
+ }
230
+ /**
231
+ * Select a specific date
232
+ */
233
+ selectDate(date, dayIndex) {
234
+ this.state.selectedDate = date;
235
+ this.state.selectedDayIndex = dayIndex ?? null;
236
+ this.state.currentDate = date.getDate();
237
+ this.state.currentMonth = date.getMonth();
238
+ this.state.currentYear = date.getFullYear();
239
+ this.updateTasks();
240
+ this.notify();
241
+ }
242
+ /**
243
+ * Update tasks for the currently selected date
244
+ */
245
+ updateTasks() {
246
+ if (!this.state.selectedDate) {
247
+ this.state.tasks = [];
248
+ return;
249
+ }
250
+ this.state.tasks = getEventsForDate(
251
+ this.config.events,
252
+ this.state.selectedDate
253
+ );
254
+ }
255
+ /**
256
+ * Update events configuration
257
+ */
258
+ updateEvents(events) {
259
+ this.config.events = events;
260
+ this.updateTasks();
261
+ this.notify();
262
+ }
263
+ /**
264
+ * Handle date cell click
265
+ */
266
+ handleDateClick(date, dayIndex) {
267
+ this.selectDate(date, dayIndex);
268
+ }
269
+ /**
270
+ * Check if date has events
271
+ */
272
+ hasEventsForDate(date) {
273
+ return getEventsForDate(this.config.events, date).length > 0;
274
+ }
275
+ /**
276
+ * Get events for a specific date
277
+ */
278
+ getEventsForDate(date) {
279
+ return getEventsForDate(this.config.events, date);
280
+ }
281
+ /**
282
+ * Clear selected date
283
+ */
284
+ clearSelection() {
285
+ this.state.selectedDate = null;
286
+ this.state.selectedDayIndex = null;
287
+ this.state.tasks = [];
288
+ this.notify();
289
+ }
290
+ /**
291
+ * Destroy the engine and cleanup listeners
292
+ */
293
+ destroy() {
294
+ this.listeners.clear();
295
+ }
296
+ };
297
+
298
+ // src/react-native/components/DatePopup.tsx
299
+ import { Modal, View, Text, TouchableOpacity, ScrollView } from "react-native";
300
+
301
+ // src/styles/react-native-styles.ts
302
+ import { StyleSheet, Dimensions } from "react-native";
303
+ var { width } = Dimensions.get("window");
304
+ var cellSize = (width - 60) / 7;
305
+ var colors = {
306
+ primary: "#fc8917",
307
+ secondary: "#fca045",
308
+ tertiary: "#fdb873",
309
+ text: "#2c3e50",
310
+ border: "#dee2e6",
311
+ todayOutline: "#f7db04",
312
+ eventIndicator: "#1890ff",
313
+ background: "#fff",
314
+ white: "#ffffff"
315
+ };
316
+ var calendarStyles = StyleSheet.create({
317
+ container: {
318
+ flex: 1,
319
+ backgroundColor: colors.background
320
+ },
321
+ titleContainer: {
322
+ paddingVertical: 20,
323
+ alignItems: "center"
324
+ },
325
+ title: {
326
+ fontSize: 24,
327
+ fontWeight: "600",
328
+ color: colors.text
329
+ },
330
+ contentContainer: {
331
+ marginHorizontal: 20,
332
+ marginTop: 20
333
+ },
334
+ card: {
335
+ backgroundColor: colors.background,
336
+ borderRadius: 8,
337
+ shadowColor: "#000",
338
+ shadowOffset: {
339
+ width: 0,
340
+ height: 2
341
+ },
342
+ shadowOpacity: 0.1,
343
+ shadowRadius: 3.84,
344
+ elevation: 5,
345
+ overflow: "hidden"
346
+ },
347
+ cardHeader: {
348
+ backgroundColor: colors.tertiary,
349
+ paddingVertical: 15,
350
+ paddingHorizontal: 20,
351
+ borderBottomWidth: 1,
352
+ borderBottomColor: colors.border
353
+ },
354
+ cardHeaderText: {
355
+ fontSize: 18,
356
+ fontWeight: "500",
357
+ color: colors.text,
358
+ textAlign: "center"
359
+ },
360
+ // Calendar Table Styles
361
+ table: {
362
+ backgroundColor: colors.background
363
+ },
364
+ tableHeader: {
365
+ flexDirection: "row",
366
+ backgroundColor: "rgba(252, 137, 23, 0.1)",
367
+ borderBottomWidth: 2,
368
+ borderBottomColor: colors.border
369
+ },
370
+ tableHeaderCell: {
371
+ flex: 1,
372
+ paddingVertical: 12,
373
+ borderRightWidth: 1,
374
+ borderRightColor: colors.border,
375
+ alignItems: "center",
376
+ justifyContent: "center"
377
+ },
378
+ tableHeaderText: {
379
+ fontSize: 14,
380
+ fontWeight: "600",
381
+ color: colors.text
382
+ },
383
+ tableRow: {
384
+ flexDirection: "row",
385
+ borderBottomWidth: 1,
386
+ borderBottomColor: colors.border
387
+ },
388
+ tableCell: {
389
+ flex: 1,
390
+ height: cellSize,
391
+ borderRightWidth: 1,
392
+ borderRightColor: colors.border,
393
+ alignItems: "center",
394
+ justifyContent: "center",
395
+ position: "relative"
396
+ },
397
+ tableCellText: {
398
+ fontSize: 16,
399
+ color: colors.text
400
+ },
401
+ // Calendar Cell States
402
+ cellToday: {
403
+ borderWidth: 2,
404
+ borderColor: colors.todayOutline
405
+ },
406
+ cellTodayText: {
407
+ fontWeight: "bold"
408
+ },
409
+ cellWithEvents: {
410
+ backgroundColor: "rgba(252, 160, 69, 0.3)"
411
+ },
412
+ eventIndicator: {
413
+ position: "absolute",
414
+ bottom: 2,
415
+ width: 4,
416
+ height: 4,
417
+ backgroundColor: colors.eventIndicator,
418
+ borderRadius: 2
419
+ },
420
+ // Navigation Buttons
421
+ navigationContainer: {
422
+ flexDirection: "row",
423
+ justifyContent: "space-between",
424
+ paddingHorizontal: 20,
425
+ paddingVertical: 20,
426
+ gap: 15
427
+ },
428
+ navigationButton: {
429
+ flex: 1,
430
+ backgroundColor: "transparent",
431
+ borderWidth: 1,
432
+ borderColor: colors.primary,
433
+ borderRadius: 6,
434
+ paddingVertical: 12,
435
+ paddingHorizontal: 16,
436
+ alignItems: "center",
437
+ justifyContent: "center"
438
+ },
439
+ navigationButtonText: {
440
+ color: colors.primary,
441
+ fontSize: 16,
442
+ fontWeight: "500"
443
+ },
444
+ navigationButtonPressed: {
445
+ backgroundColor: colors.primary
446
+ },
447
+ navigationButtonTextPressed: {
448
+ color: colors.white
449
+ },
450
+ // Jump Form
451
+ jumpForm: {
452
+ flexDirection: "row",
453
+ alignItems: "center",
454
+ justifyContent: "center",
455
+ paddingHorizontal: 20,
456
+ paddingBottom: 20,
457
+ gap: 10
458
+ },
459
+ jumpLabel: {
460
+ fontSize: 18,
461
+ fontWeight: "300",
462
+ color: colors.text
463
+ },
464
+ jumpSelect: {
465
+ borderWidth: 1,
466
+ borderColor: colors.border,
467
+ borderRadius: 6,
468
+ paddingHorizontal: 12,
469
+ paddingVertical: 8,
470
+ backgroundColor: colors.background,
471
+ minWidth: 80
472
+ },
473
+ jumpSelectText: {
474
+ fontSize: 16,
475
+ color: colors.text,
476
+ textAlign: "center"
477
+ },
478
+ // Popup Styles
479
+ popupOverlay: {
480
+ position: "absolute",
481
+ top: 0,
482
+ left: 0,
483
+ right: 0,
484
+ bottom: 0,
485
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
486
+ justifyContent: "center",
487
+ alignItems: "center",
488
+ zIndex: 1e3
489
+ },
490
+ popup: {
491
+ backgroundColor: colors.background,
492
+ borderRadius: 12,
493
+ padding: 0,
494
+ width: width * 0.8,
495
+ maxWidth: 300,
496
+ shadowColor: "#000",
497
+ shadowOffset: {
498
+ width: 0,
499
+ height: 4
500
+ },
501
+ shadowOpacity: 0.3,
502
+ shadowRadius: 6,
503
+ elevation: 8
504
+ },
505
+ popupWrapper: {
506
+ backgroundColor: colors.secondary,
507
+ borderRadius: 12,
508
+ padding: 12
509
+ },
510
+ popupBlock: {
511
+ backgroundColor: colors.primary,
512
+ borderRadius: 8,
513
+ paddingVertical: 8,
514
+ paddingHorizontal: 12,
515
+ marginBottom: 10
516
+ },
517
+ popupDay: {
518
+ fontSize: 16,
519
+ fontWeight: "600",
520
+ color: colors.white,
521
+ textAlign: "center"
522
+ },
523
+ eventsList: {
524
+ gap: 6
525
+ },
526
+ eventItem: {
527
+ backgroundColor: colors.tertiary,
528
+ borderRadius: 6,
529
+ padding: 12
530
+ },
531
+ eventItemText: {
532
+ fontSize: 14,
533
+ color: colors.text
534
+ },
535
+ noEventsMessage: {
536
+ backgroundColor: colors.tertiary,
537
+ borderRadius: 6,
538
+ padding: 12,
539
+ alignItems: "center"
540
+ },
541
+ noEventsText: {
542
+ fontSize: 14,
543
+ color: colors.text,
544
+ textAlign: "center"
545
+ },
546
+ popupCloseButton: {
547
+ position: "absolute",
548
+ top: -10,
549
+ right: -10,
550
+ backgroundColor: colors.primary,
551
+ borderRadius: 15,
552
+ width: 30,
553
+ height: 30,
554
+ alignItems: "center",
555
+ justifyContent: "center"
556
+ },
557
+ popupCloseText: {
558
+ color: colors.white,
559
+ fontSize: 16,
560
+ fontWeight: "bold"
561
+ }
562
+ });
563
+
564
+ // src/react-native/components/DatePopup.tsx
565
+ import { jsx, jsxs } from "react/jsx-runtime";
566
+ var DatePopup = ({
567
+ visible,
568
+ selectedDate,
569
+ events,
570
+ scheduleDay,
571
+ onClose,
572
+ renderEvent,
573
+ renderNoEvents,
574
+ showCloseButton = true
575
+ }) => {
576
+ if (!selectedDate) return null;
577
+ const defaultRenderEvent = (event) => /* @__PURE__ */ jsx(View, { style: calendarStyles.eventItem, children: /* @__PURE__ */ jsx(Text, { style: calendarStyles.eventItemText, children: event.name }) }, event.id || event.name);
578
+ const defaultRenderNoEvents = () => /* @__PURE__ */ jsx(View, { style: calendarStyles.noEventsMessage, children: /* @__PURE__ */ jsx(Text, { style: calendarStyles.noEventsText, children: "No events scheduled for this day." }) });
579
+ return /* @__PURE__ */ jsx(
580
+ Modal,
581
+ {
582
+ visible,
583
+ transparent: true,
584
+ animationType: "fade",
585
+ onRequestClose: onClose,
586
+ children: /* @__PURE__ */ jsx(
587
+ TouchableOpacity,
588
+ {
589
+ style: calendarStyles.popupOverlay,
590
+ activeOpacity: 1,
591
+ onPress: onClose,
592
+ children: /* @__PURE__ */ jsxs(
593
+ TouchableOpacity,
594
+ {
595
+ style: calendarStyles.popup,
596
+ activeOpacity: 1,
597
+ onPress: (e) => e.stopPropagation(),
598
+ children: [
599
+ /* @__PURE__ */ jsxs(View, { style: calendarStyles.popupWrapper, children: [
600
+ showCloseButton && /* @__PURE__ */ jsx(
601
+ TouchableOpacity,
602
+ {
603
+ style: calendarStyles.popupCloseButton,
604
+ onPress: onClose,
605
+ accessibilityLabel: "Close",
606
+ children: /* @__PURE__ */ jsx(Text, { style: calendarStyles.popupCloseText, children: "\u2715" })
607
+ }
608
+ ),
609
+ /* @__PURE__ */ jsx(View, { style: calendarStyles.popupBlock, children: /* @__PURE__ */ jsx(Text, { style: calendarStyles.popupDay, children: scheduleDay }) }),
610
+ /* @__PURE__ */ jsx(ScrollView, { showsVerticalScrollIndicator: false, children: events.length > 0 ? /* @__PURE__ */ jsx(View, { style: calendarStyles.eventsList, children: events.map(
611
+ (event) => renderEvent ? renderEvent(event) : defaultRenderEvent(event)
612
+ ) }) : renderNoEvents ? renderNoEvents() : defaultRenderNoEvents() })
613
+ ] }),
614
+ showCloseButton && /* @__PURE__ */ jsx(
615
+ TouchableOpacity,
616
+ {
617
+ style: calendarStyles.popupCloseButton,
618
+ onPress: onClose,
619
+ children: /* @__PURE__ */ jsx(Text, { style: calendarStyles.popupCloseText, children: "\xD7" })
620
+ }
621
+ )
622
+ ]
623
+ }
624
+ )
625
+ }
626
+ )
627
+ }
628
+ );
629
+ };
630
+
631
+ // src/react-native/components/Calendar.tsx
632
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
633
+ var Select = ({
634
+ options,
635
+ selectedValue,
636
+ onValueChange,
637
+ style,
638
+ textStyle
639
+ }) => {
640
+ const selectedOption = options.find((opt) => opt.value === selectedValue);
641
+ const showPicker = () => {
642
+ Alert.alert(
643
+ "Select Option",
644
+ "",
645
+ options.map((option) => ({
646
+ text: option.label,
647
+ onPress: () => onValueChange(option.value)
648
+ }))
649
+ );
650
+ };
651
+ return /* @__PURE__ */ jsx2(
652
+ TouchableOpacity2,
653
+ {
654
+ style: [calendarStyles.jumpSelect, style],
655
+ onPress: showPicker,
656
+ children: /* @__PURE__ */ jsx2(Text2, { style: [calendarStyles.jumpSelectText, textStyle], children: selectedOption?.label })
657
+ }
658
+ );
659
+ };
660
+ var Calendar = ({
661
+ events,
662
+ initialDate,
663
+ minYear,
664
+ maxYear,
665
+ weekStartsOn = 0,
666
+ onDateSelect,
667
+ onEventClick,
668
+ onMonthChange,
669
+ style,
670
+ containerStyle,
671
+ headerStyle,
672
+ headerTextStyle,
673
+ cellStyle,
674
+ cellTextStyle,
675
+ renderEvent,
676
+ renderNoEvents,
677
+ title = "Event Schedule",
678
+ showCloseButton = true
679
+ }) => {
680
+ const engine = useMemo(
681
+ () => new CalendarEngine({
682
+ events,
683
+ initialDate,
684
+ minYear,
685
+ maxYear,
686
+ weekStartsOn
687
+ }),
688
+ []
689
+ );
690
+ const [, forceUpdate] = useState({});
691
+ const rerender = useCallback(() => forceUpdate({}), []);
692
+ useEffect(() => {
693
+ const unsubscribe = engine.subscribe(rerender);
694
+ return unsubscribe;
695
+ }, [engine, rerender]);
696
+ useEffect(() => {
697
+ engine.updateEvents(events);
698
+ }, [engine, events]);
699
+ const viewModel = engine.getViewModel();
700
+ const actions = engine.getActions();
701
+ const { selectedDate, tasks } = viewModel;
702
+ const handleDatePress = (date, dayIndex) => {
703
+ engine.handleDateClick(date, dayIndex);
704
+ onDateSelect?.(date);
705
+ };
706
+ const handleNext = () => {
707
+ actions.next();
708
+ onMonthChange?.(viewModel.currentYear, viewModel.currentMonth);
709
+ };
710
+ const handlePrevious = () => {
711
+ actions.previous();
712
+ onMonthChange?.(viewModel.currentYear, viewModel.currentMonth);
713
+ };
714
+ const handleMonthChange = (month) => {
715
+ actions.jump(viewModel.currentYear, month);
716
+ onMonthChange?.(viewModel.currentYear, month);
717
+ };
718
+ const handleYearChange = (year) => {
719
+ actions.jump(year, viewModel.currentMonth);
720
+ onMonthChange?.(year, viewModel.currentMonth);
721
+ };
722
+ const closePopup = () => {
723
+ engine.clearSelection();
724
+ };
725
+ const monthOptions = viewModel.months.map((month, index) => ({
726
+ label: month,
727
+ value: index
728
+ }));
729
+ const yearOptions = viewModel.years.map((year) => ({
730
+ label: year.toString(),
731
+ value: year
732
+ }));
733
+ return /* @__PURE__ */ jsxs2(ScrollView2, { style: [calendarStyles.container, containerStyle], children: [
734
+ title && /* @__PURE__ */ jsx2(View2, { style: calendarStyles.titleContainer, children: /* @__PURE__ */ jsx2(Text2, { style: calendarStyles.title, children: title }) }),
735
+ /* @__PURE__ */ jsx2(View2, { style: [calendarStyles.contentContainer, style], children: /* @__PURE__ */ jsxs2(View2, { style: calendarStyles.card, children: [
736
+ /* @__PURE__ */ jsx2(View2, { style: [calendarStyles.cardHeader, headerStyle], children: /* @__PURE__ */ jsx2(Text2, { style: [calendarStyles.cardHeaderText, headerTextStyle], children: viewModel.monthAndYearText }) }),
737
+ /* @__PURE__ */ jsxs2(View2, { style: calendarStyles.table, children: [
738
+ /* @__PURE__ */ jsx2(View2, { style: calendarStyles.tableHeader, children: viewModel.days.map((day) => /* @__PURE__ */ jsx2(View2, { style: calendarStyles.tableHeaderCell, children: /* @__PURE__ */ jsx2(Text2, { style: calendarStyles.tableHeaderText, children: day.slice(0, 3) }) }, day)) }),
739
+ viewModel.calendarDates.map((week, weekIndex) => /* @__PURE__ */ jsx2(View2, { style: calendarStyles.tableRow, children: week.map((calendarDate, dayIndex) => {
740
+ const cellClasses = getCellClasses(calendarDate);
741
+ const isToday2 = cellClasses.includes(
742
+ "schedule--current--exam"
743
+ );
744
+ const hasEvents2 = cellClasses.includes("has--event");
745
+ return /* @__PURE__ */ jsx2(
746
+ TouchableOpacity2,
747
+ {
748
+ style: [
749
+ calendarStyles.tableCell,
750
+ cellStyle,
751
+ isToday2 && calendarStyles.cellToday,
752
+ hasEvents2 && calendarStyles.cellWithEvents
753
+ ],
754
+ onPress: () => {
755
+ if (calendarDate) {
756
+ handleDatePress(calendarDate.date, dayIndex);
757
+ }
758
+ },
759
+ disabled: !calendarDate,
760
+ children: calendarDate && /* @__PURE__ */ jsxs2(Fragment, { children: [
761
+ /* @__PURE__ */ jsx2(
762
+ Text2,
763
+ {
764
+ style: [
765
+ calendarStyles.tableCellText,
766
+ cellTextStyle,
767
+ isToday2 && calendarStyles.cellTodayText
768
+ ],
769
+ children: calendarDate.date.getDate()
770
+ }
771
+ ),
772
+ hasEvents2 && /* @__PURE__ */ jsx2(View2, { style: calendarStyles.eventIndicator })
773
+ ] })
774
+ },
775
+ `${weekIndex}-${dayIndex}`
776
+ );
777
+ }) }, weekIndex))
778
+ ] }),
779
+ /* @__PURE__ */ jsxs2(View2, { style: calendarStyles.navigationContainer, children: [
780
+ /* @__PURE__ */ jsx2(
781
+ TouchableOpacity2,
782
+ {
783
+ style: calendarStyles.navigationButton,
784
+ onPress: handlePrevious,
785
+ children: /* @__PURE__ */ jsx2(Text2, { style: calendarStyles.navigationButtonText, children: "Previous" })
786
+ }
787
+ ),
788
+ /* @__PURE__ */ jsx2(
789
+ TouchableOpacity2,
790
+ {
791
+ style: calendarStyles.navigationButton,
792
+ onPress: handleNext,
793
+ children: /* @__PURE__ */ jsx2(Text2, { style: calendarStyles.navigationButtonText, children: "Next" })
794
+ }
795
+ )
796
+ ] }),
797
+ /* @__PURE__ */ jsxs2(View2, { style: calendarStyles.jumpForm, children: [
798
+ /* @__PURE__ */ jsx2(Text2, { style: calendarStyles.jumpLabel, children: "Jump To:" }),
799
+ /* @__PURE__ */ jsx2(
800
+ Select,
801
+ {
802
+ options: monthOptions,
803
+ selectedValue: viewModel.currentMonth,
804
+ onValueChange: handleMonthChange
805
+ }
806
+ ),
807
+ /* @__PURE__ */ jsx2(
808
+ Select,
809
+ {
810
+ options: yearOptions,
811
+ selectedValue: viewModel.currentYear,
812
+ onValueChange: handleYearChange
813
+ }
814
+ )
815
+ ] })
816
+ ] }) }),
817
+ /* @__PURE__ */ jsx2(
818
+ DatePopup,
819
+ {
820
+ visible: !!selectedDate,
821
+ selectedDate,
822
+ events: tasks,
823
+ scheduleDay: viewModel.scheduleDay,
824
+ onClose: closePopup,
825
+ renderEvent,
826
+ renderNoEvents,
827
+ showCloseButton
828
+ }
829
+ )
830
+ ] });
831
+ };
832
+ export {
833
+ Calendar,
834
+ CalendarEngine,
835
+ DAYS,
836
+ DatePopup,
837
+ MONTHS,
838
+ calendarStyles,
839
+ formatDateForDisplay,
840
+ generateCalendarDates,
841
+ generateYears,
842
+ getCellClasses,
843
+ getEventsForDate,
844
+ getMonthYearText,
845
+ getPopupPositionClass,
846
+ hasEvents,
847
+ isSameDay,
848
+ isToday,
849
+ normalizeDate
850
+ };
851
+ //# sourceMappingURL=index.mjs.map