@forcecalendar/core 2.1.69 → 2.2.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.
@@ -39,11 +39,19 @@ export class TimezoneManager {
39
39
  this.database = new TimezoneDatabase();
40
40
 
41
41
  // Cache timezone offsets for performance
42
+ // offsetCache: Map<timezone, Map<15-minute UTC bucket, offset>>
42
43
  this.offsetCache = new Map();
43
44
  this.dstCache = new Map();
44
45
 
46
+ // Intl.DateTimeFormat construction is ~50x the cost of using one,
47
+ // so formatters are cached per timezone and reused
48
+ this.formatterCache = new Map();
49
+
45
50
  // Cache size management
46
51
  this.maxCacheSize = 1000;
52
+ // ~20k 15-minute buckets per zone (≈ a few hundred KB worst case) covers
53
+ // multi-year expansions without evicting entries mid-scan
54
+ this.maxOffsetBucketsPerZone = 20000;
47
55
  this.cacheHits = 0;
48
56
  this.cacheMisses = 0;
49
57
  }
@@ -109,68 +117,106 @@ export class TimezoneManager {
109
117
  // Resolve any aliases
110
118
  timezone = this.database.resolveAlias(timezone);
111
119
 
112
- // Check cache first
113
- const cacheKey = `${timezone}_${date.getFullYear()}_${date.getMonth()}_${date.getDate()}_${date.getHours()}`;
114
- if (this.offsetCache.has(cacheKey)) {
115
- this.cacheHits++;
116
- this._manageCacheSize();
117
- return this.offsetCache.get(cacheKey);
120
+ // Offsets only change at DST transitions, which occur on 15-minute UTC
121
+ // boundaries worldwide — one cached entry covers each 15-minute bucket
122
+ const bucket = Math.floor(date.getTime() / 900000);
123
+ let zoneCache = this.offsetCache.get(timezone);
124
+ if (zoneCache) {
125
+ const cached = zoneCache.get(bucket);
126
+ if (cached !== undefined) {
127
+ this.cacheHits++;
128
+ return cached;
129
+ }
130
+ } else {
131
+ zoneCache = new Map();
132
+ this.offsetCache.set(timezone, zoneCache);
118
133
  }
119
134
 
120
135
  this.cacheMisses++;
121
136
 
137
+ let offset;
138
+
122
139
  // Try using Intl API if available (best option for browser/Node.js environments)
123
140
  if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
124
141
  try {
125
- const formatter = new Intl.DateTimeFormat('en-US', {
126
- timeZone: timezone,
127
- year: 'numeric',
128
- month: '2-digit',
129
- day: '2-digit',
130
- hour: '2-digit',
131
- minute: '2-digit',
132
- second: '2-digit',
133
- hour12: false
134
- });
135
-
136
142
  // Create same date in target timezone
137
- const parts = formatter.formatToParts(date);
138
- const tzDate = new Date(
139
- parts.find(p => p.type === 'year').value,
140
- parts.find(p => p.type === 'month').value - 1,
141
- parts.find(p => p.type === 'day').value,
142
- parts.find(p => p.type === 'hour').value,
143
- parts.find(p => p.type === 'minute').value,
144
- parts.find(p => p.type === 'second').value
145
- );
146
-
147
- const offset = (tzDate.getTime() - date.getTime()) / (1000 * 60);
148
- this.offsetCache.set(cacheKey, -offset);
149
- this._manageCacheSize();
150
- return -offset;
143
+ const parts = this._getFormatter(timezone).formatToParts(date);
144
+ let year, month, day, hour, minute, second;
145
+ for (const part of parts) {
146
+ switch (part.type) {
147
+ case 'year':
148
+ year = +part.value;
149
+ break;
150
+ case 'month':
151
+ month = +part.value;
152
+ break;
153
+ case 'day':
154
+ day = +part.value;
155
+ break;
156
+ case 'hour':
157
+ hour = +part.value;
158
+ break;
159
+ case 'minute':
160
+ minute = +part.value;
161
+ break;
162
+ case 'second':
163
+ second = +part.value;
164
+ break;
165
+ }
166
+ }
167
+ const tzDate = new Date(year, month - 1, day, hour, minute, second);
168
+ offset = -((tzDate.getTime() - date.getTime()) / (1000 * 60));
151
169
  } catch (e) {
152
170
  // Fallback to database calculation
153
171
  }
154
172
  }
155
173
 
156
- // Fallback: Use timezone database
157
- const tzData = this.database.getTimezone(timezone);
158
- if (!tzData) {
159
- throw new Error(`Unknown timezone: ${timezone}`);
160
- }
174
+ if (offset === undefined) {
175
+ // Fallback: Use timezone database
176
+ const tzData = this.database.getTimezone(timezone);
177
+ if (!tzData) {
178
+ throw new Error(`Unknown timezone: ${timezone}`);
179
+ }
161
180
 
162
- let offset = tzData.offset;
181
+ offset = tzData.offset;
163
182
 
164
- // Apply DST if applicable
165
- if (tzData.dst && this.isDST(date, timezone, tzData.dst)) {
166
- offset += tzData.dst.offset;
183
+ // Apply DST if applicable
184
+ if (tzData.dst && this.isDST(date, timezone, tzData.dst)) {
185
+ offset += tzData.dst.offset;
186
+ }
167
187
  }
168
188
 
169
- this.offsetCache.set(cacheKey, offset);
170
- this._manageCacheSize();
189
+ if (zoneCache.size >= this.maxOffsetBucketsPerZone) {
190
+ zoneCache.clear();
191
+ }
192
+ zoneCache.set(bucket, offset);
171
193
  return offset;
172
194
  }
173
195
 
196
+ /**
197
+ * Get a cached Intl.DateTimeFormat for a timezone
198
+ * @param {string} timezone - Timezone identifier
199
+ * @returns {Intl.DateTimeFormat}
200
+ * @private
201
+ */
202
+ _getFormatter(timezone) {
203
+ let formatter = this.formatterCache.get(timezone);
204
+ if (!formatter) {
205
+ formatter = new Intl.DateTimeFormat('en-US', {
206
+ timeZone: timezone,
207
+ year: 'numeric',
208
+ month: '2-digit',
209
+ day: '2-digit',
210
+ hour: '2-digit',
211
+ minute: '2-digit',
212
+ second: '2-digit',
213
+ hour12: false
214
+ });
215
+ this.formatterCache.set(timezone, formatter);
216
+ }
217
+ return formatter;
218
+ }
219
+
174
220
  /**
175
221
  * Check if date is in DST for given timezone
176
222
  * @param {Date} date - Date to check
@@ -449,7 +495,7 @@ export class TimezoneManager {
449
495
  : 0;
450
496
 
451
497
  return {
452
- offsetCacheSize: this.offsetCache.size,
498
+ offsetCacheSize: [...this.offsetCache.values()].reduce((n, m) => n + m.size, 0),
453
499
  dstCacheSize: this.dstCache.size,
454
500
  maxCacheSize: this.maxCacheSize,
455
501
  cacheHits: this.cacheHits,
@@ -463,16 +509,8 @@ export class TimezoneManager {
463
509
  * @private
464
510
  */
465
511
  _manageCacheSize() {
466
- // Clear caches if they get too large
467
- if (this.offsetCache.size > this.maxCacheSize) {
468
- // Remove first half of entries (oldest)
469
- const entriesToRemove = Math.floor(this.offsetCache.size / 2);
470
- const keys = Array.from(this.offsetCache.keys());
471
- for (let i = 0; i < entriesToRemove; i++) {
472
- this.offsetCache.delete(keys[i]);
473
- }
474
- }
475
-
512
+ // Offset cache size is managed per-zone at insertion time in
513
+ // getTimezoneOffset; only the DST cache needs periodic eviction here
476
514
  if (this.dstCache.size > this.maxCacheSize / 2) {
477
515
  const entriesToRemove = Math.floor(this.dstCache.size / 2);
478
516
  const keys = Array.from(this.dstCache.keys());
package/core/types.js CHANGED
@@ -19,6 +19,9 @@
19
19
  * @property {boolean} [recurring=false] - Whether this is a recurring event
20
20
  * @property {RecurrenceRule|string} [recurrenceRule=null] - Recurrence rule (RRULE string or object)
21
21
  * @property {string} [timeZone=null] - IANA timezone for the event
22
+ * @property {string} [endTimeZone=null] - IANA timezone for the event end (cross-timezone events)
23
+ * @property {RecurrenceRule|string} [recurrence=null] - Backward-compatible alias for recurrenceRule
24
+ * @property {string} [category=null] - Single category (alias for a one-element categories array)
22
25
  * @property {EventStatus} [status='confirmed'] - Event status
23
26
  * @property {EventVisibility} [visibility='public'] - Event visibility
24
27
  * @property {Organizer} [organizer=null] - Event organizer
@@ -172,7 +175,7 @@
172
175
  * @property {boolean} isCurrentMonth - Whether this day is in the current month
173
176
  * @property {boolean} isToday - Whether this is today
174
177
  * @property {boolean} isWeekend - Whether this is a weekend day
175
- * @property {import('./core/events/Event.js').Event[]} events - Events for this day
178
+ * @property {import('./events/Event.js').Event[]} events - Events for this day
176
179
  */
177
180
 
178
181
  /**
@@ -191,9 +194,9 @@
191
194
  * @property {string} dayName - Localized day name
192
195
  * @property {boolean} isToday - Whether this is today
193
196
  * @property {boolean} isWeekend - Whether this is a weekend day
194
- * @property {import('./core/events/Event.js').Event[]} events - All events for this day
195
- * @property {Array<import('./core/events/Event.js').Event[]>} overlapGroups - Groups of overlapping events
196
- * @property {function(import('./core/events/Event.js').Event[]): Map<string, EventPosition>} getEventPositions - Function to calculate positions
197
+ * @property {import('./events/Event.js').Event[]} events - All events for this day
198
+ * @property {Array<import('./events/Event.js').Event[]>} overlapGroups - Groups of overlapping events
199
+ * @property {(events: import('./events/Event.js').Event[]) => Map<string, EventPosition>} getEventPositions - Function to calculate positions
197
200
  */
198
201
 
199
202
  /**
@@ -208,7 +211,7 @@
208
211
  * @property {Date} date - Date being displayed
209
212
  * @property {string} dayName - Localized day name
210
213
  * @property {boolean} isToday - Whether this is today
211
- * @property {import('./core/events/Event.js').Event[]} allDayEvents - All-day events
214
+ * @property {import('./events/Event.js').Event[]} allDayEvents - All-day events
212
215
  * @property {HourSlot[]} hours - Hourly time slots
213
216
  */
214
217
 
@@ -216,7 +219,7 @@
216
219
  * @typedef {Object} HourSlot
217
220
  * @property {number} hour - Hour (0-23)
218
221
  * @property {string} time - Formatted time string
219
- * @property {import('./core/events/Event.js').Event[]} events - Events in this hour
222
+ * @property {import('./events/Event.js').Event[]} events - Events in this hour
220
223
  */
221
224
 
222
225
  /**
@@ -233,7 +236,7 @@
233
236
  * @property {Date} date - Date object
234
237
  * @property {string} dayName - Localized day name
235
238
  * @property {boolean} isToday - Whether this is today
236
- * @property {import('./core/events/Event.js').Event[]} events - Events for this day
239
+ * @property {import('./events/Event.js').Event[]} events - Events for this day
237
240
  */
238
241
 
239
242
  /**
@@ -273,9 +276,9 @@
273
276
  /**
274
277
  * @typedef {Object} EventStoreChange
275
278
  * @property {('add'|'update'|'remove'|'clear')} type - Type of change
276
- * @property {import('./core/events/Event.js').Event} [event] - Affected event
277
- * @property {import('./core/events/Event.js').Event} [oldEvent] - Previous event state (for updates)
278
- * @property {import('./core/events/Event.js').Event[]} [oldEvents] - Previous events (for clear)
279
+ * @property {import('./events/Event.js').Event} [event] - Affected event
280
+ * @property {import('./events/Event.js').Event} [oldEvent] - Previous event state (for updates)
281
+ * @property {import('./events/Event.js').Event[]} [oldEvents] - Previous events (for clear)
279
282
  * @property {number} version - Store version number
280
283
  */
281
284
 
@@ -305,16 +308,16 @@
305
308
 
306
309
  /**
307
310
  * @typedef {Object} CalendarPlugin
308
- * @property {function(import('./core/calendar/Calendar.js').Calendar): void} install - Installation function
309
- * @property {function(import('./core/calendar/Calendar.js').Calendar): void} [uninstall] - Cleanup function
311
+ * @property {(calendar: import('./calendar/Calendar.js').Calendar) => void} install - Installation function
312
+ * @property {(calendar: import('./calendar/Calendar.js').Calendar) => void} [uninstall] - Cleanup function
310
313
  */
311
314
 
312
315
  /**
313
- * @typedef {function(any): void} EventListener
316
+ * @typedef {(payload: any) => void} EventListener
314
317
  */
315
318
 
316
319
  /**
317
- * @typedef {function(): void} UnsubscribeFn
320
+ * @typedef {() => void} UnsubscribeFn
318
321
  */
319
322
 
320
323
  /**
package/package.json CHANGED
@@ -1,32 +1,55 @@
1
1
  {
2
2
  "name": "@forcecalendar/core",
3
- "version": "2.1.69",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "A modern, lightweight, framework-agnostic calendar engine optimized for Salesforce",
7
7
  "main": "core/index.js",
8
8
  "module": "core/index.js",
9
- "types": "core/types.js",
9
+ "types": "./types/index.d.ts",
10
10
  "sideEffects": false,
11
11
  "scripts": {
12
12
  "test": "node tests/run-all.js",
13
13
  "test:ics": "node tests/integration/test-ics.js",
14
14
  "test:search": "node tests/integration/test-search.js",
15
- "lint": "eslint core/ --ext .js",
16
- "lint:fix": "eslint core/ --ext .js --fix",
15
+ "lint": "eslint core/",
16
+ "lint:fix": "eslint core/ --fix",
17
17
  "format": "prettier --write \"core/**/*.js\"",
18
18
  "format:check": "prettier --check \"core/**/*.js\"",
19
19
  "quality": "npm run lint && npm run format:check",
20
- "sync:version": "node scripts/sync-version.js"
20
+ "sync:version": "node scripts/sync-version.js",
21
+ "build:types": "tsc -p tsconfig.types.json",
22
+ "prepublishOnly": "npm run build:types"
21
23
  },
22
24
  "exports": {
23
- ".": "./core/index.js",
24
- "./calendar": "./core/calendar/Calendar.js",
25
- "./events": "./core/events/Event.js",
26
- "./state": "./core/state/StateManager.js",
27
- "./search": "./core/search/EventSearch.js",
28
- "./ics": "./core/ics/ICSHandler.js",
29
- "./types": "./core/types.js"
25
+ ".": {
26
+ "types": "./types/index.d.ts",
27
+ "default": "./core/index.js"
28
+ },
29
+ "./calendar": {
30
+ "types": "./types/calendar/Calendar.d.ts",
31
+ "default": "./core/calendar/Calendar.js"
32
+ },
33
+ "./events": {
34
+ "types": "./types/events/Event.d.ts",
35
+ "default": "./core/events/Event.js"
36
+ },
37
+ "./state": {
38
+ "types": "./types/state/StateManager.d.ts",
39
+ "default": "./core/state/StateManager.js"
40
+ },
41
+ "./search": {
42
+ "types": "./types/search/EventSearch.d.ts",
43
+ "default": "./core/search/EventSearch.js"
44
+ },
45
+ "./ics": {
46
+ "types": "./types/ics/ICSHandler.d.ts",
47
+ "default": "./core/ics/ICSHandler.js"
48
+ },
49
+ "./types": {
50
+ "types": "./types/types.d.ts",
51
+ "default": "./core/types.js"
52
+ }
30
53
  },
31
54
  "repository": {
32
55
  "type": "git",
@@ -50,20 +73,17 @@
50
73
  },
51
74
  "homepage": "https://github.com/forceCalendar/core#readme",
52
75
  "devDependencies": {
53
- "@babel/core": "^7.29.6",
54
- "@babel/preset-env": "^7.29.7",
55
- "@rollup/plugin-babel": "^7.0.0",
56
- "@rollup/plugin-node-resolve": "^16.0.3",
57
- "@rollup/plugin-terser": "^1.0.0",
58
- "eslint": "^8.50.0",
76
+ "@eslint/js": "^10.0.1",
77
+ "eslint": "^10.6.0",
78
+ "globals": "^17.7.0",
59
79
  "prettier": "^3.0.3",
60
- "rollup": "^4.61.1",
61
- "vite": "^6.4.3"
80
+ "typescript": "^7.0.2"
62
81
  },
63
82
  "files": [
64
83
  "core/**/*.js",
65
84
  "!core/**/*.test.js",
66
85
  "!core/**/*.spec.js",
86
+ "types/**/*.d.ts",
67
87
  "README.md",
68
88
  "LICENSE"
69
89
  ]
@@ -0,0 +1,287 @@
1
+ import { EventStore } from '../events/EventStore.js';
2
+ import { Event } from '../events/Event.js';
3
+ import { StateManager } from '../state/StateManager.js';
4
+ import { TimezoneManager } from '../timezone/TimezoneManager.js';
5
+ /**
6
+ * Calendar - Main calendar class with full timezone support
7
+ * Pure JavaScript, no DOM dependencies
8
+ * Framework agnostic, Locker Service compatible
9
+ */
10
+ export declare class Calendar {
11
+ timezoneManager: TimezoneManager;
12
+ config: {
13
+ events?: import("../types.js").EventData[];
14
+ view: string;
15
+ date: Date;
16
+ weekStartsOn: number;
17
+ locale: string;
18
+ timeZone: string;
19
+ showWeekNumbers: boolean;
20
+ showWeekends: boolean;
21
+ fixedWeekCount: boolean;
22
+ businessHours: {
23
+ start: string;
24
+ end: string;
25
+ };
26
+ };
27
+ eventStore: EventStore;
28
+ state: StateManager;
29
+ listeners: Map<any, any>;
30
+ plugins: Set<any>;
31
+ views: Map<any, any>;
32
+ /**
33
+ * Create a new Calendar instance
34
+ * @param {import('../types.js').CalendarConfig} [config={}] - Configuration options
35
+ */
36
+ constructor(config?: import('../types.js').CalendarConfig);
37
+ /**
38
+ * Set the calendar view
39
+ * @param {import('../types.js').ViewType} viewType - The view type ('month', 'week', 'day', 'list')
40
+ * @param {Date} [date=null] - Optional date to navigate to
41
+ */
42
+ setView(viewType: import('../types.js').ViewType, date?: Date): void;
43
+ /**
44
+ * Get the current view type
45
+ * @returns {import('../types.js').ViewType} The current view type
46
+ */
47
+ getView(): import('../types.js').ViewType;
48
+ /**
49
+ * Navigate to the next period
50
+ */
51
+ next(): void;
52
+ /**
53
+ * Navigate to the previous period
54
+ */
55
+ previous(): void;
56
+ /**
57
+ * Navigate to today
58
+ */
59
+ today(): void;
60
+ /**
61
+ * Navigate to a specific date
62
+ * @param {Date} date - The date to navigate to
63
+ */
64
+ goToDate(date: Date): void;
65
+ /**
66
+ * Alias for goToDate (compat)
67
+ * @param {Date} date - The date to navigate to
68
+ */
69
+ setDate(date: Date): void;
70
+ /**
71
+ * Get the current date
72
+ * @returns {Date}
73
+ */
74
+ getCurrentDate(): Date;
75
+ /**
76
+ * Add an event
77
+ * @param {import('../events/Event.js').Event|import('../types.js').EventData} eventData - Event data or Event instance
78
+ * @returns {import('../events/Event.js').Event} The added event
79
+ */
80
+ addEvent(eventData: import('../events/Event.js').Event | import('../types.js').EventData): import('../events/Event.js').Event;
81
+ /**
82
+ * Update an event
83
+ * @param {string} eventId - The event ID
84
+ * @param {Object} updates - Properties to update
85
+ * @returns {Event} The updated event
86
+ */
87
+ updateEvent(eventId: string, updates: Object): Event;
88
+ /**
89
+ * Remove an event
90
+ * @param {string} eventId - The event ID
91
+ * @returns {boolean} True if removed
92
+ */
93
+ removeEvent(eventId: string): boolean;
94
+ /**
95
+ * Alias for removeEvent (compat)
96
+ * @param {string} eventId - The event ID
97
+ * @returns {boolean} True if removed
98
+ */
99
+ deleteEvent(eventId: string): boolean;
100
+ /**
101
+ * Get an event by ID
102
+ * @param {string} eventId - The event ID
103
+ * @returns {Event|null}
104
+ */
105
+ getEvent(eventId: string): Event | null;
106
+ /**
107
+ * Get all events
108
+ * @returns {Event[]}
109
+ */
110
+ getEvents(): Event[];
111
+ /**
112
+ * Set all events (replaces existing)
113
+ * @param {Event[]} events - Array of events
114
+ */
115
+ setEvents(events: Event[]): void;
116
+ /**
117
+ * Query events with filters
118
+ * @param {Object} filters - Query filters
119
+ * @returns {Event[]}
120
+ */
121
+ queryEvents(filters: Object): Event[];
122
+ /**
123
+ * Get events for a specific date
124
+ * @param {Date} date - The date
125
+ * @param {string} [timezone] - Timezone for the query (defaults to calendar timezone)
126
+ * @returns {Event[]}
127
+ */
128
+ getEventsForDate(date: Date, timezone?: string): Event[];
129
+ /**
130
+ * Get events in a date range
131
+ * @param {Date} start - Start date
132
+ * @param {Date} end - End date
133
+ * @param {string} [timezone] - Timezone for the query (defaults to calendar timezone)
134
+ * @returns {Event[]}
135
+ */
136
+ getEventsInRange(start: Date, end: Date, timezone?: string): Event[];
137
+ /**
138
+ * Set the calendar's timezone
139
+ * @param {string} timezone - IANA timezone identifier
140
+ */
141
+ setTimezone(timezone: string): void;
142
+ /**
143
+ * Get the current timezone
144
+ * @returns {string} Current timezone
145
+ */
146
+ getTimezone(): string;
147
+ /**
148
+ * Set the calendar locale
149
+ * @param {string} locale - Locale identifier (e.g. 'en-US')
150
+ */
151
+ setLocale(locale: string): void;
152
+ /**
153
+ * Set the week start day
154
+ * @param {number} weekStartsOn - 0 = Sunday, 1 = Monday, etc.
155
+ */
156
+ setWeekStartsOn(weekStartsOn: number): void;
157
+ /**
158
+ * Convert a date from one timezone to another
159
+ * @param {Date} date - Date to convert
160
+ * @param {string} fromTimezone - Source timezone
161
+ * @param {string} toTimezone - Target timezone
162
+ * @returns {Date} Converted date
163
+ */
164
+ convertTimezone(date: Date, fromTimezone: string, toTimezone: string): Date;
165
+ /**
166
+ * Convert a date to the calendar's timezone
167
+ * @param {Date} date - Date to convert
168
+ * @param {string} fromTimezone - Source timezone
169
+ * @returns {Date} Date in calendar timezone
170
+ */
171
+ toCalendarTimezone(date: Date, fromTimezone: string): Date;
172
+ /**
173
+ * Convert a date from the calendar's timezone
174
+ * @param {Date} date - Date in calendar timezone
175
+ * @param {string} toTimezone - Target timezone
176
+ * @returns {Date} Converted date
177
+ */
178
+ fromCalendarTimezone(date: Date, toTimezone: string): Date;
179
+ /**
180
+ * Format a date in a specific timezone
181
+ * @param {Date} date - Date to format
182
+ * @param {string} [timezone] - Timezone for formatting (defaults to calendar timezone)
183
+ * @param {Object} [options] - Formatting options
184
+ * @returns {string} Formatted date string
185
+ */
186
+ formatInTimezone(date: Date, timezone?: string, options?: Object): string;
187
+ /**
188
+ * Get list of common timezones with offsets
189
+ * @returns {Array<{value: string, label: string, offset: string}>} Timezone list
190
+ */
191
+ getTimezones(): Array<{
192
+ value: string;
193
+ label: string;
194
+ offset: string;
195
+ }>;
196
+ /**
197
+ * Get overlapping event groups for a date
198
+ * @param {Date} date - The date to check
199
+ * @param {boolean} timedOnly - Only include timed events
200
+ * @returns {Array<Event[]>} Array of event groups that overlap
201
+ */
202
+ getOverlapGroups(date: Date, timedOnly?: boolean): Array<Event[]>;
203
+ /**
204
+ * Calculate event positions for rendering
205
+ * @param {Event[]} events - Array of overlapping events
206
+ * @returns {Map<string, {column: number, totalColumns: number}>} Position data
207
+ */
208
+ calculateEventPositions(events: Event[]): Map<string, {
209
+ column: number;
210
+ totalColumns: number;
211
+ }>;
212
+ /**
213
+ * Get the current view's data
214
+ * @returns {import('../types.js').MonthViewData|import('../types.js').WeekViewData|import('../types.js').DayViewData|import('../types.js').ListViewData|null} View-specific data
215
+ */
216
+ getViewData(): import('../types.js').MonthViewData | import('../types.js').WeekViewData | import('../types.js').DayViewData | import('../types.js').ListViewData | null;
217
+ /**
218
+ * Get month view data
219
+ * @private
220
+ */
221
+ private _getMonthViewData;
222
+ /**
223
+ * Get week view data
224
+ * @private
225
+ */
226
+ private _getWeekViewData;
227
+ /**
228
+ * Get day view data
229
+ * @private
230
+ */
231
+ private _getDayViewData;
232
+ /**
233
+ * Get list view data
234
+ * @private
235
+ */
236
+ private _getListViewData;
237
+ /**
238
+ * Select an event
239
+ * @param {string} eventId - Event ID to select
240
+ */
241
+ selectEvent(eventId: string): void;
242
+ /**
243
+ * Clear event selection
244
+ */
245
+ clearEventSelection(): void;
246
+ /**
247
+ * Select a date
248
+ * @param {Date} date - Date to select
249
+ */
250
+ selectDate(date: Date): void;
251
+ /**
252
+ * Clear date selection
253
+ */
254
+ clearDateSelection(): void;
255
+ /**
256
+ * Subscribe to calendar events
257
+ * @param {string} eventName - Event name
258
+ * @param {Function} callback - Callback function
259
+ * @returns {Function} Unsubscribe function
260
+ */
261
+ on(eventName: string, callback: Function): Function;
262
+ /**
263
+ * Unsubscribe from calendar events
264
+ * @param {string} eventName - Event name
265
+ * @param {Function} callback - Callback function
266
+ */
267
+ off(eventName: string, callback: Function): void;
268
+ /**
269
+ * Emit an event
270
+ * @private
271
+ */
272
+ private _emit;
273
+ /**
274
+ * Set up internal listeners
275
+ * @private
276
+ */
277
+ private _setupInternalListeners;
278
+ /**
279
+ * Install a plugin
280
+ * @param {Object} plugin - Plugin object with install method
281
+ */
282
+ use(plugin: Object): void;
283
+ /**
284
+ * Destroy the calendar and clean up
285
+ */
286
+ destroy(): void;
287
+ }