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