kalendly 0.1.5 → 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.
- package/README.md +29 -17
- package/dist/core/index.d.mts +16 -4
- package/dist/core/index.d.ts +16 -4
- package/dist/core/index.js +63 -7
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +62 -7
- package/dist/core/index.mjs.map +1 -1
- package/dist/index.d.mts +28 -7
- package/dist/index.d.ts +28 -7
- package/dist/index.js +929 -280
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +942 -285
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +16 -4
- package/dist/react/index.d.ts +16 -4
- package/dist/react/index.js +253 -64
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +259 -65
- package/dist/react/index.mjs.map +1 -1
- package/dist/react-native/index.d.mts +17 -4
- package/dist/react-native/index.d.ts +17 -4
- package/dist/react-native/index.js +516 -134
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native/index.mjs +522 -138
- package/dist/react-native/index.mjs.map +1 -1
- package/dist/styles/calendar.css +319 -11
- package/dist/vanilla/index.d.mts +21 -4
- package/dist/vanilla/index.d.ts +21 -4
- package/dist/vanilla/index.js +283 -96
- package/dist/vanilla/index.js.map +1 -1
- package/dist/vanilla/index.mjs +282 -96
- package/dist/vanilla/index.mjs.map +1 -1
- package/dist/vanilla/index.umd.js +282 -96
- package/dist/vanilla/index.umd.js.map +1 -1
- package/dist/vue/components/Calendar.vue.d.ts +8 -4
- package/dist/vue/components/Calendar.vue.d.ts.map +1 -1
- package/dist/vue/index.d.ts +18 -14
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/index.js +1 -1
- package/dist/vue/index.mjs +410 -310
- package/package.json +27 -27
package/README.md
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
# kalendly Universal Calendar
|
|
1
|
+
# kalendly Universal Calendar
|
|
2
2
|
|
|
3
|
-
A universal calendar
|
|
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
|
|
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
16
|
## 🎯 Live Demo
|
|
18
17
|
|
|
@@ -287,18 +286,19 @@ export default App;
|
|
|
287
286
|
|
|
288
287
|
### Props
|
|
289
288
|
|
|
290
|
-
| Prop
|
|
291
|
-
|
|
|
292
|
-
| `events`
|
|
293
|
-
| `initialDate`
|
|
294
|
-
| `minYear`
|
|
295
|
-
| `maxYear`
|
|
296
|
-
| `weekStartsOn`
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
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 |
|
|
302
302
|
|
|
303
303
|
### CalendarEvent Interface
|
|
304
304
|
|
|
@@ -735,7 +735,9 @@ Always include the CSS file:
|
|
|
735
735
|
```css
|
|
736
736
|
:root {
|
|
737
737
|
--calendar-primary-color: #fc8917;
|
|
738
|
+
--calendar-primary-color-rgb: 252, 137, 23;
|
|
738
739
|
--calendar-secondary-color: #fca045;
|
|
740
|
+
--calendar-secondary-color-rgb: 252, 160, 69;
|
|
739
741
|
--calendar-tertiary-color: #fdb873;
|
|
740
742
|
--calendar-text-color: #2c3e50;
|
|
741
743
|
--calendar-border-color: #dee2e6;
|
|
@@ -745,6 +747,8 @@ Always include the CSS file:
|
|
|
745
747
|
}
|
|
746
748
|
```
|
|
747
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
|
+
|
|
748
752
|
### React Native Theming
|
|
749
753
|
|
|
750
754
|
```javascript
|
|
@@ -785,6 +789,10 @@ const actions = engine.getActions();
|
|
|
785
789
|
actions.next();
|
|
786
790
|
actions.previous();
|
|
787
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
|
|
788
796
|
|
|
789
797
|
// Clean up
|
|
790
798
|
unsubscribe();
|
|
@@ -840,6 +848,10 @@ See [CHANGELOG.md](CHANGELOG.md) for detailed release notes and version history.
|
|
|
840
848
|
|
|
841
849
|
### Recent Updates
|
|
842
850
|
|
|
843
|
-
- **v0.1.
|
|
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
|
|
844
856
|
- **v0.1.1**: Pre-commit hooks and trusted publishing with OIDC
|
|
845
857
|
- **v0.1.0**: Initial release with React, Vue, React Native, and Vanilla JavaScript support
|
package/dist/core/index.d.mts
CHANGED
|
@@ -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:
|
|
75
|
+
calendarDates: CalendarDate[][];
|
|
74
76
|
popupPositionClass: string;
|
|
75
77
|
}
|
|
76
78
|
type CalendarEventHandler = (event: CalendarEvent) => void;
|
|
@@ -80,6 +82,7 @@ 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;
|
|
@@ -99,6 +102,7 @@ interface CalendarTheme {
|
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
declare const MONTHS: string[];
|
|
105
|
+
declare const MONTHS_FULL: string[];
|
|
102
106
|
declare const DAYS: string[];
|
|
103
107
|
declare function normalizeDate(date: Date): Date;
|
|
104
108
|
declare function isSameDay(date1: Date, date2: Date): boolean;
|
|
@@ -106,9 +110,9 @@ declare function isToday(date: Date): boolean;
|
|
|
106
110
|
declare function generateYears(minYear?: number, maxYear?: number): number[];
|
|
107
111
|
declare function getEventsForDate(events: CalendarEvent[], date: Date): CalendarEvent[];
|
|
108
112
|
declare function hasEvents(events: CalendarEvent[], date: Date): boolean;
|
|
109
|
-
declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1):
|
|
113
|
+
declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): CalendarDate[][];
|
|
110
114
|
declare function getPopupPositionClass(selectedDayIndex: number | null): string;
|
|
111
|
-
declare function getCellClasses(calendarDate: CalendarDate
|
|
115
|
+
declare function getCellClasses(calendarDate: CalendarDate): string[];
|
|
112
116
|
declare function formatDateForDisplay(date: Date): string;
|
|
113
117
|
declare function getMonthYearText(year: number, month: number): string;
|
|
114
118
|
declare function formatTimeRange(event: CalendarEvent): string;
|
|
@@ -158,6 +162,14 @@ declare class CalendarEngine {
|
|
|
158
162
|
* Jump to specific month and year
|
|
159
163
|
*/
|
|
160
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;
|
|
161
173
|
/**
|
|
162
174
|
* Select a specific date
|
|
163
175
|
*/
|
|
@@ -208,4 +220,4 @@ declare class CalendarEngine {
|
|
|
208
220
|
destroy(): void;
|
|
209
221
|
}
|
|
210
222
|
|
|
211
|
-
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, 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 };
|
package/dist/core/index.d.ts
CHANGED
|
@@ -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:
|
|
75
|
+
calendarDates: CalendarDate[][];
|
|
74
76
|
popupPositionClass: string;
|
|
75
77
|
}
|
|
76
78
|
type CalendarEventHandler = (event: CalendarEvent) => void;
|
|
@@ -80,6 +82,7 @@ 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;
|
|
@@ -99,6 +102,7 @@ interface CalendarTheme {
|
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
declare const MONTHS: string[];
|
|
105
|
+
declare const MONTHS_FULL: string[];
|
|
102
106
|
declare const DAYS: string[];
|
|
103
107
|
declare function normalizeDate(date: Date): Date;
|
|
104
108
|
declare function isSameDay(date1: Date, date2: Date): boolean;
|
|
@@ -106,9 +110,9 @@ declare function isToday(date: Date): boolean;
|
|
|
106
110
|
declare function generateYears(minYear?: number, maxYear?: number): number[];
|
|
107
111
|
declare function getEventsForDate(events: CalendarEvent[], date: Date): CalendarEvent[];
|
|
108
112
|
declare function hasEvents(events: CalendarEvent[], date: Date): boolean;
|
|
109
|
-
declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1):
|
|
113
|
+
declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): CalendarDate[][];
|
|
110
114
|
declare function getPopupPositionClass(selectedDayIndex: number | null): string;
|
|
111
|
-
declare function getCellClasses(calendarDate: CalendarDate
|
|
115
|
+
declare function getCellClasses(calendarDate: CalendarDate): string[];
|
|
112
116
|
declare function formatDateForDisplay(date: Date): string;
|
|
113
117
|
declare function getMonthYearText(year: number, month: number): string;
|
|
114
118
|
declare function formatTimeRange(event: CalendarEvent): string;
|
|
@@ -158,6 +162,14 @@ declare class CalendarEngine {
|
|
|
158
162
|
* Jump to specific month and year
|
|
159
163
|
*/
|
|
160
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;
|
|
161
173
|
/**
|
|
162
174
|
* Select a specific date
|
|
163
175
|
*/
|
|
@@ -208,4 +220,4 @@ declare class CalendarEngine {
|
|
|
208
220
|
destroy(): void;
|
|
209
221
|
}
|
|
210
222
|
|
|
211
|
-
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, 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 };
|
package/dist/core/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 `${
|
|
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,
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/index.ts","../../src/core/utils.ts","../../src/core/calendar-engine.ts"],"sourcesContent":["export * from './types';\nexport * from './utils';\nexport { CalendarEngine } from './calendar-engine';\n\n// Re-export commonly used utilities\nexport {\n MONTHS,\n DAYS,\n normalizeDate,\n isSameDay,\n isToday,\n generateYears,\n getEventsForDate,\n hasEvents,\n generateCalendarDates,\n getPopupPositionClass,\n getCellClasses,\n formatDateForDisplay,\n getMonthYearText,\n} from './utils';\n","import { CalendarEvent, CalendarDate, CategoryColorMap } from './types';\n\nexport const MONTHS = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n];\n\nexport const DAYS = [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n];\n\nexport function normalizeDate(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);\n}\n\nexport function isSameDay(date1: Date, date2: Date): boolean {\n return normalizeDate(date1).getTime() === normalizeDate(date2).getTime();\n}\n\nexport function isToday(date: Date): boolean {\n return isSameDay(date, new Date());\n}\n\nexport function generateYears(minYear?: number, maxYear?: number): number[] {\n const currentYear = new Date().getFullYear();\n const min = minYear ?? currentYear - 30;\n const max = maxYear ?? currentYear + 10;\n\n return Array.from({ length: max - min + 1 }, (_, i) => min + i);\n}\n\nexport function getEventsForDate(\n events: CalendarEvent[],\n date: Date\n): CalendarEvent[] {\n const normalizedTargetDate = normalizeDate(date);\n\n return events.filter(event => {\n const eventDate = normalizeDate(new Date(event.date));\n return eventDate.getTime() === normalizedTargetDate.getTime();\n });\n}\n\nexport function hasEvents(events: CalendarEvent[], date: Date): boolean {\n return getEventsForDate(events, date).length > 0;\n}\n\nexport function generateCalendarDates(\n year: number,\n month: number,\n events: CalendarEvent[] = [],\n weekStartsOn: 0 | 1 = 0\n): (CalendarDate | null)[][] {\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n const daysInMonth = lastDay.getDate();\n\n let firstDayOfWeek = firstDay.getDay();\n if (weekStartsOn === 1) {\n firstDayOfWeek = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;\n }\n\n const dates: (CalendarDate | null)[][] = [];\n let day = 1;\n\n for (let week = 0; week < 6; week++) {\n const weekDates: (CalendarDate | null)[] = [];\n\n for (let dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {\n if (week === 0 && dayOfWeek < firstDayOfWeek) {\n weekDates.push(null);\n } else if (day > daysInMonth) {\n weekDates.push(null);\n } else {\n const currentDate = new Date(year, month, day);\n const dateEvents = getEventsForDate(events, currentDate);\n\n weekDates.push({\n date: currentDate,\n isCurrentMonth: true,\n isToday: isToday(currentDate),\n hasEvents: dateEvents.length > 0,\n events: dateEvents,\n });\n day++;\n }\n }\n\n dates.push(weekDates);\n\n if (day > daysInMonth && weekDates.every(date => date === null)) {\n break;\n }\n }\n\n return dates;\n}\n\nexport function getPopupPositionClass(selectedDayIndex: number | null): string {\n if (selectedDayIndex === null) return 'popup-center-bottom';\n\n if (selectedDayIndex < 3) {\n return 'popup-right';\n } else if (selectedDayIndex > 4) {\n return 'popup-left';\n } else {\n return 'popup-center-bottom';\n }\n}\n\nexport function getCellClasses(calendarDate: CalendarDate | null): string[] {\n if (!calendarDate) return [];\n\n const classes: string[] = [];\n\n if (calendarDate.isToday) {\n classes.push('schedule--current--exam');\n }\n\n if (calendarDate.hasEvents) {\n classes.push('has--event');\n }\n\n return classes;\n}\n\nexport function formatDateForDisplay(date: Date): string {\n return `${DAYS[date.getDay()]} ${date.getDate()}`;\n}\n\nexport function getMonthYearText(year: number, month: number): string {\n return `${MONTHS[month]} ${year}`;\n}\n\nexport function formatTimeRange(event: CalendarEvent): string {\n if (event.allDay || (!event.startTime && !event.endTime)) {\n return 'All day';\n }\n\n if (event.startTime && event.endTime) {\n return `${event.startTime} - ${event.endTime}`;\n }\n\n if (event.startTime) {\n return `${event.startTime}`;\n }\n\n return '';\n}\n\nexport function formatAttendees(attendees?: string[]): string {\n if (!attendees || attendees.length === 0) return '';\n\n if (attendees.length === 1) return attendees[0];\n if (attendees.length === 2) return attendees.join(' and ');\n\n return `${attendees.slice(0, -1).join(', ')}, and ${attendees[attendees.length - 1]}`;\n}\n\nexport function sortEventsByTime(events: CalendarEvent[]): CalendarEvent[] {\n return [...events].sort((a, b) => {\n const aAllDay = a.allDay || (!a.startTime && !a.endTime);\n const bAllDay = b.allDay || (!b.startTime && !b.endTime);\n\n if (aAllDay && !bAllDay) return -1;\n if (!aAllDay && bAllDay) return 1;\n\n if (!a.startTime || !b.startTime) return 0;\n return a.startTime.localeCompare(b.startTime);\n });\n}\n\nexport const DEFAULT_CATEGORY_COLORS: CategoryColorMap = {\n work: '#3b82f6',\n personal: '#8b5cf6',\n meeting: '#10b981',\n deadline: '#ef4444',\n appointment: '#f59e0b',\n other: '#6b7280',\n};\n\n// Dynamic function that accepts custom colors\nexport function getDefaultEventColor(\n category?: string,\n customColors?: CategoryColorMap\n): string {\n const colorMap = customColors || DEFAULT_CATEGORY_COLORS;\n\n if (category && colorMap[category]) {\n return colorMap[category];\n }\n\n // Default fallback color\n return '#fc8917';\n}\n\n// Helper to merge custom colors with defaults\nexport function mergeCategoryColors(\n customColors?: CategoryColorMap\n): CategoryColorMap {\n return {\n ...DEFAULT_CATEGORY_COLORS,\n ...customColors,\n };\n}\n\n// Validate if a color is a valid hex color\nexport function isValidHexColor(color: string): boolean {\n return /^#([0-9A-F]{3}){1,2}$/i.test(color);\n}\n\n// Get color for a category with validation\nexport function getCategoryColor(\n category: string,\n customColors?: CategoryColorMap\n): string {\n const colorMap = mergeCategoryColors(customColors);\n const color = colorMap[category] || colorMap.other || '#fc8917';\n\n return isValidHexColor(color) ? color : '#fc8917';\n}\n","import {\n CalendarEvent,\n CalendarState,\n CalendarConfig,\n CalendarActions,\n CalendarViewModel,\n CategoryColorMap,\n} from './types';\nimport {\n generateCalendarDates,\n getEventsForDate,\n generateYears,\n getPopupPositionClass,\n getMonthYearText,\n formatDateForDisplay,\n mergeCategoryColors,\n getCategoryColor,\n MONTHS,\n DAYS,\n} from './utils';\n\nexport class CalendarEngine {\n private state: CalendarState;\n private config: CalendarConfig;\n private listeners: Set<() => void> = new Set();\n private categoryColors: CategoryColorMap;\n\n constructor(config: CalendarConfig) {\n this.config = config;\n this.categoryColors = mergeCategoryColors(config.categoryColors);\n\n const initialDate = config.initialDate || new Date();\n this.state = {\n currentYear: initialDate.getFullYear(),\n currentMonth: initialDate.getMonth(),\n currentDate: initialDate.getDate(),\n selectedDate: null,\n selectedDayIndex: null,\n tasks: [],\n };\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Notify all listeners of state changes\n */\n private notify(): void {\n this.listeners.forEach(listener => listener());\n }\n\n /**\n * Get current state\n */\n getState(): CalendarState {\n return { ...this.state };\n }\n\n /**\n * Get view model with computed properties\n */\n getViewModel(): CalendarViewModel {\n const calendarDates = generateCalendarDates(\n this.state.currentYear,\n this.state.currentMonth,\n this.config.events,\n this.config.weekStartsOn\n );\n\n return {\n ...this.state,\n months: MONTHS,\n days: DAYS,\n years: generateYears(this.config.minYear, this.config.maxYear),\n monthAndYearText: getMonthYearText(\n this.state.currentYear,\n this.state.currentMonth\n ),\n scheduleDay: this.state.selectedDate\n ? formatDateForDisplay(this.state.selectedDate)\n : '',\n calendarDates,\n popupPositionClass: getPopupPositionClass(this.state.selectedDayIndex),\n };\n }\n\n /**\n * Get actions object\n */\n getActions(): CalendarActions {\n return {\n next: this.next.bind(this),\n previous: this.previous.bind(this),\n jump: this.jump.bind(this),\n selectDate: this.selectDate.bind(this),\n updateTasks: this.updateTasks.bind(this),\n };\n }\n\n /**\n * Navigate to next month\n */\n private next(): void {\n if (this.state.currentMonth === 11) {\n this.state.currentMonth = 0;\n this.state.currentYear++;\n } else {\n this.state.currentMonth++;\n }\n\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Navigate to previous month\n */\n private previous(): void {\n if (this.state.currentMonth === 0) {\n this.state.currentMonth = 11;\n this.state.currentYear--;\n } else {\n this.state.currentMonth--;\n }\n\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Jump to specific month and year\n */\n private jump(year: number, month: number): void {\n this.state.currentYear = year;\n this.state.currentMonth = month;\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Select a specific date\n */\n private selectDate(date: Date, dayIndex?: number): void {\n this.state.selectedDate = date;\n this.state.selectedDayIndex = dayIndex ?? null;\n this.state.currentDate = date.getDate();\n this.state.currentMonth = date.getMonth();\n this.state.currentYear = date.getFullYear();\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Update tasks for the currently selected date\n */\n private updateTasks(): void {\n if (!this.state.selectedDate) {\n this.state.tasks = [];\n return;\n }\n\n this.state.tasks = getEventsForDate(\n this.config.events,\n this.state.selectedDate\n );\n }\n\n /**\n * Update events configuration\n */\n updateEvents(events: CalendarEvent[]): void {\n this.config.events = events;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Handle date cell click\n */\n handleDateClick(date: Date, dayIndex?: number): void {\n this.selectDate(date, dayIndex);\n }\n\n /**\n * Check if date has events\n */\n hasEventsForDate(date: Date): boolean {\n return getEventsForDate(this.config.events, date).length > 0;\n }\n\n /**\n * Get events for a specific date\n */\n getEventsForDate(date: Date): CalendarEvent[] {\n return getEventsForDate(this.config.events, date);\n }\n\n /**\n * Clear selected date\n */\n clearSelection(): void {\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.state.tasks = [];\n this.notify();\n }\n\n /**\n * Get category color (with custom colors support)\n */\n getCategoryColor(category?: string): string {\n if (!category) return '#fc8917';\n return getCategoryColor(category, this.categoryColors);\n }\n\n /**\n * Update category colors dynamically\n */\n updateCategoryColors(colors: CategoryColorMap): void {\n this.categoryColors = mergeCategoryColors(colors);\n this.notify();\n }\n\n /**\n * Get all category colors\n */\n getCategoryColors(): CategoryColorMap {\n return { ...this.categoryColors };\n }\n\n /**\n * Register a new category with color\n */\n registerCategory(name: string, color: string): void {\n this.categoryColors[name] = color;\n this.notify();\n }\n\n /**\n * Destroy the engine and cleanup listeners\n */\n destroy(): void {\n this.listeners.clear();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/index.ts","../../src/core/utils.ts","../../src/core/calendar-engine.ts"],"sourcesContent":["export * from './types';\nexport * from './utils';\nexport { CalendarEngine } from './calendar-engine';\n\n// Re-export commonly used utilities\nexport {\n MONTHS,\n MONTHS_FULL,\n DAYS,\n normalizeDate,\n isSameDay,\n isToday,\n generateYears,\n getEventsForDate,\n hasEvents,\n generateCalendarDates,\n getPopupPositionClass,\n getCellClasses,\n formatDateForDisplay,\n getMonthYearText,\n} from './utils';\n","import { CalendarEvent, CalendarDate, CategoryColorMap } from './types';\n\nexport const MONTHS = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n];\n\nexport const MONTHS_FULL = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n];\n\nexport const DAYS = [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n];\n\nexport function normalizeDate(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);\n}\n\nexport function isSameDay(date1: Date, date2: Date): boolean {\n return normalizeDate(date1).getTime() === normalizeDate(date2).getTime();\n}\n\nexport function isToday(date: Date): boolean {\n return isSameDay(date, new Date());\n}\n\nexport function generateYears(minYear?: number, maxYear?: number): number[] {\n const currentYear = new Date().getFullYear();\n const min = minYear ?? currentYear - 30;\n const max = maxYear ?? currentYear + 10;\n\n return Array.from({ length: max - min + 1 }, (_, i) => min + i);\n}\n\nexport function getEventsForDate(\n events: CalendarEvent[],\n date: Date\n): CalendarEvent[] {\n const normalizedTargetDate = normalizeDate(date);\n\n return events.filter(event => {\n const eventDate = normalizeDate(new Date(event.date));\n return eventDate.getTime() === normalizedTargetDate.getTime();\n });\n}\n\nexport function hasEvents(events: CalendarEvent[], date: Date): boolean {\n return getEventsForDate(events, date).length > 0;\n}\n\nexport function generateCalendarDates(\n year: number,\n month: number,\n events: CalendarEvent[] = [],\n weekStartsOn: 0 | 1 = 0\n): CalendarDate[][] {\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n const daysInMonth = lastDay.getDate();\n const prevMonthLastDay = new Date(year, month, 0).getDate();\n\n let firstDayOfWeek = firstDay.getDay();\n if (weekStartsOn === 1) {\n firstDayOfWeek = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;\n }\n\n const dates: CalendarDate[][] = [];\n let day = 1;\n let nextMonthDay = 1;\n\n for (let week = 0; week < 6; week++) {\n const weekDates: CalendarDate[] = [];\n\n for (let dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {\n if (week === 0 && dayOfWeek < firstDayOfWeek) {\n // Previous month days\n const prevDay = prevMonthLastDay - firstDayOfWeek + dayOfWeek + 1;\n const prevDate = new Date(year, month - 1, prevDay);\n const dateEvents = getEventsForDate(events, prevDate);\n weekDates.push({\n date: prevDate,\n isCurrentMonth: false,\n isToday: isToday(prevDate),\n hasEvents: dateEvents.length > 0,\n events: dateEvents,\n });\n } else if (day > daysInMonth) {\n // Next month days\n const nextDate = new Date(year, month + 1, nextMonthDay);\n const dateEvents = getEventsForDate(events, nextDate);\n weekDates.push({\n date: nextDate,\n isCurrentMonth: false,\n isToday: isToday(nextDate),\n hasEvents: dateEvents.length > 0,\n events: dateEvents,\n });\n nextMonthDay++;\n } else {\n // Current month days\n const currentDate = new Date(year, month, day);\n const dateEvents = getEventsForDate(events, currentDate);\n weekDates.push({\n date: currentDate,\n isCurrentMonth: true,\n isToday: isToday(currentDate),\n hasEvents: dateEvents.length > 0,\n events: dateEvents,\n });\n day++;\n }\n }\n\n dates.push(weekDates);\n }\n\n return dates;\n}\n\nexport function getPopupPositionClass(selectedDayIndex: number | null): string {\n if (selectedDayIndex === null) return 'popup-center-bottom';\n\n if (selectedDayIndex < 3) {\n return 'popup-right';\n } else if (selectedDayIndex > 4) {\n return 'popup-left';\n } else {\n return 'popup-center-bottom';\n }\n}\n\nexport function getCellClasses(calendarDate: CalendarDate): string[] {\n const classes: string[] = [];\n\n if (!calendarDate.isCurrentMonth) {\n classes.push('other-month');\n }\n\n if (calendarDate.isToday) {\n classes.push('schedule--current--exam');\n }\n\n if (calendarDate.hasEvents) {\n classes.push('has--event');\n }\n\n return classes;\n}\n\nexport function formatDateForDisplay(date: Date): string {\n return `${DAYS[date.getDay()]} ${date.getDate()}`;\n}\n\nexport function getMonthYearText(year: number, month: number): string {\n return `${MONTHS_FULL[month]} ${year}`;\n}\n\nexport function formatTimeRange(event: CalendarEvent): string {\n if (event.allDay || (!event.startTime && !event.endTime)) {\n return 'All day';\n }\n\n if (event.startTime && event.endTime) {\n return `${event.startTime} - ${event.endTime}`;\n }\n\n if (event.startTime) {\n return `${event.startTime}`;\n }\n\n return '';\n}\n\nexport function formatAttendees(attendees?: string[]): string {\n if (!attendees || attendees.length === 0) return '';\n\n if (attendees.length === 1) return attendees[0];\n if (attendees.length === 2) return attendees.join(' and ');\n\n return `${attendees.slice(0, -1).join(', ')}, and ${attendees[attendees.length - 1]}`;\n}\n\nexport function sortEventsByTime(events: CalendarEvent[]): CalendarEvent[] {\n return [...events].sort((a, b) => {\n const aAllDay = a.allDay || (!a.startTime && !a.endTime);\n const bAllDay = b.allDay || (!b.startTime && !b.endTime);\n\n if (aAllDay && !bAllDay) return -1;\n if (!aAllDay && bAllDay) return 1;\n\n if (!a.startTime || !b.startTime) return 0;\n return a.startTime.localeCompare(b.startTime);\n });\n}\n\nexport const DEFAULT_CATEGORY_COLORS: CategoryColorMap = {\n work: '#3b82f6',\n personal: '#8b5cf6',\n meeting: '#10b981',\n deadline: '#ef4444',\n appointment: '#f59e0b',\n other: '#6b7280',\n};\n\n// Dynamic function that accepts custom colors\nexport function getDefaultEventColor(\n category?: string,\n customColors?: CategoryColorMap\n): string {\n const colorMap = customColors || DEFAULT_CATEGORY_COLORS;\n\n if (category && colorMap[category]) {\n return colorMap[category];\n }\n\n // Default fallback color\n return '#fc8917';\n}\n\n// Helper to merge custom colors with defaults\nexport function mergeCategoryColors(\n customColors?: CategoryColorMap\n): CategoryColorMap {\n return {\n ...DEFAULT_CATEGORY_COLORS,\n ...customColors,\n };\n}\n\n// Validate if a color is a valid hex color\nexport function isValidHexColor(color: string): boolean {\n return /^#([0-9A-F]{3}){1,2}$/i.test(color);\n}\n\n// Get color for a category with validation\nexport function getCategoryColor(\n category: string,\n customColors?: CategoryColorMap\n): string {\n const colorMap = mergeCategoryColors(customColors);\n const color = colorMap[category] || colorMap.other || '#fc8917';\n\n return isValidHexColor(color) ? color : '#fc8917';\n}\n","import {\n CalendarEvent,\n CalendarState,\n CalendarConfig,\n CalendarActions,\n CalendarViewModel,\n CategoryColorMap,\n} from './types';\nimport {\n generateCalendarDates,\n getEventsForDate,\n generateYears,\n getPopupPositionClass,\n getMonthYearText,\n formatDateForDisplay,\n mergeCategoryColors,\n getCategoryColor,\n MONTHS,\n DAYS,\n} from './utils';\n\nexport class CalendarEngine {\n private state: CalendarState;\n private config: CalendarConfig;\n private listeners: Set<() => void> = new Set();\n private categoryColors: CategoryColorMap;\n\n constructor(config: CalendarConfig) {\n this.config = config;\n this.categoryColors = mergeCategoryColors(config.categoryColors);\n\n const initialDate = config.initialDate || new Date();\n this.state = {\n currentYear: initialDate.getFullYear(),\n currentMonth: initialDate.getMonth(),\n currentDate: initialDate.getDate(),\n selectedDate: null,\n selectedDayIndex: null,\n tasks: [],\n };\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Notify all listeners of state changes\n */\n private notify(): void {\n this.listeners.forEach(listener => listener());\n }\n\n /**\n * Get current state\n */\n getState(): CalendarState {\n return { ...this.state };\n }\n\n /**\n * Get view model with computed properties\n */\n getViewModel(): CalendarViewModel {\n const calendarDates = generateCalendarDates(\n this.state.currentYear,\n this.state.currentMonth,\n this.config.events,\n this.config.weekStartsOn\n );\n\n return {\n ...this.state,\n months: MONTHS,\n days: DAYS,\n years: generateYears(this.config.minYear, this.config.maxYear),\n monthAndYearText: getMonthYearText(\n this.state.currentYear,\n this.state.currentMonth\n ),\n scheduleDay: this.state.selectedDate\n ? formatDateForDisplay(this.state.selectedDate)\n : '',\n calendarDates,\n popupPositionClass: getPopupPositionClass(this.state.selectedDayIndex),\n };\n }\n\n /**\n * Get actions object\n */\n getActions(): CalendarActions {\n return {\n next: this.next.bind(this),\n previous: this.previous.bind(this),\n jump: this.jump.bind(this),\n goToToday: this.goToToday.bind(this),\n isCurrentMonth: this.isCurrentMonth.bind(this),\n selectDate: this.selectDate.bind(this),\n updateTasks: this.updateTasks.bind(this),\n };\n }\n\n /**\n * Navigate to next month\n */\n private next(): void {\n if (this.state.currentMonth === 11) {\n this.state.currentMonth = 0;\n this.state.currentYear++;\n } else {\n this.state.currentMonth++;\n }\n\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Navigate to previous month\n */\n private previous(): void {\n if (this.state.currentMonth === 0) {\n this.state.currentMonth = 11;\n this.state.currentYear--;\n } else {\n this.state.currentMonth--;\n }\n\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Jump to specific month and year\n */\n private jump(year: number, month: number): void {\n this.state.currentYear = year;\n this.state.currentMonth = month;\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Navigate to current month (today)\n */\n private goToToday(): void {\n const today = new Date();\n this.state.currentYear = today.getFullYear();\n this.state.currentMonth = today.getMonth();\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Check if currently viewing today's month\n */\n private isCurrentMonth(): boolean {\n const today = new Date();\n return (\n this.state.currentYear === today.getFullYear() &&\n this.state.currentMonth === today.getMonth()\n );\n }\n\n /**\n * Select a specific date\n */\n private selectDate(date: Date, dayIndex?: number): void {\n this.state.selectedDate = date;\n this.state.selectedDayIndex = dayIndex ?? null;\n this.state.currentDate = date.getDate();\n this.state.currentMonth = date.getMonth();\n this.state.currentYear = date.getFullYear();\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Update tasks for the currently selected date\n */\n private updateTasks(): void {\n if (!this.state.selectedDate) {\n this.state.tasks = [];\n return;\n }\n\n this.state.tasks = getEventsForDate(\n this.config.events,\n this.state.selectedDate\n );\n }\n\n /**\n * Update events configuration\n */\n updateEvents(events: CalendarEvent[]): void {\n this.config.events = events;\n this.updateTasks();\n this.notify();\n }\n\n /**\n * Handle date cell click\n */\n handleDateClick(date: Date, dayIndex?: number): void {\n this.selectDate(date, dayIndex);\n }\n\n /**\n * Check if date has events\n */\n hasEventsForDate(date: Date): boolean {\n return getEventsForDate(this.config.events, date).length > 0;\n }\n\n /**\n * Get events for a specific date\n */\n getEventsForDate(date: Date): CalendarEvent[] {\n return getEventsForDate(this.config.events, date);\n }\n\n /**\n * Clear selected date\n */\n clearSelection(): void {\n this.state.selectedDate = null;\n this.state.selectedDayIndex = null;\n this.state.tasks = [];\n this.notify();\n }\n\n /**\n * Get category color (with custom colors support)\n */\n getCategoryColor(category?: string): string {\n if (!category) return '#fc8917';\n return getCategoryColor(category, this.categoryColors);\n }\n\n /**\n * Update category colors dynamically\n */\n updateCategoryColors(colors: CategoryColorMap): void {\n this.categoryColors = mergeCategoryColors(colors);\n this.notify();\n }\n\n /**\n * Get all category colors\n */\n getCategoryColors(): CategoryColorMap {\n return { ...this.categoryColors };\n }\n\n /**\n * Register a new category with color\n */\n registerCategory(name: string, color: string): void {\n this.categoryColors[name] = color;\n this.notify();\n }\n\n /**\n * Destroy the engine and cleanup listeners\n */\n destroy(): void {\n this.listeners.clear();\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/core/index.mjs
CHANGED
|
@@ -13,6 +13,20 @@ var MONTHS = [
|
|
|
13
13
|
"Nov",
|
|
14
14
|
"Dec"
|
|
15
15
|
];
|
|
16
|
+
var MONTHS_FULL = [
|
|
17
|
+
"January",
|
|
18
|
+
"February",
|
|
19
|
+
"March",
|
|
20
|
+
"April",
|
|
21
|
+
"May",
|
|
22
|
+
"June",
|
|
23
|
+
"July",
|
|
24
|
+
"August",
|
|
25
|
+
"September",
|
|
26
|
+
"October",
|
|
27
|
+
"November",
|
|
28
|
+
"December"
|
|
29
|
+
];
|
|
16
30
|
var DAYS = [
|
|
17
31
|
"Sunday",
|
|
18
32
|
"Monday",
|
|
@@ -51,19 +65,39 @@ function generateCalendarDates(year, month, events = [], weekStartsOn = 0) {
|
|
|
51
65
|
const firstDay = new Date(year, month, 1);
|
|
52
66
|
const lastDay = new Date(year, month + 1, 0);
|
|
53
67
|
const daysInMonth = lastDay.getDate();
|
|
68
|
+
const prevMonthLastDay = new Date(year, month, 0).getDate();
|
|
54
69
|
let firstDayOfWeek = firstDay.getDay();
|
|
55
70
|
if (weekStartsOn === 1) {
|
|
56
71
|
firstDayOfWeek = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;
|
|
57
72
|
}
|
|
58
73
|
const dates = [];
|
|
59
74
|
let day = 1;
|
|
75
|
+
let nextMonthDay = 1;
|
|
60
76
|
for (let week = 0; week < 6; week++) {
|
|
61
77
|
const weekDates = [];
|
|
62
78
|
for (let dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
|
|
63
79
|
if (week === 0 && dayOfWeek < firstDayOfWeek) {
|
|
64
|
-
|
|
80
|
+
const prevDay = prevMonthLastDay - firstDayOfWeek + dayOfWeek + 1;
|
|
81
|
+
const prevDate = new Date(year, month - 1, prevDay);
|
|
82
|
+
const dateEvents = getEventsForDate(events, prevDate);
|
|
83
|
+
weekDates.push({
|
|
84
|
+
date: prevDate,
|
|
85
|
+
isCurrentMonth: false,
|
|
86
|
+
isToday: isToday(prevDate),
|
|
87
|
+
hasEvents: dateEvents.length > 0,
|
|
88
|
+
events: dateEvents
|
|
89
|
+
});
|
|
65
90
|
} else if (day > daysInMonth) {
|
|
66
|
-
|
|
91
|
+
const nextDate = new Date(year, month + 1, nextMonthDay);
|
|
92
|
+
const dateEvents = getEventsForDate(events, nextDate);
|
|
93
|
+
weekDates.push({
|
|
94
|
+
date: nextDate,
|
|
95
|
+
isCurrentMonth: false,
|
|
96
|
+
isToday: isToday(nextDate),
|
|
97
|
+
hasEvents: dateEvents.length > 0,
|
|
98
|
+
events: dateEvents
|
|
99
|
+
});
|
|
100
|
+
nextMonthDay++;
|
|
67
101
|
} else {
|
|
68
102
|
const currentDate = new Date(year, month, day);
|
|
69
103
|
const dateEvents = getEventsForDate(events, currentDate);
|
|
@@ -78,9 +112,6 @@ function generateCalendarDates(year, month, events = [], weekStartsOn = 0) {
|
|
|
78
112
|
}
|
|
79
113
|
}
|
|
80
114
|
dates.push(weekDates);
|
|
81
|
-
if (day > daysInMonth && weekDates.every((date) => date === null)) {
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
115
|
}
|
|
85
116
|
return dates;
|
|
86
117
|
}
|
|
@@ -95,8 +126,10 @@ function getPopupPositionClass(selectedDayIndex) {
|
|
|
95
126
|
}
|
|
96
127
|
}
|
|
97
128
|
function getCellClasses(calendarDate) {
|
|
98
|
-
if (!calendarDate) return [];
|
|
99
129
|
const classes = [];
|
|
130
|
+
if (!calendarDate.isCurrentMonth) {
|
|
131
|
+
classes.push("other-month");
|
|
132
|
+
}
|
|
100
133
|
if (calendarDate.isToday) {
|
|
101
134
|
classes.push("schedule--current--exam");
|
|
102
135
|
}
|
|
@@ -109,7 +142,7 @@ function formatDateForDisplay(date) {
|
|
|
109
142
|
return `${DAYS[date.getDay()]} ${date.getDate()}`;
|
|
110
143
|
}
|
|
111
144
|
function getMonthYearText(year, month) {
|
|
112
|
-
return `${
|
|
145
|
+
return `${MONTHS_FULL[month]} ${year}`;
|
|
113
146
|
}
|
|
114
147
|
function formatTimeRange(event) {
|
|
115
148
|
if (event.allDay || !event.startTime && !event.endTime) {
|
|
@@ -236,6 +269,8 @@ var CalendarEngine = class {
|
|
|
236
269
|
next: this.next.bind(this),
|
|
237
270
|
previous: this.previous.bind(this),
|
|
238
271
|
jump: this.jump.bind(this),
|
|
272
|
+
goToToday: this.goToToday.bind(this),
|
|
273
|
+
isCurrentMonth: this.isCurrentMonth.bind(this),
|
|
239
274
|
selectDate: this.selectDate.bind(this),
|
|
240
275
|
updateTasks: this.updateTasks.bind(this)
|
|
241
276
|
};
|
|
@@ -281,6 +316,25 @@ var CalendarEngine = class {
|
|
|
281
316
|
this.updateTasks();
|
|
282
317
|
this.notify();
|
|
283
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* Navigate to current month (today)
|
|
321
|
+
*/
|
|
322
|
+
goToToday() {
|
|
323
|
+
const today = /* @__PURE__ */ new Date();
|
|
324
|
+
this.state.currentYear = today.getFullYear();
|
|
325
|
+
this.state.currentMonth = today.getMonth();
|
|
326
|
+
this.state.selectedDate = null;
|
|
327
|
+
this.state.selectedDayIndex = null;
|
|
328
|
+
this.updateTasks();
|
|
329
|
+
this.notify();
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Check if currently viewing today's month
|
|
333
|
+
*/
|
|
334
|
+
isCurrentMonth() {
|
|
335
|
+
const today = /* @__PURE__ */ new Date();
|
|
336
|
+
return this.state.currentYear === today.getFullYear() && this.state.currentMonth === today.getMonth();
|
|
337
|
+
}
|
|
284
338
|
/**
|
|
285
339
|
* Select a specific date
|
|
286
340
|
*/
|
|
@@ -380,6 +434,7 @@ export {
|
|
|
380
434
|
DAYS,
|
|
381
435
|
DEFAULT_CATEGORY_COLORS,
|
|
382
436
|
MONTHS,
|
|
437
|
+
MONTHS_FULL,
|
|
383
438
|
formatAttendees,
|
|
384
439
|
formatDateForDisplay,
|
|
385
440
|
formatTimeRange,
|