kalendly 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +260 -21
  2. package/dist/core/index.d.mts +29 -4
  3. package/dist/core/index.d.ts +29 -4
  4. package/dist/core/index.js +63 -7
  5. package/dist/core/index.js.map +1 -1
  6. package/dist/core/index.mjs +62 -7
  7. package/dist/core/index.mjs.map +1 -1
  8. package/dist/index.d.mts +50 -7
  9. package/dist/index.d.ts +50 -7
  10. package/dist/index.js +1030 -298
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +1049 -302
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/react/index.d.mts +30 -4
  15. package/dist/react/index.d.ts +30 -4
  16. package/dist/react/index.js +284 -64
  17. package/dist/react/index.js.map +1 -1
  18. package/dist/react/index.mjs +290 -65
  19. package/dist/react/index.mjs.map +1 -1
  20. package/dist/react-native/index.d.mts +31 -4
  21. package/dist/react-native/index.d.ts +31 -4
  22. package/dist/react-native/index.js +550 -152
  23. package/dist/react-native/index.js.map +1 -1
  24. package/dist/react-native/index.mjs +562 -155
  25. package/dist/react-native/index.mjs.map +1 -1
  26. package/dist/styles/calendar.css +325 -5
  27. package/dist/vanilla/index.d.mts +38 -4
  28. package/dist/vanilla/index.d.ts +38 -4
  29. package/dist/vanilla/index.js +319 -96
  30. package/dist/vanilla/index.js.map +1 -1
  31. package/dist/vanilla/index.mjs +318 -96
  32. package/dist/vanilla/index.mjs.map +1 -1
  33. package/dist/vanilla/index.umd.js +318 -96
  34. package/dist/vanilla/index.umd.js.map +1 -1
  35. package/dist/vue/components/Calendar.vue.d.ts +8 -4
  36. package/dist/vue/components/Calendar.vue.d.ts.map +1 -1
  37. package/dist/vue/index.d.ts +18 -14
  38. package/dist/vue/index.d.ts.map +1 -1
  39. package/dist/vue/index.js +1 -1
  40. package/dist/vue/index.mjs +397 -278
  41. package/dist/vue/types.d.ts +2 -1
  42. package/dist/vue/types.d.ts.map +1 -1
  43. package/package.json +32 -28
  44. package/styles.d.ts +1 -0
package/README.md CHANGED
@@ -1,26 +1,39 @@
1
- # kalendly Universal Calendar Scheduler
1
+ # kalendly Universal Calendar
2
2
 
3
- A universal calendar scheduler component that works seamlessly across React, Vue, and React Native with full TypeScript support.
3
+ A universal calendar component that works seamlessly across React, Vue, and React Native with full TypeScript support.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - 🚀 **Universal**: Works with React, Vue, React Native, and Vanilla JavaScript
8
- - 📱 **Responsive**: Mobile-friendly design that matches your existing Vue implementation
8
+ - 📱 **Responsive**: Mobile-friendly design that matches your existing UI implementation
9
9
  - 🎨 **Customizable**: Easy to theme and customize with CSS variables
10
10
  - 🔒 **Type Safe**: Full TypeScript support
11
11
  - 📅 **Event Management**: Add, display, and manage events with rich metadata
12
12
  - 🔔 **Advanced Features**: Recurring events, reminders, categories, priorities, and collaboration
13
13
  - 🌐 **Accessible**: Built with accessibility in mind
14
14
  - 📦 **Tree Shakeable**: Import only what you need
15
- - 🎯 **Design Consistent**: Matches the original Vue calendar design and feel
16
15
 
17
- ## Live Examples
16
+ ## 🎯 Live Demo
18
17
 
