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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1403 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name2 in all)
4
+ __defProp(target, name2, { get: all[name2], enumerable: true });
5
+ };
6
+
7
+ // src/core/utils.ts
8
+ var MONTHS = [
9
+ "Jan",
10
+ "Feb",
11
+ "Mar",
12
+ "Apr",
13
+ "May",
14
+ "Jun",
15
+ "Jul",
16
+ "Aug",
17
+ "Sep",
18
+ "Oct",
19
+ "Nov",
20
+ "Dec"
21
+ ];
22
+ var DAYS = [
23
+ "Sunday",
24
+ "Monday",
25
+ "Tuesday",
26
+ "Wednesday",
27
+ "Thursday",
28
+ "Friday",
29
+ "Saturday"
30
+ ];
31
+ function normalizeDate(date) {
32
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
33
+ }
34
+ function isSameDay(date1, date2) {
35
+ return normalizeDate(date1).getTime() === normalizeDate(date2).getTime();
36
+ }
37
+ function isToday(date) {
38
+ return isSameDay(date, /* @__PURE__ */ new Date());
39
+ }
40
+ function generateYears(minYear, maxYear) {
41
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
42
+ const min = minYear ?? currentYear - 30;
43
+ const max = maxYear ?? currentYear + 10;
44
+ return Array.from({ length: max - min + 1 }, (_, i) => min + i);
45
+ }
46
+ function getEventsForDate(events, date) {
47
+ const normalizedTargetDate = normalizeDate(date);
48
+ return events.filter((event) => {
49
+ const eventDate = normalizeDate(new Date(event.date));
50
+ return eventDate.getTime() === normalizedTargetDate.getTime();
51
+ });
52
+ }
53
+ function hasEvents(events, date) {
54
+ return getEventsForDate(events, date).length > 0;
55
+ }
56
+ function generateCalendarDates(year, month, events = [], weekStartsOn = 0) {
57
+ const firstDay = new Date(year, month, 1);
58
+ const lastDay = new Date(year, month + 1, 0);
59
+ const daysInMonth = lastDay.getDate();
60
+ let firstDayOfWeek = firstDay.getDay();
61
+ if (weekStartsOn === 1) {
62
+ firstDayOfWeek = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;
63
+ }
64
+ const dates = [];
65
+ let day = 1;
66
+ for (let week = 0; week < 6; week++) {
67
+ const weekDates = [];
68
+ for (let dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
69
+ if (week === 0 && dayOfWeek < firstDayOfWeek) {
70
+ weekDates.push(null);
71
+ } else if (day > daysInMonth) {
72
+ weekDates.push(null);
73
+ } else {
74
+ const currentDate = new Date(year, month, day);
75
+ const dateEvents = getEventsForDate(events, currentDate);
76
+ weekDates.push({
77
+ date: currentDate,
78
+ isCurrentMonth: true,
79
+ isToday: isToday(currentDate),
80
+ hasEvents: dateEvents.length > 0,
81
+ events: dateEvents
82
+ });
83
+ day++;
84
+ }
85
+ }
86
+ dates.push(weekDates);
87
+ if (day > daysInMonth && weekDates.every((date) => date === null)) {
88
+ break;
89
+ }
90
+ }
91
+ return dates;
92
+ }
93
+ function getPopupPositionClass(selectedDayIndex) {
94
+ if (selectedDayIndex === null) return "popup-center-bottom";
95
+ if (selectedDayIndex < 3) {
96
+ return "popup-right";
97
+ } else if (selectedDayIndex > 4) {
98
+ return "popup-left";
99
+ } else {
100
+ return "popup-center-bottom";
101
+ }
102
+ }
103
+ function getCellClasses(calendarDate) {
104
+ if (!calendarDate) return [];
105
+ const classes = [];
106
+ if (calendarDate.isToday) {
107
+ classes.push("schedule--current--exam");
108
+ }
109
+ if (calendarDate.hasEvents) {
110
+ classes.push("has--event");
111
+ }
112
+ return classes;
113
+ }
114
+ function formatDateForDisplay(date) {
115
+ return `${DAYS[date.getDay()]} ${date.getDate()}`;
116
+ }
117
+ function getMonthYearText(year, month) {
118
+ return `${MONTHS[month]} ${year}`;
119
+ }
120
+
121
+ // src/core/calendar-engine.ts
122
+ var CalendarEngine = class {
123
+ constructor(config) {
124
+ this.listeners = /* @__PURE__ */ new Set();
125
+ this.config = config;
126
+ const initialDate = config.initialDate || /* @__PURE__ */ new Date();
127
+ this.state = {
128
+ currentYear: initialDate.getFullYear(),
129
+ currentMonth: initialDate.getMonth(),
130
+ currentDate: initialDate.getDate(),
131
+ selectedDate: null,
132
+ selectedDayIndex: null,
133
+ tasks: []
134
+ };
135
+ }
136
+ /**
137
+ * Subscribe to state changes
138
+ */
139
+ subscribe(listener) {
140
+ this.listeners.add(listener);
141
+ return () => this.listeners.delete(listener);
142
+ }
143
+ /**
144
+ * Notify all listeners of state changes
145
+ */
146
+ notify() {
147
+ this.listeners.forEach((listener) => listener());
148
+ }
149
+ /**
150
+ * Get current state
151
+ */
152
+ getState() {
153
+ return { ...this.state };
154
+ }
155
+ /**
156
+ * Get view model with computed properties
157
+ */
158
+ getViewModel() {
159
+ const calendarDates = generateCalendarDates(
160
+ this.state.currentYear,
161
+ this.state.currentMonth,
162
+ this.config.events,
163
+ this.config.weekStartsOn
164
+ );
165
+ return {
166
+ ...this.state,
167
+ months: MONTHS,
168
+ days: DAYS,
169
+ years: generateYears(this.config.minYear, this.config.maxYear),
170
+ monthAndYearText: getMonthYearText(
171
+ this.state.currentYear,
172
+ this.state.currentMonth
173
+ ),
174
+ scheduleDay: this.state.selectedDate ? formatDateForDisplay(this.state.selectedDate) : "",
175
+ calendarDates,
176
+ popupPositionClass: getPopupPositionClass(this.state.selectedDayIndex)
177
+ };
178
+ }
179
+ /**
180
+ * Get actions object
181
+ */
182
+ getActions() {
183
+ return {
184
+ next: this.next.bind(this),
185
+ previous: this.previous.bind(this),
186
+ jump: this.jump.bind(this),
187
+ selectDate: this.selectDate.bind(this),
188
+ updateTasks: this.updateTasks.bind(this)
189
+ };
190
+ }
191
+ /**
192
+ * Navigate to next month
193
+ */
194
+ next() {
195
+ if (this.state.currentMonth === 11) {
196
+ this.state.currentMonth = 0;
197
+ this.state.currentYear++;
198
+ } else {
199
+ this.state.currentMonth++;
200
+ }
201
+ this.state.selectedDate = null;
202
+ this.state.selectedDayIndex = null;
203
+ this.updateTasks();
204
+ this.notify();
205
+ }
206
+ /**
207
+ * Navigate to previous month
208
+ */
209
+ previous() {
210
+ if (this.state.currentMonth === 0) {
211
+ this.state.currentMonth = 11;
212
+ this.state.currentYear--;
213
+ } else {
214
+ this.state.currentMonth--;
215
+ }
216
+ this.state.selectedDate = null;
217
+ this.state.selectedDayIndex = null;
218
+ this.updateTasks();
219
+ this.notify();
220
+ }
221
+ /**
222
+ * Jump to specific month and year
223
+ */
224
+ jump(year, month) {
225
+ this.state.currentYear = year;
226
+ this.state.currentMonth = month;
227
+ this.state.selectedDate = null;
228
+ this.state.selectedDayIndex = null;
229
+ this.updateTasks();
230
+ this.notify();
231
+ }
232
+ /**
233
+ * Select a specific date
234
+ */
235
+ selectDate(date, dayIndex) {
236
+ this.state.selectedDate = date;
237
+ this.state.selectedDayIndex = dayIndex ?? null;
238
+ this.state.currentDate = date.getDate();
239
+ this.state.currentMonth = date.getMonth();
240
+ this.state.currentYear = date.getFullYear();
241
+ this.updateTasks();
242
+ this.notify();
243
+ }
244
+ /**
245
+ * Update tasks for the currently selected date
246
+ */
247
+ updateTasks() {
248
+ if (!this.state.selectedDate) {
249
+ this.state.tasks = [];
250
+ return;
251
+ }
252
+ this.state.tasks = getEventsForDate(
253
+ this.config.events,
254
+ this.state.selectedDate
255
+ );
256
+ }
257
+ /**
258
+ * Update events configuration
259
+ */
260
+ updateEvents(events) {
261
+ this.config.events = events;
262
+ this.updateTasks();
263
+ this.notify();
264
+ }
265
+ /**
266
+ * Handle date cell click
267
+ */
268
+ handleDateClick(date, dayIndex) {
269
+ this.selectDate(date, dayIndex);
270
+ }
271
+ /**
272
+ * Check if date has events
273
+ */
274
+ hasEventsForDate(date) {
275
+ return getEventsForDate(this.config.events, date).length > 0;
276
+ }
277
+ /**
278
+ * Get events for a specific date
279
+ */
280
+ getEventsForDate(date) {
281
+ return getEventsForDate(this.config.events, date);
282
+ }
283
+ /**
284
+ * Clear selected date
285
+ */
286
+ clearSelection() {
287
+ this.state.selectedDate = null;
288
+ this.state.selectedDayIndex = null;
289
+ this.state.tasks = [];
290
+ this.notify();
291
+ }
292
+ /**
293
+ * Destroy the engine and cleanup listeners
294
+ */
295
+ destroy() {
296
+ this.listeners.clear();
297
+ }
298
+ };
299
+
300
+ // src/react/index.tsx
301
+ var react_exports = {};
302
+ __export(react_exports, {
303
+ Calendar: () => Calendar,
304
+ CalendarEngine: () => CalendarEngine,
305
+ DAYS: () => DAYS,
306
+ DatePopup: () => DatePopup,
307
+ MONTHS: () => MONTHS,
308
+ formatDateForDisplay: () => formatDateForDisplay,
309
+ generateCalendarDates: () => generateCalendarDates,
310
+ generateYears: () => generateYears,
311
+ getCellClasses: () => getCellClasses,
312
+ getEventsForDate: () => getEventsForDate,
313
+ getMonthYearText: () => getMonthYearText,
314
+ getPopupPositionClass: () => getPopupPositionClass,
315
+ hasEvents: () => hasEvents,
316
+ isSameDay: () => isSameDay,
317
+ isToday: () => isToday,
318
+ normalizeDate: () => normalizeDate
319
+ });
320
+
321
+ // src/react/components/Calendar.tsx
322
+ import { useEffect, useState, useCallback, useMemo } from "react";
323
+
324
+ // src/react/components/DatePopup.tsx
325
+ import { jsx, jsxs } from "react/jsx-runtime";
326
+ var DatePopup = ({
327
+ isVisible,
328
+ selectedDate,
329
+ events,
330
+ scheduleDay,
331
+ popupPositionClass,
332
+ onEventClick,
333
+ onClose,
334
+ renderEvent,
335
+ renderNoEvents
336
+ }) => {
337
+ if (!isVisible || !selectedDate) return null;
338
+ const handleEventClick = (event) => {
339
+ onEventClick?.(event);
340
+ };
341
+ const defaultRenderEvent = (event) => /* @__PURE__ */ jsx(
342
+ "li",
343
+ {
344
+ className: `event--item${onEventClick ? " clickable" : ""}`,
345
+ onClick: () => handleEventClick(event),
346
+ children: event.name
347
+ },
348
+ event.id || event.name
349
+ );
350
+ const defaultRenderNoEvents = () => /* @__PURE__ */ jsx("div", { className: "no-events-message", children: "No events scheduled for this day." });
351
+ return /* @__PURE__ */ jsxs("div", { className: `date-popup ${popupPositionClass}`, children: [
352
+ /* @__PURE__ */ jsx(
353
+ "button",
354
+ {
355
+ type: "button",
356
+ className: "popup-close",
357
+ onClick: onClose,
358
+ "aria-label": "Close",
359
+ children: "\u2715"
360
+ }
361
+ ),
362
+ /* @__PURE__ */ jsxs("div", { className: "schedule--wrapper", children: [
363
+ /* @__PURE__ */ jsx("div", { className: "schedule--block", children: /* @__PURE__ */ jsx("h2", { className: "schedule--day", children: scheduleDay }) }),
364
+ events.length > 0 ? /* @__PURE__ */ jsx("div", { className: "event--wrapper", children: /* @__PURE__ */ jsx("ul", { children: events.map(
365
+ (event) => renderEvent ? /* @__PURE__ */ jsx(
366
+ "li",
367
+ {
368
+ className: `event--item${onEventClick ? " clickable" : ""}`,
369
+ onClick: () => handleEventClick(event),
370
+ children: renderEvent(event)
371
+ },
372
+ event.id || event.name
373
+ ) : defaultRenderEvent(event)
374
+ ) }) }) : renderNoEvents ? renderNoEvents() : defaultRenderNoEvents()
375
+ ] })
376
+ ] });
377
+ };
378
+
379
+ // src/react/components/Calendar.tsx
380
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
381
+ var Calendar = ({
382
+ events,
383
+ initialDate,
384
+ minYear,
385
+ maxYear,
386
+ weekStartsOn = 0,
387
+ onDateSelect,
388
+ onEventClick,
389
+ onMonthChange,
390
+ className = "",
391
+ style,
392
+ renderEvent,
393
+ renderNoEvents,
394
+ title = "Event Schedule"
395
+ }) => {
396
+ const engine = useMemo(
397
+ () => new CalendarEngine({
398
+ events,
399
+ initialDate,
400
+ minYear,
401
+ maxYear,
402
+ weekStartsOn
403
+ }),
404
+ []
405
+ );
406
+ const [, forceUpdate] = useState({});
407
+ const rerender = useCallback(() => forceUpdate({}), []);
408
+ useEffect(() => {
409
+ const unsubscribe = engine.subscribe(rerender);
410
+ return unsubscribe;
411
+ }, [engine, rerender]);
412
+ useEffect(() => {
413
+ engine.updateEvents(events);
414
+ }, [engine, events]);
415
+ useEffect(() => {
416
+ return () => {
417
+ engine.destroy();
418
+ };
419
+ }, [engine]);
420
+ const viewModel = engine.getViewModel();
421
+ const actions = engine.getActions();
422
+ const { selectedDate, tasks, selectedDayIndex } = viewModel;
423
+ const handleDateClick = (event) => {
424
+ const td = event.target.closest("td");
425
+ if (!td) return;
426
+ const cellContent = td.textContent?.trim();
427
+ if (!cellContent) return;
428
+ const clickedDate = new Date(
429
+ viewModel.currentYear,
430
+ viewModel.currentMonth,
431
+ parseInt(cellContent)
432
+ );
433
+ const dayIndex = td.parentNode ? Array.from(td.parentNode.children).indexOf(td) : 0;
434
+ engine.handleDateClick(clickedDate, dayIndex);
435
+ onDateSelect?.(clickedDate);
436
+ };
437
+ const handleMonthChange = () => {
438
+ onMonthChange?.(viewModel.currentYear, viewModel.currentMonth);
439
+ };
440
+ const handleYearChange = (event) => {
441
+ const year = parseInt(event.target.value);
442
+ actions.jump(year, viewModel.currentMonth);
443
+ handleMonthChange();
444
+ };
445
+ const handleMonthSelectChange = (event) => {
446
+ const month = parseInt(event.target.value);
447
+ actions.jump(viewModel.currentYear, month);
448
+ handleMonthChange();
449
+ };
450
+ const handleNext = () => {
451
+ actions.next();
452
+ handleMonthChange();
453
+ };
454
+ const handlePrevious = () => {
455
+ actions.previous();
456
+ handleMonthChange();
457
+ };
458
+ return /* @__PURE__ */ jsxs2("div", { className: `kalendly-calendar ${className}`, style, children: [
459
+ title && /* @__PURE__ */ jsx2("div", { className: "page--title", children: /* @__PURE__ */ jsx2("h1", { children: title }) }),
460
+ /* @__PURE__ */ jsx2("div", { className: "calendar--content", children: /* @__PURE__ */ jsxs2("div", { className: "calendar--card", children: [
461
+ /* @__PURE__ */ jsx2("h3", { className: "calendar--card--header", children: viewModel.monthAndYearText }),
462
+ /* @__PURE__ */ jsxs2("table", { className: "calendar--table calendar--table--bordered", children: [
463
+ /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: viewModel.days.map((day) => /* @__PURE__ */ jsx2("th", { children: day.slice(0, 3) }, day)) }) }),
464
+ /* @__PURE__ */ jsx2("tbody", { onClick: handleDateClick, children: viewModel.calendarDates.map((week, weekIndex) => /* @__PURE__ */ jsx2("tr", { children: week.map((calendarDate, dayIndex) => {
465
+ const cellClasses = getCellClasses(calendarDate);
466
+ return /* @__PURE__ */ jsx2(
467
+ "td",
468
+ {
469
+ className: cellClasses.join(" "),
470
+ children: calendarDate?.date.getDate() || ""
471
+ },
472
+ `${weekIndex}-${dayIndex}`
473
+ );
474
+ }) }, weekIndex)) })
475
+ ] }),
476
+ /* @__PURE__ */ jsxs2("div", { className: "calendar--navigation--buttons", children: [
477
+ /* @__PURE__ */ jsx2(
478
+ "button",
479
+ {
480
+ className: "calendar--navigation--btn",
481
+ onClick: handlePrevious,
482
+ children: "Previous"
483
+ }
484
+ ),
485
+ /* @__PURE__ */ jsx2("button", { className: "calendar--navigation--btn", onClick: handleNext, children: "Next" })
486
+ ] }),
487
+ /* @__PURE__ */ jsxs2("form", { className: "calendar--form--jump", children: [
488
+ /* @__PURE__ */ jsx2("div", { className: "calendar--lead", children: "Jump To:" }),
489
+ /* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsx2("label", { className: "calendar--form--jump--item", children: /* @__PURE__ */ jsx2(
490
+ "select",
491
+ {
492
+ value: viewModel.currentMonth,
493
+ onChange: handleMonthSelectChange,
494
+ "aria-label": "Select month",
495
+ children: viewModel.months.map((month, index) => /* @__PURE__ */ jsx2("option", { value: index, children: month }, index))
496
+ }
497
+ ) }) }),
498
+ /* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsx2("label", { className: "calendar--form--jump--item", children: /* @__PURE__ */ jsx2(
499
+ "select",
500
+ {
501
+ value: viewModel.currentYear,
502
+ onChange: handleYearChange,
503
+ "aria-label": "Select year",
504
+ children: viewModel.years.map((year) => /* @__PURE__ */ jsx2("option", { value: year, children: year }, year))
505
+ }
506
+ ) }) })
507
+ ] }),
508
+ /* @__PURE__ */ jsx2(
509
+ DatePopup,
510
+ {
511
+ isVisible: !!selectedDate,
512
+ selectedDate,
513
+ events: tasks,
514
+ scheduleDay: viewModel.scheduleDay,
515
+ popupPositionClass: viewModel.popupPositionClass,
516
+ onClose: () => engine.clearSelection(),
517
+ onEventClick,
518
+ renderEvent,
519
+ renderNoEvents
520
+ }
521
+ )
522
+ ] }) })
523
+ ] });
524
+ };
525
+
526
+ // src/react-native/index.tsx
527
+ var react_native_exports = {};
528
+ __export(react_native_exports, {
529
+ Calendar: () => Calendar2,
530
+ CalendarEngine: () => CalendarEngine,
531
+ DAYS: () => DAYS,
532
+ DatePopup: () => DatePopup2,
533
+ MONTHS: () => MONTHS,
534
+ calendarStyles: () => calendarStyles,
535
+ formatDateForDisplay: () => formatDateForDisplay,
536
+ generateCalendarDates: () => generateCalendarDates,
537
+ generateYears: () => generateYears,
538
+ getCellClasses: () => getCellClasses,
539
+ getEventsForDate: () => getEventsForDate,
540
+ getMonthYearText: () => getMonthYearText,
541
+ getPopupPositionClass: () => getPopupPositionClass,
542
+ hasEvents: () => hasEvents,
543
+ isSameDay: () => isSameDay,
544
+ isToday: () => isToday,
545
+ normalizeDate: () => normalizeDate
546
+ });
547
+
548
+ // src/react-native/components/Calendar.tsx
549
+ import { useEffect as useEffect2, useState as useState2, useCallback as useCallback2, useMemo as useMemo2 } from "react";
550
+ import { View as View2, Text as Text2, TouchableOpacity as TouchableOpacity2, ScrollView as ScrollView2, Alert } from "react-native";
551
+
552
+ // src/react-native/components/DatePopup.tsx
553
+ import { Modal, View, Text, TouchableOpacity, ScrollView } from "react-native";
554
+
555
+ // src/styles/react-native-styles.ts
556
+ import { StyleSheet, Dimensions } from "react-native";
557
+ var { width } = Dimensions.get("window");
558
+ var cellSize = (width - 60) / 7;
559
+ var colors = {
560
+ primary: "#fc8917",
561
+ secondary: "#fca045",
562
+ tertiary: "#fdb873",
563
+ text: "#2c3e50",
564
+ border: "#dee2e6",
565
+ todayOutline: "#f7db04",
566
+ eventIndicator: "#1890ff",
567
+ background: "#fff",
568
+ white: "#ffffff"
569
+ };
570
+ var calendarStyles = StyleSheet.create({
571
+ container: {
572
+ flex: 1,
573
+ backgroundColor: colors.background
574
+ },
575
+ titleContainer: {
576
+ paddingVertical: 20,
577
+ alignItems: "center"
578
+ },
579
+ title: {
580
+ fontSize: 24,
581
+ fontWeight: "600",
582
+ color: colors.text
583
+ },
584
+ contentContainer: {
585
+ marginHorizontal: 20,
586
+ marginTop: 20
587
+ },
588
+ card: {
589
+ backgroundColor: colors.background,
590
+ borderRadius: 8,
591
+ shadowColor: "#000",
592
+ shadowOffset: {
593
+ width: 0,
594
+ height: 2
595
+ },
596
+ shadowOpacity: 0.1,
597
+ shadowRadius: 3.84,
598
+ elevation: 5,
599
+ overflow: "hidden"
600
+ },
601
+ cardHeader: {
602
+ backgroundColor: colors.tertiary,
603
+ paddingVertical: 15,
604
+ paddingHorizontal: 20,
605
+ borderBottomWidth: 1,
606
+ borderBottomColor: colors.border
607
+ },
608
+ cardHeaderText: {
609
+ fontSize: 18,
610
+ fontWeight: "500",
611
+ color: colors.text,
612
+ textAlign: "center"
613
+ },
614
+ // Calendar Table Styles
615
+ table: {
616
+ backgroundColor: colors.background
617
+ },
618
+ tableHeader: {
619
+ flexDirection: "row",
620
+ backgroundColor: "rgba(252, 137, 23, 0.1)",
621
+ borderBottomWidth: 2,
622
+ borderBottomColor: colors.border
623
+ },
624
+ tableHeaderCell: {
625
+ flex: 1,
626
+ paddingVertical: 12,
627
+ borderRightWidth: 1,
628
+ borderRightColor: colors.border,
629
+ alignItems: "center",
630
+ justifyContent: "center"
631
+ },
632
+ tableHeaderText: {
633
+ fontSize: 14,
634
+ fontWeight: "600",
635
+ color: colors.text
636
+ },
637
+ tableRow: {
638
+ flexDirection: "row",
639
+ borderBottomWidth: 1,
640
+ borderBottomColor: colors.border
641
+ },
642
+ tableCell: {
643
+ flex: 1,
644
+ height: cellSize,
645
+ borderRightWidth: 1,
646
+ borderRightColor: colors.border,
647
+ alignItems: "center",
648
+ justifyContent: "center",
649
+ position: "relative"
650
+ },
651
+ tableCellText: {
652
+ fontSize: 16,
653
+ color: colors.text
654
+ },
655
+ // Calendar Cell States
656
+ cellToday: {
657
+ borderWidth: 2,
658
+ borderColor: colors.todayOutline
659
+ },
660
+ cellTodayText: {
661
+ fontWeight: "bold"
662
+ },
663
+ cellWithEvents: {
664
+ backgroundColor: "rgba(252, 160, 69, 0.3)"
665
+ },
666
+ eventIndicator: {
667
+ position: "absolute",
668
+ bottom: 2,
669
+ width: 4,
670
+ height: 4,
671
+ backgroundColor: colors.eventIndicator,
672
+ borderRadius: 2
673
+ },
674
+ // Navigation Buttons
675
+ navigationContainer: {
676
+ flexDirection: "row",
677
+ justifyContent: "space-between",
678
+ paddingHorizontal: 20,
679
+ paddingVertical: 20,
680
+ gap: 15
681
+ },
682
+ navigationButton: {
683
+ flex: 1,
684
+ backgroundColor: "transparent",
685
+ borderWidth: 1,
686
+ borderColor: colors.primary,
687
+ borderRadius: 6,
688
+ paddingVertical: 12,
689
+ paddingHorizontal: 16,
690
+ alignItems: "center",
691
+ justifyContent: "center"
692
+ },
693
+ navigationButtonText: {
694
+ color: colors.primary,
695
+ fontSize: 16,
696
+ fontWeight: "500"
697
+ },
698
+ navigationButtonPressed: {
699
+ backgroundColor: colors.primary
700
+ },
701
+ navigationButtonTextPressed: {
702
+ color: colors.white
703
+ },
704
+ // Jump Form
705
+ jumpForm: {
706
+ flexDirection: "row",
707
+ alignItems: "center",
708
+ justifyContent: "center",
709
+ paddingHorizontal: 20,
710
+ paddingBottom: 20,
711
+ gap: 10
712
+ },
713
+ jumpLabel: {
714
+ fontSize: 18,
715
+ fontWeight: "300",
716
+ color: colors.text
717
+ },
718
+ jumpSelect: {
719
+ borderWidth: 1,
720
+ borderColor: colors.border,
721
+ borderRadius: 6,
722
+ paddingHorizontal: 12,
723
+ paddingVertical: 8,
724
+ backgroundColor: colors.background,
725
+ minWidth: 80
726
+ },
727
+ jumpSelectText: {
728
+ fontSize: 16,
729
+ color: colors.text,
730
+ textAlign: "center"
731
+ },
732
+ // Popup Styles
733
+ popupOverlay: {
734
+ position: "absolute",
735
+ top: 0,
736
+ left: 0,
737
+ right: 0,
738
+ bottom: 0,
739
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
740
+ justifyContent: "center",
741
+ alignItems: "center",
742
+ zIndex: 1e3
743
+ },
744
+ popup: {
745
+ backgroundColor: colors.background,
746
+ borderRadius: 12,
747
+ padding: 0,
748
+ width: width * 0.8,
749
+ maxWidth: 300,
750
+ shadowColor: "#000",
751
+ shadowOffset: {
752
+ width: 0,
753
+ height: 4
754
+ },
755
+ shadowOpacity: 0.3,
756
+ shadowRadius: 6,
757
+ elevation: 8
758
+ },
759
+ popupWrapper: {
760
+ backgroundColor: colors.secondary,
761
+ borderRadius: 12,
762
+ padding: 12
763
+ },
764
+ popupBlock: {
765
+ backgroundColor: colors.primary,
766
+ borderRadius: 8,
767
+ paddingVertical: 8,
768
+ paddingHorizontal: 12,
769
+ marginBottom: 10
770
+ },
771
+ popupDay: {
772
+ fontSize: 16,
773
+ fontWeight: "600",
774
+ color: colors.white,
775
+ textAlign: "center"
776
+ },
777
+ eventsList: {
778
+ gap: 6
779
+ },
780
+ eventItem: {
781
+ backgroundColor: colors.tertiary,
782
+ borderRadius: 6,
783
+ padding: 12
784
+ },
785
+ eventItemText: {
786
+ fontSize: 14,
787
+ color: colors.text
788
+ },
789
+ noEventsMessage: {
790
+ backgroundColor: colors.tertiary,
791
+ borderRadius: 6,
792
+ padding: 12,
793
+ alignItems: "center"
794
+ },
795
+ noEventsText: {
796
+ fontSize: 14,
797
+ color: colors.text,
798
+ textAlign: "center"
799
+ },
800
+ popupCloseButton: {
801
+ position: "absolute",
802
+ top: -10,
803
+ right: -10,
804
+ backgroundColor: colors.primary,
805
+ borderRadius: 15,
806
+ width: 30,
807
+ height: 30,
808
+ alignItems: "center",
809
+ justifyContent: "center"
810
+ },
811
+ popupCloseText: {
812
+ color: colors.white,
813
+ fontSize: 16,
814
+ fontWeight: "bold"
815
+ }
816
+ });
817
+
818
+ // src/react-native/components/DatePopup.tsx
819
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
820
+ var DatePopup2 = ({
821
+ visible,
822
+ selectedDate,
823
+ events,
824
+ scheduleDay,
825
+ onClose,
826
+ renderEvent,
827
+ renderNoEvents,
828
+ showCloseButton = true
829
+ }) => {
830
+ if (!selectedDate) return null;
831
+ const defaultRenderEvent = (event) => /* @__PURE__ */ jsx3(View, { style: calendarStyles.eventItem, children: /* @__PURE__ */ jsx3(Text, { style: calendarStyles.eventItemText, children: event.name }) }, event.id || event.name);
832
+ const defaultRenderNoEvents = () => /* @__PURE__ */ jsx3(View, { style: calendarStyles.noEventsMessage, children: /* @__PURE__ */ jsx3(Text, { style: calendarStyles.noEventsText, children: "No events scheduled for this day." }) });
833
+ return /* @__PURE__ */ jsx3(
834
+ Modal,
835
+ {
836
+ visible,
837
+ transparent: true,
838
+ animationType: "fade",
839
+ onRequestClose: onClose,
840
+ children: /* @__PURE__ */ jsx3(
841
+ TouchableOpacity,
842
+ {
843
+ style: calendarStyles.popupOverlay,
844
+ activeOpacity: 1,
845
+ onPress: onClose,
846
+ children: /* @__PURE__ */ jsxs3(
847
+ TouchableOpacity,
848
+ {
849
+ style: calendarStyles.popup,
850
+ activeOpacity: 1,
851
+ onPress: (e) => e.stopPropagation(),
852
+ children: [
853
+ /* @__PURE__ */ jsxs3(View, { style: calendarStyles.popupWrapper, children: [
854
+ showCloseButton && /* @__PURE__ */ jsx3(
855
+ TouchableOpacity,
856
+ {
857
+ style: calendarStyles.popupCloseButton,
858
+ onPress: onClose,
859
+ accessibilityLabel: "Close",
860
+ children: /* @__PURE__ */ jsx3(Text, { style: calendarStyles.popupCloseText, children: "\u2715" })
861
+ }
862
+ ),
863
+ /* @__PURE__ */ jsx3(View, { style: calendarStyles.popupBlock, children: /* @__PURE__ */ jsx3(Text, { style: calendarStyles.popupDay, children: scheduleDay }) }),
864
+ /* @__PURE__ */ jsx3(ScrollView, { showsVerticalScrollIndicator: false, children: events.length > 0 ? /* @__PURE__ */ jsx3(View, { style: calendarStyles.eventsList, children: events.map(
865
+ (event) => renderEvent ? renderEvent(event) : defaultRenderEvent(event)
866
+ ) }) : renderNoEvents ? renderNoEvents() : defaultRenderNoEvents() })
867
+ ] }),
868
+ showCloseButton && /* @__PURE__ */ jsx3(
869
+ TouchableOpacity,
870
+ {
871
+ style: calendarStyles.popupCloseButton,
872
+ onPress: onClose,
873
+ children: /* @__PURE__ */ jsx3(Text, { style: calendarStyles.popupCloseText, children: "\xD7" })
874
+ }
875
+ )
876
+ ]
877
+ }
878
+ )
879
+ }
880
+ )
881
+ }
882
+ );
883
+ };
884
+
885
+ // src/react-native/components/Calendar.tsx
886
+ import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
887
+ var Select = ({
888
+ options,
889
+ selectedValue,
890
+ onValueChange,
891
+ style,
892
+ textStyle
893
+ }) => {
894
+ const selectedOption = options.find((opt) => opt.value === selectedValue);
895
+ const showPicker = () => {
896
+ Alert.alert(
897
+ "Select Option",
898
+ "",
899
+ options.map((option) => ({
900
+ text: option.label,
901
+ onPress: () => onValueChange(option.value)
902
+ }))
903
+ );
904
+ };
905
+ return /* @__PURE__ */ jsx4(
906
+ TouchableOpacity2,
907
+ {
908
+ style: [calendarStyles.jumpSelect, style],
909
+ onPress: showPicker,
910
+ children: /* @__PURE__ */ jsx4(Text2, { style: [calendarStyles.jumpSelectText, textStyle], children: selectedOption?.label })
911
+ }
912
+ );
913
+ };
914
+ var Calendar2 = ({
915
+ events,
916
+ initialDate,
917
+ minYear,
918
+ maxYear,
919
+ weekStartsOn = 0,
920
+ onDateSelect,
921
+ onEventClick,
922
+ onMonthChange,
923
+ style,
924
+ containerStyle,
925
+ headerStyle,
926
+ headerTextStyle,
927
+ cellStyle,
928
+ cellTextStyle,
929
+ renderEvent,
930
+ renderNoEvents,
931
+ title = "Event Schedule",
932
+ showCloseButton = true
933
+ }) => {
934
+ const engine = useMemo2(
935
+ () => new CalendarEngine({
936
+ events,
937
+ initialDate,
938
+ minYear,
939
+ maxYear,
940
+ weekStartsOn
941
+ }),
942
+ []
943
+ );
944
+ const [, forceUpdate] = useState2({});
945
+ const rerender = useCallback2(() => forceUpdate({}), []);
946
+ useEffect2(() => {
947
+ const unsubscribe = engine.subscribe(rerender);
948
+ return unsubscribe;
949
+ }, [engine, rerender]);
950
+ useEffect2(() => {
951
+ engine.updateEvents(events);
952
+ }, [engine, events]);
953
+ const viewModel = engine.getViewModel();
954
+ const actions = engine.getActions();
955
+ const { selectedDate, tasks } = viewModel;
956
+ const handleDatePress = (date, dayIndex) => {
957
+ engine.handleDateClick(date, dayIndex);
958
+ onDateSelect?.(date);
959
+ };
960
+ const handleNext = () => {
961
+ actions.next();
962
+ onMonthChange?.(viewModel.currentYear, viewModel.currentMonth);
963
+ };
964
+ const handlePrevious = () => {
965
+ actions.previous();
966
+ onMonthChange?.(viewModel.currentYear, viewModel.currentMonth);
967
+ };
968
+ const handleMonthChange = (month) => {
969
+ actions.jump(viewModel.currentYear, month);
970
+ onMonthChange?.(viewModel.currentYear, month);
971
+ };
972
+ const handleYearChange = (year) => {
973
+ actions.jump(year, viewModel.currentMonth);
974
+ onMonthChange?.(year, viewModel.currentMonth);
975
+ };
976
+ const closePopup = () => {
977
+ engine.clearSelection();
978
+ };
979
+ const monthOptions = viewModel.months.map((month, index) => ({
980
+ label: month,
981
+ value: index
982
+ }));
983
+ const yearOptions = viewModel.years.map((year) => ({
984
+ label: year.toString(),
985
+ value: year
986
+ }));
987
+ return /* @__PURE__ */ jsxs4(ScrollView2, { style: [calendarStyles.container, containerStyle], children: [
988
+ title && /* @__PURE__ */ jsx4(View2, { style: calendarStyles.titleContainer, children: /* @__PURE__ */ jsx4(Text2, { style: calendarStyles.title, children: title }) }),
989
+ /* @__PURE__ */ jsx4(View2, { style: [calendarStyles.contentContainer, style], children: /* @__PURE__ */ jsxs4(View2, { style: calendarStyles.card, children: [
990
+ /* @__PURE__ */ jsx4(View2, { style: [calendarStyles.cardHeader, headerStyle], children: /* @__PURE__ */ jsx4(Text2, { style: [calendarStyles.cardHeaderText, headerTextStyle], children: viewModel.monthAndYearText }) }),
991
+ /* @__PURE__ */ jsxs4(View2, { style: calendarStyles.table, children: [
992
+ /* @__PURE__ */ jsx4(View2, { style: calendarStyles.tableHeader, children: viewModel.days.map((day) => /* @__PURE__ */ jsx4(View2, { style: calendarStyles.tableHeaderCell, children: /* @__PURE__ */ jsx4(Text2, { style: calendarStyles.tableHeaderText, children: day.slice(0, 3) }) }, day)) }),
993
+ viewModel.calendarDates.map((week, weekIndex) => /* @__PURE__ */ jsx4(View2, { style: calendarStyles.tableRow, children: week.map((calendarDate, dayIndex) => {
994
+ const cellClasses = getCellClasses(calendarDate);
995
+ const isToday2 = cellClasses.includes(
996
+ "schedule--current--exam"
997
+ );
998
+ const hasEvents2 = cellClasses.includes("has--event");
999
+ return /* @__PURE__ */ jsx4(
1000
+ TouchableOpacity2,
1001
+ {
1002
+ style: [
1003
+ calendarStyles.tableCell,
1004
+ cellStyle,
1005
+ isToday2 && calendarStyles.cellToday,
1006
+ hasEvents2 && calendarStyles.cellWithEvents
1007
+ ],
1008
+ onPress: () => {
1009
+ if (calendarDate) {
1010
+ handleDatePress(calendarDate.date, dayIndex);
1011
+ }
1012
+ },
1013
+ disabled: !calendarDate,
1014
+ children: calendarDate && /* @__PURE__ */ jsxs4(Fragment, { children: [
1015
+ /* @__PURE__ */ jsx4(
1016
+ Text2,
1017
+ {
1018
+ style: [
1019
+ calendarStyles.tableCellText,
1020
+ cellTextStyle,
1021
+ isToday2 && calendarStyles.cellTodayText
1022
+ ],
1023
+ children: calendarDate.date.getDate()
1024
+ }
1025
+ ),
1026
+ hasEvents2 && /* @__PURE__ */ jsx4(View2, { style: calendarStyles.eventIndicator })
1027
+ ] })
1028
+ },
1029
+ `${weekIndex}-${dayIndex}`
1030
+ );
1031
+ }) }, weekIndex))
1032
+ ] }),
1033
+ /* @__PURE__ */ jsxs4(View2, { style: calendarStyles.navigationContainer, children: [
1034
+ /* @__PURE__ */ jsx4(
1035
+ TouchableOpacity2,
1036
+ {
1037
+ style: calendarStyles.navigationButton,
1038
+ onPress: handlePrevious,
1039
+ children: /* @__PURE__ */ jsx4(Text2, { style: calendarStyles.navigationButtonText, children: "Previous" })
1040
+ }
1041
+ ),
1042
+ /* @__PURE__ */ jsx4(
1043
+ TouchableOpacity2,
1044
+ {
1045
+ style: calendarStyles.navigationButton,
1046
+ onPress: handleNext,
1047
+ children: /* @__PURE__ */ jsx4(Text2, { style: calendarStyles.navigationButtonText, children: "Next" })
1048
+ }
1049
+ )
1050
+ ] }),
1051
+ /* @__PURE__ */ jsxs4(View2, { style: calendarStyles.jumpForm, children: [
1052
+ /* @__PURE__ */ jsx4(Text2, { style: calendarStyles.jumpLabel, children: "Jump To:" }),
1053
+ /* @__PURE__ */ jsx4(
1054
+ Select,
1055
+ {
1056
+ options: monthOptions,
1057
+ selectedValue: viewModel.currentMonth,
1058
+ onValueChange: handleMonthChange
1059
+ }
1060
+ ),
1061
+ /* @__PURE__ */ jsx4(
1062
+ Select,
1063
+ {
1064
+ options: yearOptions,
1065
+ selectedValue: viewModel.currentYear,
1066
+ onValueChange: handleYearChange
1067
+ }
1068
+ )
1069
+ ] })
1070
+ ] }) }),
1071
+ /* @__PURE__ */ jsx4(
1072
+ DatePopup2,
1073
+ {
1074
+ visible: !!selectedDate,
1075
+ selectedDate,
1076
+ events: tasks,
1077
+ scheduleDay: viewModel.scheduleDay,
1078
+ onClose: closePopup,
1079
+ renderEvent,
1080
+ renderNoEvents,
1081
+ showCloseButton
1082
+ }
1083
+ )
1084
+ ] });
1085
+ };
1086
+
1087
+ // src/vanilla/index.ts
1088
+ var vanilla_exports = {};
1089
+ __export(vanilla_exports, {
1090
+ CalendarEngine: () => CalendarEngine,
1091
+ DAYS: () => DAYS,
1092
+ MONTHS: () => MONTHS,
1093
+ VanillaCalendar: () => VanillaCalendar,
1094
+ createCalendar: () => createCalendar,
1095
+ formatDateForDisplay: () => formatDateForDisplay,
1096
+ generateCalendarDates: () => generateCalendarDates,
1097
+ generateYears: () => generateYears,
1098
+ getCellClasses: () => getCellClasses,
1099
+ getEventsForDate: () => getEventsForDate,
1100
+ getMonthYearText: () => getMonthYearText,
1101
+ getPopupPositionClass: () => getPopupPositionClass,
1102
+ hasEvents: () => hasEvents,
1103
+ isSameDay: () => isSameDay,
1104
+ isToday: () => isToday,
1105
+ normalizeDate: () => normalizeDate
1106
+ });
1107
+
1108
+ // src/vanilla/Calendar.ts
1109
+ var VanillaCalendar = class {
1110
+ constructor(props) {
1111
+ this.unsubscribe = null;
1112
+ this.props = props;
1113
+ if (typeof props.container === "string") {
1114
+ const element = document.querySelector(props.container);
1115
+ if (!element) {
1116
+ throw new Error(`Container element "${props.container}" not found`);
1117
+ }
1118
+ this.container = element;
1119
+ } else {
1120
+ this.container = props.container;
1121
+ }
1122
+ this.engine = new CalendarEngine({
1123
+ events: props.events,
1124
+ initialDate: props.initialDate,
1125
+ minYear: props.minYear,
1126
+ maxYear: props.maxYear,
1127
+ weekStartsOn: props.weekStartsOn
1128
+ });
1129
+ this.actions = this.engine.getActions();
1130
+ this.init();
1131
+ }
1132
+ init() {
1133
+ this.container.classList.add("kalendly-calendar");
1134
+ if (this.props.className) {
1135
+ this.container.classList.add(this.props.className);
1136
+ }
1137
+ this.unsubscribe = this.engine.subscribe(() => {
1138
+ this.render();
1139
+ });
1140
+ this.render();
1141
+ }
1142
+ render() {
1143
+ const viewModel = this.engine.getViewModel();
1144
+ const defaultRenderEvent = (event) => `<li class="event--item">${event.name}</li>`;
1145
+ const defaultRenderNoEvents = () => '<div class="no-events-message">No events scheduled for this day.</div>';
1146
+ const renderEvent = this.props.renderEvent || defaultRenderEvent;
1147
+ const renderNoEvents = this.props.renderNoEvents || defaultRenderNoEvents;
1148
+ const html = `
1149
+ ${this.props.title ? `
1150
+ <div class="page--title">
1151
+ <h1>${this.props.title}</h1>
1152
+ </div>
1153
+ ` : ""}
1154
+
1155
+ <div class="calendar--content">
1156
+ <div class="calendar--card">
1157
+ <h3 class="calendar--card--header">${viewModel.monthAndYearText}</h3>
1158
+
1159
+ <table class="calendar--table calendar--table--bordered">
1160
+ <thead>
1161
+ <tr>
1162
+ ${viewModel.days.map((day) => `<th>${day.slice(0, 3)}</th>`).join("")}
1163
+ </tr>
1164
+ </thead>
1165
+ <tbody data-calendar-body>
1166
+ ${viewModel.calendarDates.map(
1167
+ (week, weekIndex) => `
1168
+ <tr>
1169
+ ${week.map((calendarDate, dayIndex) => {
1170
+ const classes = getCellClasses(calendarDate);
1171
+ const dateString = calendarDate ? calendarDate.date.toISOString() : "";
1172
+ return `
1173
+ <td
1174
+ class="${classes.join(" ")}"
1175
+ data-date="${dateString}"
1176
+ data-day-index="${dayIndex}"
1177
+ ${calendarDate ? 'data-clickable="true"' : ""}
1178
+ >
1179
+ ${calendarDate?.date.getDate() || ""}
1180
+ </td>
1181
+ `;
1182
+ }).join("")}
1183
+ </tr>
1184
+ `
1185
+ ).join("")}
1186
+ </tbody>
1187
+ </table>
1188
+
1189
+ ${viewModel.selectedDate ? `
1190
+ <div class="date-popup ${viewModel.popupPositionClass}">
1191
+ <button type="button" class="popup-close" data-action="close-popup" aria-label="Close">\u2715</button>
1192
+ <div class="schedule--wrapper">
1193
+ <div class="schedule--block">
1194
+ <h2 class="schedule--day">${viewModel.scheduleDay}</h2>
1195
+ </div>
1196
+ ${viewModel.tasks.length > 0 ? `
1197
+ <div class="event--wrapper">
1198
+ <ul>
1199
+ ${viewModel.tasks.map((event) => renderEvent(event)).join("")}
1200
+ </ul>
1201
+ </div>
1202
+ ` : renderNoEvents()}
1203
+ </div>
1204
+ </div>
1205
+ ` : ""}
1206
+
1207
+ <div class="calendar--navigation--buttons">
1208
+ <button class="calendar--navigation--btn" data-action="previous">
1209
+ Previous
1210
+ </button>
1211
+ <button class="calendar--navigation--btn" data-action="next">
1212
+ Next
1213
+ </button>
1214
+ </div>
1215
+
1216
+ <form class="calendar--form--jump">
1217
+ <div class="calendar--lead">Jump To:</div>
1218
+ <div>
1219
+ <label class="calendar--form--jump--item">
1220
+ <select data-month-select>
1221
+ ${viewModel.months.map(
1222
+ (month, index) => `
1223
+ <option value="${index}" ${index === viewModel.currentMonth ? "selected" : ""}>
1224
+ ${month}
1225
+ </option>
1226
+ `
1227
+ ).join("")}
1228
+ </select>
1229
+ </label>
1230
+ </div>
1231
+ <div>
1232
+ <label class="calendar--form--jump--item">
1233
+ <select data-year-select>
1234
+ ${viewModel.years.map(
1235
+ (year) => `
1236
+ <option value="${year}" ${year === viewModel.currentYear ? "selected" : ""}>
1237
+ ${year}
1238
+ </option>
1239
+ `
1240
+ ).join("")}
1241
+ </select>
1242
+ </label>
1243
+ </div>
1244
+ </form>
1245
+ </div>
1246
+ </div>
1247
+ `;
1248
+ this.container.innerHTML = html;
1249
+ this.attachEventListeners();
1250
+ }
1251
+ attachEventListeners() {
1252
+ const tableBody = this.container.querySelector("[data-calendar-body]");
1253
+ if (tableBody) {
1254
+ tableBody.addEventListener("click", (e) => {
1255
+ const target = e.target;
1256
+ const cell = target.closest('td[data-clickable="true"]');
1257
+ if (cell && cell.dataset.date) {
1258
+ const date = new Date(cell.dataset.date);
1259
+ const dayIndex = parseInt(cell.dataset.dayIndex || "0");
1260
+ this.engine.handleDateClick(date, dayIndex);
1261
+ this.container.dispatchEvent(
1262
+ new CustomEvent("dateSelect", {
1263
+ detail: { date, dayIndex }
1264
+ })
1265
+ );
1266
+ }
1267
+ });
1268
+ }
1269
+ const prevBtn = this.container.querySelector('[data-action="previous"]');
1270
+ const nextBtn = this.container.querySelector('[data-action="next"]');
1271
+ if (prevBtn) {
1272
+ prevBtn.addEventListener("click", () => {
1273
+ this.actions.previous();
1274
+ this.container.dispatchEvent(
1275
+ new CustomEvent("monthChange", {
1276
+ detail: {
1277
+ year: this.engine.getViewModel().currentYear,
1278
+ month: this.engine.getViewModel().currentMonth
1279
+ }
1280
+ })
1281
+ );
1282
+ });
1283
+ }
1284
+ if (nextBtn) {
1285
+ nextBtn.addEventListener("click", () => {
1286
+ this.actions.next();
1287
+ this.container.dispatchEvent(
1288
+ new CustomEvent("monthChange", {
1289
+ detail: {
1290
+ year: this.engine.getViewModel().currentYear,
1291
+ month: this.engine.getViewModel().currentMonth
1292
+ }
1293
+ })
1294
+ );
1295
+ });
1296
+ }
1297
+ const monthSelect = this.container.querySelector(
1298
+ "[data-month-select]"
1299
+ );
1300
+ const yearSelect = this.container.querySelector(
1301
+ "[data-year-select]"
1302
+ );
1303
+ if (monthSelect) {
1304
+ monthSelect.addEventListener("change", (e) => {
1305
+ const target = e.target;
1306
+ const month = parseInt(target.value);
1307
+ const year = this.engine.getViewModel().currentYear;
1308
+ this.actions.jump(year, month);
1309
+ this.container.dispatchEvent(
1310
+ new CustomEvent("monthChange", {
1311
+ detail: { year, month }
1312
+ })
1313
+ );
1314
+ });
1315
+ }
1316
+ if (yearSelect) {
1317
+ yearSelect.addEventListener("change", (e) => {
1318
+ const target = e.target;
1319
+ const year = parseInt(target.value);
1320
+ const month = this.engine.getViewModel().currentMonth;
1321
+ this.actions.jump(year, month);
1322
+ this.container.dispatchEvent(
1323
+ new CustomEvent("monthChange", {
1324
+ detail: { year, month }
1325
+ })
1326
+ );
1327
+ });
1328
+ }
1329
+ const closeBtn = this.container.querySelector(
1330
+ '[data-action="close-popup"]'
1331
+ );
1332
+ if (closeBtn) {
1333
+ closeBtn.addEventListener("click", (e) => {
1334
+ e.stopPropagation();
1335
+ this.engine.clearSelection();
1336
+ });
1337
+ }
1338
+ document.addEventListener("click", (e) => {
1339
+ const target = e.target;
1340
+ const popup = this.container.querySelector(".date-popup");
1341
+ if (popup && !popup.contains(target) && !target.closest("[data-calendar-body]")) {
1342
+ this.engine.clearSelection();
1343
+ }
1344
+ });
1345
+ }
1346
+ // Public API methods
1347
+ updateEvents(events) {
1348
+ this.engine.updateEvents(events);
1349
+ }
1350
+ getCurrentDate() {
1351
+ return this.engine.getViewModel().selectedDate;
1352
+ }
1353
+ goToDate(date) {
1354
+ this.actions.jump(date.getFullYear(), date.getMonth());
1355
+ }
1356
+ getEngine() {
1357
+ return this.engine;
1358
+ }
1359
+ destroy() {
1360
+ if (this.unsubscribe) {
1361
+ this.unsubscribe();
1362
+ this.unsubscribe = null;
1363
+ }
1364
+ this.engine.destroy();
1365
+ this.container.innerHTML = "";
1366
+ this.container.classList.remove("kalendly-calendar");
1367
+ if (this.props.className) {
1368
+ this.container.classList.remove(this.props.className);
1369
+ }
1370
+ }
1371
+ };
1372
+ function createCalendar(props) {
1373
+ return new VanillaCalendar(props);
1374
+ }
1375
+
1376
+ // src/index.ts
1377
+ var version = "1.0.0";
1378
+ var name = "kalendly";
1379
+ export {
1380
+ CalendarEngine,
1381
+ DAYS,
1382
+ MONTHS,
1383
+ react_exports as React,
1384
+ Calendar as ReactCalendar,
1385
+ react_native_exports as ReactNative,
1386
+ Calendar2 as ReactNativeCalendar,
1387
+ vanilla_exports as Vanilla,
1388
+ createCalendar as createVanillaCalendar,
1389
+ formatDateForDisplay,
1390
+ generateCalendarDates,
1391
+ generateYears,
1392
+ getCellClasses,
1393
+ getEventsForDate,
1394
+ getMonthYearText,
1395
+ getPopupPositionClass,
1396
+ hasEvents,
1397
+ isSameDay,
1398
+ isToday,
1399
+ name,
1400
+ normalizeDate,
1401
+ version
1402
+ };
1403
+ //# sourceMappingURL=index.mjs.map