19
- Check out the interactive examples: [https://kalendly-example.netlify.app/](https://kalendly-example.netlify.app)
18
+ <div align="center">
20
19
 
21
- - [Vanilla JavaScript](https://kalendly-example.netlify.app/vanilla)
22
- - [React](https://kalendly-example.netlify.app/react)
23
- - [Vue](https://kalendly-example.netlify.app/vue)
20
+ [![Kalendly Calendar Demo](./docs/images/calendar-demo.png)](https://kalendly-example.netlify.app/)
21
+
22
+ **[🚀 Try the Interactive Demo →](https://kalendly-example.netlify.app/)**
23
+
24
+ </div>
25
+
26
+ <p align="center">
27
+ <a href="https://kalendly-example.netlify.app/vanilla">
28
+ <img src="https://img.shields.io/badge/Vanilla_JS-fc8917?style=for-the-badge&logo=javascript&logoColor=white" alt="Vanilla JS Demo"/>
29
+ </a>
30
+ <a href="https://kalendly-example.netlify.app/react">
31
+ <img src="https://img.shields.io/badge/React-61DAFB?style=for-the-badge&logo=react&logoColor=black" alt="React Demo"/>
32
+ </a>
33
+ <a href="https://kalendly-example.netlify.app/vue">
34
+ <img src="https://img.shields.io/badge/Vue-4FC08D?style=for-the-badge&logo=vue.js&logoColor=white" alt="Vue Demo"/>
35
+ </a>
36
+ </p>
24
37
 
25
38
  ## Installation
26
39
 
@@ -273,17 +286,19 @@ export default App;
273
286
 
274
287
  ### Props
275
288
 
276
- | Prop | Type | Default | Description |
277
- | ---------------- | --------------------------------------- | ------------------ | --------------------------------------- |
278
- | `events` | `CalendarEvent[]` | `[]` | Array of events to display |
279
- | `initialDate` | `Date` | `new Date()` | Initial date to display |
280
- | `minYear` | `number` | `currentYear - 30` | Minimum selectable year |
281
- | `maxYear` | `number` | `currentYear + 10` | Maximum selectable year |
282
- | `weekStartsOn` | `0 \| 1` | `0` | Week start day (0 = Sunday, 1 = Monday) |
283
- | `categoryColors` | `CategoryColorMap` | `{}` | Custom colors for event categories |
284
- | `onDateSelect` | `(date: Date) => void` | - | Callback when date is selected |
285
- | `onEventClick` | `(event: CalendarEvent) => void` | - | Callback when event is clicked |
286
- | `onMonthChange` | `(year: number, month: number) => void` | - | Callback when month changes |
289
+ | Prop | Type | Default | Description |
290
+ | -------------------- | --------------------------------------- | ------------------ | --------------------------------------- |
291
+ | `events` | `CalendarEvent[]` | `[]` | Array of events to display |
292
+ | `initialDate` | `Date` | `new Date()` | Initial date to display |
293
+ | `minYear` | `number` | `currentYear - 30` | Minimum selectable year |
294
+ | `maxYear` | `number` | `currentYear + 10` | Maximum selectable year |
295
+ | `weekStartsOn` | `0 \| 1` | `0` | Week start day (0 = Sunday, 1 = Monday) |
296
+ | `useShortMonthNames` | `boolean` | `false` | Use abbreviated month names (Jan, Feb) |
297
+ | `categoryColors` | `CategoryColorMap` | `{}` | Custom colors for event categories |
298
+ | `theme` | `CalendarTheme` | `undefined` | Custom theme colors for the calendar |
299
+ | `onDateSelect` | `(date: Date) => void` | - | Callback when date is selected |
300
+ | `onEventClick` | `(event: CalendarEvent) => void` | - | Callback when event is clicked |
301
+ | `onMonthChange` | `(year: number, month: number) => void` | - | Callback when month changes |
287
302
 
288
303
  ### CalendarEvent Interface
289
304
 
@@ -397,6 +412,218 @@ const categoryColors = {
397
412
  <Calendar events={events} categoryColors={categoryColors} />
398
413
  ```
399
414
 
415
+ ## Theming
416
+
417
+ Kalendly supports custom theming across all frameworks with a **consistent API**. Customize calendar colors to match your brand or create light/dark themes.
418
+
419
+ ### CalendarTheme Interface
420
+
421
+ ```typescript
422
+ interface CalendarTheme {
423
+ primary?: string; // Primary brand color
424
+ secondary?: string; // Secondary brand color
425
+ tertiary?: string; // Tertiary/accent color
426
+ textColor?: string; // Main text color
427
+ textLight?: string; // Light/secondary text color
428
+ background?: string; // Background color
429
+ cellHover?: string; // Cell hover state color
430
+ borderColor?: string; // Border color
431
+ todayOutline?: string; // Today indicator color
432
+ selectedBg?: string; // Selected date background
433
+ eventIndicator?: string; // Event indicator dot color
434
+ }
435
+ ```
436
+
437
+ ### Basic Theme Example
438
+
439
+ **React:**
440
+
441
+ ```tsx
442
+ import { Calendar } from 'kalendly/react';
443
+ import 'kalendly/styles';
444
+
445
+ function App() {
446
+ return (
447
+ <Calendar
448
+ events={events}
449
+ theme={{
450
+ primary: '#3b82f6',
451
+ secondary: '#60a5fa',
452
+ tertiary: '#93c5fd',
453
+ borderColor: '#e5e7eb',
454
+ todayOutline: '#fbbf24',
455
+ eventIndicator: '#10b981',
456
+ }}
457
+ />
458
+ );
459
+ }
460
+ ```
461
+
462
+ **Vue:**
463
+
464
+ ```vue
465
+ <template>
466
+ <Calendar :events="events" :theme="calendarTheme" />
467
+ </template>
468
+
469
+ <script setup lang="ts">
470
+ import { Calendar } from 'kalendly/vue';
471
+ import 'kalendly/styles';
472
+
473
+ const calendarTheme = {
474
+ primary: '#3b82f6',
475
+ secondary: '#60a5fa',
476
+ tertiary: '#93c5fd',
477
+ borderColor: '#e5e7eb',
478
+ todayOutline: '#fbbf24',
479
+ eventIndicator: '#10b981',
480
+ };
481
+ </script>
482
+ ```
483
+
484
+ **Vanilla JavaScript:**
485
+
486
+ ```javascript
487
+ import { createCalendar } from 'kalendly/vanilla';
488
+ import 'kalendly/styles';
489
+
490
+ const calendar = createCalendar({
491
+ container: '#calendar',
492
+ events: events,
493
+ theme: {
494
+ primary: '#3b82f6',
495
+ secondary: '#60a5fa',
496
+ tertiary: '#93c5fd',
497
+ borderColor: '#e5e7eb',
498
+ todayOutline: '#fbbf24',
499
+ eventIndicator: '#10b981',
500
+ },
501
+ });
502
+ ```
503
+
504
+ **React Native:**
505
+
506
+ ```tsx
507
+ import { Calendar } from 'kalendly/react-native';
508
+
509
+ function App() {
510
+ return (
511
+ <Calendar
512
+ events={events}
513
+ theme={{
514
+ primary: '#3b82f6',
515
+ secondary: '#60a5fa',
516
+ tertiary: '#93c5fd',
517
+ borderColor: '#e5e7eb',
518
+ todayOutline: '#fbbf24',
519
+ eventIndicator: '#10b981',
520
+ }}
521
+ />
522
+ );
523
+ }
524
+ ```
525
+
526
+ ### Dark Theme Example
527
+
528
+ ```typescript
529
+ const darkTheme = {
530
+ primary: '#6366f1',
531
+ secondary: '#818cf8',
532
+ tertiary: '#a5b4fc',
533
+ textColor: '#f9fafb',
534
+ textLight: '#d1d5db',
535
+ background: '#1f2937',
536
+ cellHover: '#374151',
537
+ borderColor: '#4b5563',
538
+ todayOutline: '#fbbf24',
539
+ selectedBg: '#312e81',
540
+ eventIndicator: '#34d399'
541
+ };
542
+
543
+ <Calendar events={events} theme={darkTheme} />
544
+ ```
545
+
546
+ ### Dynamic Theme Switching
547
+
548
+ **React:**
549
+
550
+ ```tsx
551
+ import { useState } from 'react';
552
+ import { Calendar } from 'kalendly/react';
553
+
554
+ const themes = {
555
+ blue: { primary: '#3b82f6', secondary: '#60a5fa' },
556
+ purple: { primary: '#8b5cf6', secondary: '#a78bfa' },
557
+ green: { primary: '#10b981', secondary: '#34d399' },
558
+ };
559
+
560
+ function App() {
561
+ const [currentTheme, setCurrentTheme] = useState('blue');
562
+
563
+ return (
564
+ <>
565
+ <button onClick={() => setCurrentTheme('blue')}>Blue</button>
566
+ <button onClick={() => setCurrentTheme('purple')}>Purple</button>
567
+ <button onClick={() => setCurrentTheme('green')}>Green</button>
568
+
569
+ <Calendar events={events} theme={themes[currentTheme]} />
570
+ </>
571
+ );
572
+ }
573
+ ```
574
+
575
+ **Vue:**
576
+
577
+ ```vue
578
+ <template>
579
+ <div>
580
+ <button @click="currentTheme = 'blue'">Blue</button>
581
+ <button @click="currentTheme = 'purple'">Purple</button>
582
+ <button @click="currentTheme = 'green'">Green</button>
583
+
584
+ <Calendar :events="events" :theme="themes[currentTheme]" />
585
+ </div>
586
+ </template>
587
+
588
+ <script setup lang="ts">
589
+ import { ref } from 'vue';
590
+ import { Calendar } from 'kalendly/vue';
591
+
592
+ const themes = {
593
+ blue: { primary: '#3b82f6', secondary: '#60a5fa' },
594
+ purple: { primary: '#8b5cf6', secondary: '#a78bfa' },
595
+ green: { primary: '#10b981', secondary: '#34d399' },
596
+ };
597
+
598
+ const currentTheme = ref('blue');
599
+ </script>
600
+ ```
601
+
602
+ **Vanilla JavaScript:**
603
+
604
+ ```javascript
605
+ import { createCalendar } from 'kalendly/vanilla';
606
+
607
+ const themes = {
608
+ blue: { primary: '#3b82f6', secondary: '#60a5fa' },
609
+ purple: { primary: '#8b5cf6', secondary: '#a78bfa' },
610
+ green: { primary: '#10b981', secondary: '#34d399' },
611
+ };
612
+
613
+ const calendar = createCalendar({
614
+ container: '#calendar',
615
+ events: events,
616
+ theme: themes.blue,
617
+ });
618
+
619
+ // Update theme dynamically without recreation
620
+ document.getElementById('purple-btn').addEventListener('click', () => {
621
+ calendar.updateTheme(themes.purple);
622
+ });
623
+ ```
624
+
625
+ > **Note:** The `updateTheme()` method is available in Vanilla JavaScript for efficient theme updates without recreating the calendar instance.
626
+
400
627
  ## Framework-Specific Features
401
628
 
402
629
  ### React Props
@@ -508,7 +735,9 @@ Always include the CSS file:
508
735
  ```css
509
736
  :root {
510
737
  --calendar-primary-color: #fc8917;
738
+ --calendar-primary-color-rgb: 252, 137, 23;
511
739
  --calendar-secondary-color: #fca045;
740
+ --calendar-secondary-color-rgb: 252, 160, 69;
512
741
  --calendar-tertiary-color: #fdb873;
513
742
  --calendar-text-color: #2c3e50;
514
743
  --calendar-border-color: #dee2e6;
@@ -518,6 +747,8 @@ Always include the CSS file:
518
747
  }
519
748
  ```
520
749
 
750
+ > **Note:** The `-rgb` variables are used for semi-transparent backgrounds (e.g., hover states) and provide compatibility with older browsers (Chrome < 111, Safari iOS < 16.2).
751
+
521
752
  ### React Native Theming
522
753
 
523
754
  ```javascript
@@ -558,6 +789,10 @@ const actions = engine.getActions();
558
789
  actions.next();
559
790
  actions.previous();
560
791
  actions.jump(2025, 5); // June 2025
792
+ actions.goToToday(); // Navigate to current month
793
+
794
+ // Check current view
795
+ const isCurrentMonth = actions.isCurrentMonth(); // true if viewing today's month
561
796
 
562
797
  // Clean up
563
798
  unsubscribe();
@@ -613,6 +848,10 @@ See [CHANGELOG.md](CHANGELOG.md) for detailed release notes and version history.
613
848
 
614
849
  ### Recent Updates
615
850
 
616
- - **v0.1.2** (Upcoming): Enhanced event parameters with structured metadata, categories, recurrence, collaboration features, and Netlify deployment
851
+ - **v0.1.6** (Upcoming): Navigation enhancements with Today button, month/year picker dropdown, calendar grid improvements showing previous/next month days, and browser compatibility fixes
852
+ - **v0.1.5**: Universal theming system, TypeScript support improvements, integration test enhancements
853
+ - **v0.1.4**: Netlify configuration updates
854
+ - **v0.1.3**: Vue types generation improvements
855
+ - **v0.1.2**: Enhanced event parameters with structured metadata, categories, recurrence, collaboration features
617
856
  - **v0.1.1**: Pre-commit hooks and trusted publishing with OIDC
618
857
  - **v0.1.0**: Initial release with React, Vue, React Native, and Vanilla JavaScript support
@@ -57,6 +57,8 @@ interface CalendarActions {
57
57
  next: () => void;
58
58
  previous: () => void;
59
59
  jump: (year: number, month: number) => void;
60
+ goToToday: () => void;
61
+ isCurrentMonth: () => boolean;
60
62
  selectDate: (date: Date) => void;
61
63
  updateTasks: () => void;
62
64
  }
@@ -70,7 +72,7 @@ interface CalendarViewModel extends CalendarState {
70
72
  years: number[];
71
73
  monthAndYearText: string;
72
74
  scheduleDay: string;
73
- calendarDates: (CalendarDate | null)[][];
75
+ calendarDates: CalendarDate[][];
74
76
  popupPositionClass: string;
75
77
  }
76
78
  type CalendarEventHandler = (event: CalendarEvent) => void;
@@ -80,12 +82,27 @@ interface CalendarProps {
80
82
  minYear?: number;
81
83
  maxYear?: number;
82
84
  weekStartsOn?: 0 | 1;
85
+ useShortMonthNames?: boolean;
83
86
  onDateSelect?: (date: Date) => void;
84
87
  onEventClick?: CalendarEventHandler;
85
88
  onMonthChange?: (year: number, month: number) => void;
86
89
  }
90
+ interface CalendarTheme {
91
+ primary?: string;
92
+ secondary?: string;
93
+ tertiary?: string;
94
+ textColor?: string;
95
+ textLight?: string;
96
+ background?: string;
97
+ cellHover?: string;
98
+ borderColor?: string;
99
+ todayOutline?: string;
100
+ selectedBg?: string;
101
+ eventIndicator?: string;
102
+ }
87
103
 
88
104
  declare const MONTHS: string[];
105
+ declare const MONTHS_FULL: string[];
89
106
  declare const DAYS: string[];
90
107
  declare function normalizeDate(date: Date): Date;
91
108
  declare function isSameDay(date1: Date, date2: Date): boolean;
@@ -93,9 +110,9 @@ declare function isToday(date: Date): boolean;
93
110
  declare function generateYears(minYear?: number, maxYear?: number): number[];
94
111
  declare function getEventsForDate(events: CalendarEvent[], date: Date): CalendarEvent[];
95
112
  declare function hasEvents(events: CalendarEvent[], date: Date): boolean;
96
- declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): (CalendarDate | null)[][];
113
+ declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): CalendarDate[][];
97
114
  declare function getPopupPositionClass(selectedDayIndex: number | null): string;
98
- declare function getCellClasses(calendarDate: CalendarDate | null): string[];
115
+ declare function getCellClasses(calendarDate: CalendarDate): string[];
99
116
  declare function formatDateForDisplay(date: Date): string;
100
117
  declare function getMonthYearText(year: number, month: number): string;
101
118
  declare function formatTimeRange(event: CalendarEvent): string;
@@ -145,6 +162,14 @@ declare class CalendarEngine {
145
162
  * Jump to specific month and year
146
163
  */
147
164
  private jump;
165
+ /**
166
+ * Navigate to current month (today)
167
+ */
168
+ private goToToday;
169
+ /**
170
+ * Check if currently viewing today's month
171
+ */
172
+ private isCurrentMonth;
148
173
  /**
149
174
  * Select a specific date
150
175
  */
@@ -195,4 +220,4 @@ declare class CalendarEngine {
195
220
  destroy(): void;
196
221
  }
197
222
 
198
- export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarProps, type CalendarState, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, type PopupPosition, formatAttendees, formatDateForDisplay, formatTimeRange, generateCalendarDates, generateYears, getCategoryColor, getCellClasses, getDefaultEventColor, getEventsForDate, getMonthYearText, getPopupPositionClass, hasEvents, isSameDay, isToday, isValidHexColor, mergeCategoryColors, normalizeDate, sortEventsByTime };
223
+ export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarProps, type CalendarState, type CalendarTheme, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, MONTHS_FULL, type PopupPosition, formatAttendees, formatDateForDisplay, formatTimeRange, generateCalendarDates, generateYears, getCategoryColor, getCellClasses, getDefaultEventColor, getEventsForDate, getMonthYearText, getPopupPositionClass, hasEvents, isSameDay, isToday, isValidHexColor, mergeCategoryColors, normalizeDate, sortEventsByTime };
@@ -57,6 +57,8 @@ interface CalendarActions {
57
57
  next: () => void;
58
58
  previous: () => void;
59
59
  jump: (year: number, month: number) => void;
60
+ goToToday: () => void;
61
+ isCurrentMonth: () => boolean;
60
62
  selectDate: (date: Date) => void;
61
63
  updateTasks: () => void;
62
64
  }
@@ -70,7 +72,7 @@ interface CalendarViewModel extends CalendarState {
70
72
  years: number[];
71
73
  monthAndYearText: string;
72
74
  scheduleDay: string;
73
- calendarDates: (CalendarDate | null)[][];
75
+ calendarDates: CalendarDate[][];
74
76
  popupPositionClass: string;
75
77
  }
76
78
  type CalendarEventHandler = (event: CalendarEvent) => void;
@@ -80,12 +82,27 @@ interface CalendarProps {
80
82
  minYear?: number;
81
83
  maxYear?: number;
82
84
  weekStartsOn?: 0 | 1;
85
+ useShortMonthNames?: boolean;
83
86
  onDateSelect?: (date: Date) => void;
84
87
  onEventClick?: CalendarEventHandler;
85
88
  onMonthChange?: (year: number, month: number) => void;
86
89
  }
90
+ interface CalendarTheme {
91
+ primary?: string;
92
+ secondary?: string;
93
+ tertiary?: string;
94
+ textColor?: string;
95
+ textLight?: string;
96
+ background?: string;
97
+ cellHover?: string;
98
+ borderColor?: string;
99
+ todayOutline?: string;
100
+ selectedBg?: string;
101
+ eventIndicator?: string;
102
+ }
87
103
 
88
104
  declare const MONTHS: string[];
105
+ declare const MONTHS_FULL: string[];
89
106
  declare const DAYS: string[];
90
107
  declare function normalizeDate(date: Date): Date;
91
108
  declare function isSameDay(date1: Date, date2: Date): boolean;
@@ -93,9 +110,9 @@ declare function isToday(date: Date): boolean;
93
110
  declare function generateYears(minYear?: number, maxYear?: number): number[];
94
111
  declare function getEventsForDate(events: CalendarEvent[], date: Date): CalendarEvent[];
95
112
  declare function hasEvents(events: CalendarEvent[], date: Date): boolean;
96
- declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): (CalendarDate | null)[][];
113
+ declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): CalendarDate[][];
97
114
  declare function getPopupPositionClass(selectedDayIndex: number | null): string;
98
- declare function getCellClasses(calendarDate: CalendarDate | null): string[];
115
+ declare function getCellClasses(calendarDate: CalendarDate): string[];
99
116
  declare function formatDateForDisplay(date: Date): string;
100
117
  declare function getMonthYearText(year: number, month: number): string;
101
118
  declare function formatTimeRange(event: CalendarEvent): string;
@@ -145,6 +162,14 @@ declare class CalendarEngine {
145
162
  * Jump to specific month and year
146
163
  */
147
164
  private jump;
165
+ /**
166
+ * Navigate to current month (today)
167
+ */
168
+ private goToToday;
169
+ /**
170
+ * Check if currently viewing today's month
171
+ */
172
+ private isCurrentMonth;
148
173
  /**
149
174
  * Select a specific date
150
175
  */
@@ -195,4 +220,4 @@ declare class CalendarEngine {
195
220
  destroy(): void;
196
221
  }
197
222
 
198
- export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarProps, type CalendarState, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, type PopupPosition, formatAttendees, formatDateForDisplay, formatTimeRange, generateCalendarDates, generateYears, getCategoryColor, getCellClasses, getDefaultEventColor, getEventsForDate, getMonthYearText, getPopupPositionClass, hasEvents, isSameDay, isToday, isValidHexColor, mergeCategoryColors, normalizeDate, sortEventsByTime };
223
+ export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarProps, type CalendarState, type CalendarTheme, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, MONTHS_FULL, type PopupPosition, formatAttendees, formatDateForDisplay, formatTimeRange, generateCalendarDates, generateYears, getCategoryColor, getCellClasses, getDefaultEventColor, getEventsForDate, getMonthYearText, getPopupPositionClass, hasEvents, isSameDay, isToday, isValidHexColor, mergeCategoryColors, normalizeDate, sortEventsByTime };
@@ -24,6 +24,7 @@ __export(index_exports, {
24
24
  DAYS: () => DAYS,
25
25
  DEFAULT_CATEGORY_COLORS: () => DEFAULT_CATEGORY_COLORS,
26
26
  MONTHS: () => MONTHS,
27
+ MONTHS_FULL: () => MONTHS_FULL,
27
28
  formatAttendees: () => formatAttendees,
28
29
  formatDateForDisplay: () => formatDateForDisplay,
29
30
  formatTimeRange: () => formatTimeRange,
@@ -60,6 +61,20 @@ var MONTHS = [
60
61
  "Nov",
61
62
  "Dec"
62
63
  ];
64
+ var MONTHS_FULL = [
65
+ "January",
66
+ "February",
67
+ "March",
68
+ "April",
69
+ "May",
70
+ "June",
71
+ "July",
72
+ "August",
73
+ "September",
74
+ "October",
75
+ "November",
76
+ "December"
77
+ ];
63
78
  var DAYS = [
64
79
  "Sunday",
65
80
  "Monday",
@@ -98,19 +113,39 @@ function generateCalendarDates(year, month, events = [], weekStartsOn = 0) {
98
113
  const firstDay = new Date(year, month, 1);
99
114
  const lastDay = new Date(year, month + 1, 0);
100
115
  const daysInMonth = lastDay.getDate();
116
+ const prevMonthLastDay = new Date(year, month, 0).getDate();
101
117
  let firstDayOfWeek = firstDay.getDay();
102
118
  if (weekStartsOn === 1) {
103
119
  firstDayOfWeek = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;
104
120
  }
105
121
  const dates = [];
106
122
  let day = 1;
123
+ let nextMonthDay = 1;
107
124
  for (let week = 0; week < 6; week++) {
108
125
  const weekDates = [];
109
126
  for (let dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
110
127
  if (week === 0 && dayOfWeek < firstDayOfWeek) {
111
- weekDates.push(null);
128
+ const prevDay = prevMonthLastDay - firstDayOfWeek + dayOfWeek + 1;
129
+ const prevDate = new Date(year, month - 1, prevDay);
130
+ const dateEvents = getEventsForDate(events, prevDate);
131
+ weekDates.push({
132
+ date: prevDate,
133
+ isCurrentMonth: false,
134
+ isToday: isToday(prevDate),
135
+ hasEvents: dateEvents.length > 0,
136
+ events: dateEvents
137
+ });
112
138
  } else if (day > daysInMonth) {
113
- weekDates.push(null);
139
+ const nextDate = new Date(year, month + 1, nextMonthDay);
140
+ const dateEvents = getEventsForDate(events, nextDate);
141
+ weekDates.push({
142
+ date: nextDate,
143
+ isCurrentMonth: false,
144
+ isToday: isToday(nextDate),
145
+ hasEvents: dateEvents.length > 0,
146
+ events: dateEvents
147
+ });
148
+ nextMonthDay++;
114
149
  } else {
115
150
  const currentDate = new Date(year, month, day);
116
151
  const dateEvents = getEventsForDate(events, currentDate);
@@ -125,9 +160,6 @@ function generateCalendarDates(year, month, events = [], weekStartsOn = 0) {
125
160
  }
126
161
  }
127
162
  dates.push(weekDates);
128
- if (day > daysInMonth && weekDates.every((date) => date === null)) {
129
- break;
130
- }
131
163
  }
132
164
  return dates;
133
165
  }
@@ -142,8 +174,10 @@ function getPopupPositionClass(selectedDayIndex) {
142
174
  }
143
175
  }
144
176
  function getCellClasses(calendarDate) {
145
- if (!calendarDate) return [];
146
177
  const classes = [];
178
+ if (!calendarDate.isCurrentMonth) {
179
+ classes.push("other-month");
180
+ }
147
181
  if (calendarDate.isToday) {
148
182
  classes.push("schedule--current--exam");
149
183
  }
@@ -156,7 +190,7 @@ function formatDateForDisplay(date) {
156
190
  return `${DAYS[date.getDay()]} ${date.getDate()}`;
157
191
  }
158
192
  function getMonthYearText(year, month) {
159
- return `${MONTHS[month]} ${year}`;
193
+ return `${MONTHS_FULL[month]} ${year}`;
160
194
  }
161
195
  function formatTimeRange(event) {
162
196
  if (event.allDay || !event.startTime && !event.endTime) {
@@ -283,6 +317,8 @@ var CalendarEngine = class {
283
317
  next: this.next.bind(this),
284
318
  previous: this.previous.bind(this),
285
319
  jump: this.jump.bind(this),
320
+ goToToday: this.goToToday.bind(this),
321
+ isCurrentMonth: this.isCurrentMonth.bind(this),
286
322
  selectDate: this.selectDate.bind(this),
287
323
  updateTasks: this.updateTasks.bind(this)
288
324
  };
@@ -328,6 +364,25 @@ var CalendarEngine = class {
328
364
  this.updateTasks();
329
365
  this.notify();
330
366
  }
367
+ /**
368
+ * Navigate to current month (today)
369
+ */
370
+ goToToday() {
371
+ const today = /* @__PURE__ */ new Date();
372
+ this.state.currentYear = today.getFullYear();
373
+ this.state.currentMonth = today.getMonth();
374
+ this.state.selectedDate = null;
375
+ this.state.selectedDayIndex = null;
376
+ this.updateTasks();
377
+ this.notify();
378
+ }
379
+ /**
380
+ * Check if currently viewing today's month
381
+ */
382
+ isCurrentMonth() {
383
+ const today = /* @__PURE__ */ new Date();
384
+ return this.state.currentYear === today.getFullYear() && this.state.currentMonth === today.getMonth();
385
+ }
331
386
  /**
332
387
  * Select a specific date
333
388
  */
@@ -428,6 +483,7 @@ var CalendarEngine = class {
428
483
  DAYS,
429
484
  DEFAULT_CATEGORY_COLORS,
430
485
  MONTHS,
486
+ MONTHS_FULL,
431
487
  formatAttendees,
432
488
  formatDateForDisplay,
433
489
  formatTimeRange,