@ilamy/calendar 1.8.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,27 +1,5 @@
1
- import { Weekday } from "rrule";
2
- import { RRule } from "rrule";
3
- import { Options } from "rrule";
4
- import { Dayjs } from "dayjs";
5
- /**
6
- * Re-rrule.js Options with practical TypeScript interface.
7
- * Makes all properties optional except freq and dtstart (which are required by RFC 5545).
8
- * This allows clean object creation without needing explicit null values.
9
- *
10
- * @see https://tools.ietf.org/html/rfc5545 - RFC 5545 iCalendar specification
11
- * @see https://github.com/jakubroztocil/rrule - rrule.js library documentation
12
- */
13
- type RRuleOptions = {
14
- /**
15
- * The frequency of the event. Must be one of the following: DAILY, WEEKLY, MONTHLY, etc.
16
- */
17
- freq: Options["freq"];
18
- /**
19
- * The start date of the recurrence rule. This defines when the recurrence pattern begins.
20
- * Required for proper RRULE functionality according to RFC 5545.
21
- * @important Same as the event start date.
22
- */
23
- dtstart: Date;
24
- } & Partial<Omit<Options, "freq" | "dtstart">>;
1
+ import { ComponentType, ReactNode as ReactNode2 } from "react";
2
+ import { Dayjs as Dayjs2, ManipulateType as ManipulateType2 } from "dayjs";
25
3
  /**
26
4
  * Core calendar event interface representing a single calendar event.
27
5
  * This is the primary data structure for calendar events.
@@ -32,9 +10,9 @@ interface CalendarEvent {
32
10
  /** Display title of the event */
33
11
  title: string;
34
12
  /** Start date and time of the event */
35
- start: Dayjs;
13
+ start: Dayjs2;
36
14
  /** End date and time of the event */
37
- end: Dayjs;
15
+ end: Dayjs2;
38
16
  /**
39
17
  * Color for the event (supports CSS color values, hex, rgb, hsl, or CSS class names)
40
18
  * @example "#3b82f6", "blue-500", "rgb(59, 130, 246)"
@@ -55,29 +33,6 @@ interface CalendarEvent {
55
33
  */
56
34
  allDay?: boolean;
57
35
  /**
58
- * Recurrence rule for recurring events (RFC 5545 standard)
59
- *
60
- * Uses TypeScript interface for better readability, type safety, and IDE support
61
- * compared to RRULE string format. Converted to rrule.js format internally.
62
- *
63
- * @example { freq: 'WEEKLY', interval: 1, byweekday: ['MO', 'WE', 'FR'] }
64
- * @example { freq: 'DAILY', interval: 1, count: 10 }
65
- * @example { freq: 'MONTHLY', interval: 1, until: new Date('2025-12-31') }
66
- */
67
- rrule?: RRuleOptions;
68
- /**
69
- * Exception dates (EXDATE) - dates to exclude from recurrence
70
- * Uses ISO string format for storage and transmission
71
- * @example ['2025-01-15T09:00:00.000Z', '2025-01-22T09:00:00.000Z']
72
- */
73
- exdates?: string[];
74
- /**
75
- * Recurrence ID (RECURRENCE-ID) - identifies modified instances
76
- * Points to the original occurrence date this event modifies
77
- * Used for events that are modifications of recurring instances
78
- */
79
- recurrenceId?: string;
80
- /**
81
36
  * UID for iCalendar compatibility
82
37
  * Unique identifier across calendar systems
83
38
  */
@@ -91,7 +46,7 @@ interface CalendarEvent {
91
46
  * Use this to store additional metadata specific to your application
92
47
  * @example { meetingType: 'standup', attendees: ['john', 'jane'] }
93
48
  */
94
- data?: Record<string, any>;
49
+ data?: Record<string, unknown>;
95
50
  }
96
51
  /**
97
52
  * Supported days of the week for calendar configuration.
@@ -119,50 +74,6 @@ interface BusinessHours {
119
74
  */
120
75
  endTime?: number;
121
76
  }
122
- interface EventFormProps {
123
- open?: boolean;
124
- selectedEvent?: CalendarEvent | null;
125
- onAdd?: (event: CalendarEvent) => void;
126
- onUpdate?: (event: CalendarEvent) => void;
127
- onDelete?: (event: CalendarEvent) => void;
128
- onClose: () => void;
129
- }
130
- import React4 from "react";
131
- import React3 from "react";
132
- /**
133
- * Public-facing resource calendar event interface with flexible date types.
134
- * Similar to IlamyCalendarPropEvent but with resource assignment fields.
135
- * Dates can be provided as Dayjs, Date, or string and will be normalized internally.
136
- *
137
- * @interface IlamyResourceCalendarPropEvent
138
- * @extends {IlamyCalendarPropEvent}
139
- */
140
- interface IlamyResourceCalendarPropEvent extends IlamyCalendarPropEvent {
141
- /** Single resource assignment */
142
- resourceId?: string | number;
143
- /** Multiple resource assignment (cross-resource events) */
144
- resourceIds?: (string | number)[];
145
- }
146
- interface IlamyResourceCalendarProps extends Omit<IlamyCalendarProps, "events"> {
147
- /** Array of events to display */
148
- events?: IlamyResourceCalendarPropEvent[];
149
- /** Array of resources */
150
- resources?: Resource[];
151
- /** Custom render function for resources */
152
- renderResource?: (resource: Resource) => React.ReactNode;
153
- /**
154
- * Orientation of the resource view.
155
- * - "horizontal": Resources are rows, time is columns (default)
156
- * - "vertical": Resources are columns, time is rows
157
- */
158
- orientation?: "horizontal" | "vertical";
159
- /**
160
- * Granularity of time slots in the week view.
161
- * - "hourly": Time slots are 1 hour (default)
162
- * - "daily": Time slots are 1 day
163
- */
164
- weekViewGranularity?: "hourly" | "daily";
165
- }
166
77
  /**
167
78
  * Resource interface representing a calendar resource (person, room, equipment, etc.)
168
79
  */
@@ -181,8 +92,6 @@ interface Resource {
181
92
  * @example "#dbeafe", "blue-100", "rgba(59, 130, 246, 0.1)"
182
93
  */
183
94
  backgroundColor?: string;
184
- /** Optional position for resource display */
185
- position?: number;
186
95
  /**
187
96
  * Configuration for resource-specific business hours.
188
97
  * If provided, these will be used instead of the global business hours for this resource.
@@ -193,9 +102,266 @@ interface Resource {
193
102
  * Use this to store additional metadata specific to your application
194
103
  * @example { avatar: 'https://example.com/avatar.png', role: 'admin' }
195
104
  */
196
- data?: Record<string, any>;
105
+ data?: Record<string, unknown>;
106
+ }
107
+ interface PluginDateRange {
108
+ start: Dayjs2;
109
+ end: Dayjs2;
110
+ }
111
+ interface PluginMutationArgs {
112
+ event: CalendarEvent;
113
+ updates?: Partial<CalendarEvent>;
114
+ currentEvents: CalendarEvent[];
115
+ scope: unknown;
116
+ }
117
+ /** Structured result from `applyEdit` when a mutation updates multiple stored rows. */
118
+ interface PluginMutationResult {
119
+ events: CalendarEvent[];
120
+ /** Existing rows to persist via `onEventUpdate`. */
121
+ updated: CalendarEvent[];
122
+ /** New rows to persist via `onEventAdd`. */
123
+ added: CalendarEvent[];
124
+ /** Existing rows to persist via `onEventDelete`. */
125
+ deleted: CalendarEvent[];
126
+ }
127
+ /**
128
+ * Calendar configuration handed to a view's `columns()`/`renderHeader()`.
129
+ * Carries the resource axis (`resources`, `orientation`) so a resource-capable
130
+ * view can compose both arrangements. `range()` receives only the
131
+ * `firstDayOfWeek` slice (see its own signature).
132
+ */
133
+ interface ViewConfig {
134
+ firstDayOfWeek: number;
135
+ hiddenDays?: Set<number>;
136
+ businessHours?: BusinessHours | BusinessHours[];
137
+ hideNonBusinessHours?: boolean;
138
+ /** The resource axis. Set only when the calendar renders resources. */
139
+ resources?: Resource[];
140
+ /**
141
+ * The calendar-level resource arrangement (the user's choice): where the
142
+ * resource axis goes. Only meaningful when `resources` is set.
143
+ */
144
+ orientation?: "vertical" | "horizontal";
145
+ /**
146
+ * Week-view granularity when `resources` is set: 'hourly' (default) nests
147
+ * hour slots under each day; 'daily' shows one cell per day.
148
+ */
149
+ weekViewGranularity?: "hourly" | "daily";
150
+ }
151
+ /**
152
+ * One column of a 'vertical' view (time flows down the column).
153
+ * Formalizes the calendar's existing VerticalGrid column input.
154
+ */
155
+ interface VerticalColumnSpec {
156
+ /** Stable column id; drives testids and React keys. */
157
+ id: string;
158
+ /** The date this column represents; gutter/label columns leave it unset. */
159
+ day?: Dayjs2;
160
+ /** The cells of the column: hour slots (gridType 'hour') or dates ('day'). */
161
+ days: Dayjs2[];
162
+ gridType?: "day" | "hour";
163
+ className?: string;
164
+ /** Label-only column (e.g. the time gutter): renders no events. */
165
+ noEvents?: boolean;
166
+ renderCell?: (date: Dayjs2) => ReactNode2;
167
+ /**
168
+ * Resource-axis identity when the column belongs to one resource. The
169
+ * single carrier: consumers derive the id from `resource.id`.
170
+ */
171
+ resource?: Resource;
172
+ }
173
+ /** One cell of a 'horizontal' row. */
174
+ interface HorizontalCellSpec {
175
+ id: string;
176
+ day?: Dayjs2;
177
+ /** A grouped cell spanning several dates (nested-axis arrangements). */
178
+ days?: Dayjs2[];
179
+ gridType: "day" | "hour";
180
+ className?: string;
181
+ }
182
+ /**
183
+ * One row of a 'horizontal' view (date cells flow across the row).
184
+ * Formalizes the calendar's existing HorizontalGrid row input.
185
+ */
186
+ interface HorizontalRowSpec {
187
+ /** Stable row id; drives testids and React keys (matches VerticalColumnSpec.id). */
188
+ id: string;
189
+ columns?: HorizontalCellSpec[];
190
+ className?: string;
191
+ showDayNumber?: boolean;
192
+ /** Resource-axis identity when the row belongs to one resource. */
193
+ resource?: Resource;
194
+ }
195
+ /** What a view's `columns()` returns; `layout` picks which engine consumes it. */
196
+ type ColumnSpec = VerticalColumnSpec | HorizontalRowSpec;
197
+ /** Context passed to a view's `renderHeader`. */
198
+ interface ViewHeaderContext {
199
+ date: Dayjs2;
200
+ config: ViewConfig;
201
+ }
202
+ /**
203
+ * Describes a view type — contributed by a plugin or built into the calendar
204
+ * core (the four built-ins are themselves `PluginView` entries). A view either
205
+ * declares `columns` + `layout` and renders through the shared grid engines,
206
+ * or renders entirely through `component` (the escape hatch).
207
+ */
208
+ interface PluginView {
209
+ /** Unique view id, e.g. 'resource-week'. */
210
+ name: string;
211
+ /** View-switcher label (or a translation key; unknown keys render as-is). */
212
+ label?: string;
213
+ /**
214
+ * View-switcher icon (a component taking `className`, e.g. a lucide icon).
215
+ * Always shown in the switcher; the label appears beside it only when the
216
+ * view is selected, and as a hover tooltip otherwise.
217
+ */
218
+ icon: ComponentType<{
219
+ className?: string;
220
+ }>;
221
+ /**
222
+ * The escape hatch: renders the whole view when `columns`/`layout` are
223
+ * absent. Spec-driven views omit it. A view with neither renders nothing
224
+ * (dev builds log a warning).
225
+ */
226
+ component?: ComponentType;
227
+ /** How far prev/next steps when `navigationStep` is absent ('week', 'month', …). */
228
+ navigationUnit?: ManipulateType2;
229
+ /**
230
+ * How far prev/next jumps; defaults to one `navigationUnit`. Custom-duration
231
+ * views (a 40-day grid, a 4-day vertical view) set `{ amount: 40, unit: 'day' }`
232
+ * so navigation moves a full window.
233
+ *
234
+ * This also selects the header title/date-picker form (the core derives it
235
+ * generically, never by view name): a single `day`/`week`/`month`/`year` step
236
+ * borrows that grid's picker and title; any other step (amount > 1, or a custom
237
+ * unit) shows the day picker over the view's `range`. A third-party view gets
238
+ * the right picker for free just by declaring how it navigates.
239
+ */
240
+ navigationStep?: {
241
+ amount: number;
242
+ unit: ManipulateType2;
243
+ };
244
+ /**
245
+ * Visible range for navigation callbacks and the event pipeline. Views
246
+ * without `range` fall back to the month 6x7 grid range. Receives only the
247
+ * `firstDayOfWeek` slice of the config; the full axis config reaches
248
+ * `columns()`/`renderHeader()`.
249
+ */
250
+ range?: (date: Dayjs2, config: Pick<ViewConfig, "firstDayOfWeek">) => {
251
+ start: Dayjs2;
252
+ end: Dayjs2;
253
+ };
254
+ /**
255
+ * Column/row specs for the shared renderer. Return `VerticalColumnSpec[]`
256
+ * when `layout` is 'vertical', `HorizontalRowSpec[]` when 'horizontal'.
257
+ * Omit (together with `layout`) to render `component` instead.
258
+ */
259
+ columns?: (date: Dayjs2, config: ViewConfig) => VerticalColumnSpec[] | HorizontalRowSpec[];
260
+ /**
261
+ * The view's intrinsic shape (the author's choice): which engine renders it
262
+ * when the calendar has NO resources. 'vertical' = time flows down;
263
+ * 'horizontal' = date cells flow across in stacked rows. With resources on
264
+ * a resource-capable view, the calendar-level `orientation` wins instead:
265
+ * `engine = resources && supportsResources ? orientation : layout`.
266
+ */
267
+ layout?: "vertical" | "horizontal";
268
+ /** Header row content rendered above the grid by the shared renderer. */
269
+ renderHeader?: (ctx: ViewHeaderContext) => ReactNode2;
270
+ /**
271
+ * Whether `columns()` composes the resource axis when `config.resources`
272
+ * is set. Defaults to false; the view switcher hides resource-incapable
273
+ * views on a resource calendar.
274
+ */
275
+ supportsResources?: boolean;
276
+ }
277
+ /**
278
+ * A calendar plugin contributes optional behavior and UI through generic hooks
279
+ * named after pipeline moments and mount points, never after a feature. The
280
+ * core stays agnostic of any specific plugin (e.g. recurrence).
281
+ *
282
+ * Hooks follow the Rollup/Vite execution kinds:
283
+ * - `transformEvents` is sequential: each plugin receives the previous
284
+ * plugin's output, forming a transform chain.
285
+ * - `managesEvent` is first-match: the first plugin whose managesEvent returns
286
+ * true owns its scoped mutations.
287
+ * - `renderSlot` is additive: every plugin may contribute to a mount point.
288
+ *
289
+ * `slotName` is an opaque string identifier and `context` is opaque to the
290
+ * core. The built-in slot names and their context shapes live in the calendar
291
+ * core, which this contract does NOT depend on, so adding a slot never changes
292
+ * this interface. A plugin narrows `context` by `slotName` at its boundary.
293
+ *
294
+ * `scope` is opaque to the core: the owner produces it (via the mutation-scope
295
+ * slot) and consumes it in `applyEdit` / `applyDelete`. A plugin that provides
296
+ * `applyEdit` / `applyDelete` should also render the mutation-scope slot so the
297
+ * core can gather that scope before mutating.
298
+ */
299
+ interface IlamyPlugin {
300
+ name: string;
301
+ transformEvents?: (events: CalendarEvent[], range: PluginDateRange) => CalendarEvent[];
302
+ managesEvent?: (event: CalendarEvent) => boolean;
303
+ applyEdit?: (args: PluginMutationArgs) => CalendarEvent[] | PluginMutationResult;
304
+ applyDelete?: (args: PluginMutationArgs) => CalendarEvent[] | PluginMutationResult;
305
+ renderSlot?: (slotName: string, context: unknown) => ReactNode2;
306
+ /**
307
+ * Contributes arbitrary data to a named point. Additive: all plugins may
308
+ * contribute to the same point; the runtime aggregates all results via
309
+ * `collect`. Parallel to `renderSlot` but for data rather than UI nodes.
310
+ */
311
+ contribute?: (point: string, context: unknown) => unknown[];
312
+ /**
313
+ * Registers new view types that the calendar can switch to. Each entry in
314
+ * the array describes one view (id, component, navigation unit, …).
315
+ */
316
+ views?: PluginView[];
317
+ /**
318
+ * Wraps the calendar subtree so the plugin's own React context is available
319
+ * to its views, slots, and components. Rendered as the outermost wrapper
320
+ * among all plugin providers.
321
+ */
322
+ provider?: ComponentType<{
323
+ children: ReactNode2;
324
+ }>;
197
325
  }
198
- interface Translations {
326
+ /** Context passed to the `event-form` slot (inside the create/edit form). */
327
+ interface EventFormSlotContext {
328
+ event: CalendarEvent;
329
+ onChange: (updates: Partial<CalendarEvent>) => void;
330
+ }
331
+ /**
332
+ * Context passed to the `event-mutation-scope` slot. The owning plugin renders
333
+ * UI to gather its opaque `scope`, then calls `resolve(scope)` (or `cancel`).
334
+ */
335
+ interface EventMutationScopeSlotContext {
336
+ event: CalendarEvent;
337
+ operation: "edit" | "delete";
338
+ resolve: (scope: unknown) => void;
339
+ cancel: () => void;
340
+ }
341
+ import dayjs from "dayjs";
342
+ type Dayjs3 = dayjs.Dayjs3;
343
+ type ManipulateType3 = dayjs.ManipulateType3;
344
+ declare const _default: typeof dayjs;
345
+ /**
346
+ * The calendar's plugin mount points. These belong to the host (the components
347
+ * that render them: the event form and the drag-and-drop flow), NOT to the
348
+ * plugin kernel and NOT to any individual plugin. The kernel's `renderSlot`
349
+ * takes a plain `slotName: string` and knows nothing about this list; the core
350
+ * renders these named slots and any plugin may fill the ones it cares about.
351
+ */
352
+ declare const SLOT_EVENT_FORM = "event-form";
353
+ declare const SLOT_EVENT_MUTATION_SCOPE = "event-mutation-scope";
354
+ interface EventFormProps {
355
+ open?: boolean;
356
+ selectedEvent?: CalendarEvent | null;
357
+ onAdd?: (event: CalendarEvent) => void;
358
+ onUpdate?: (event: CalendarEvent) => void;
359
+ onDelete?: (event: CalendarEvent) => void;
360
+ onClose: () => void;
361
+ }
362
+ import React4 from "react";
363
+ import React3 from "react";
364
+ declare const defaultTranslations: {
199
365
  today: string;
200
366
  create: string;
201
367
  new: string;
@@ -203,6 +369,8 @@ interface Translations {
203
369
  delete: string;
204
370
  cancel: string;
205
371
  export: string;
372
+ previous: string;
373
+ next: string;
206
374
  event: string;
207
375
  events: string;
208
376
  newEvent: string;
@@ -226,6 +394,16 @@ interface Translations {
226
394
  repeat: string;
227
395
  repeats: string;
228
396
  customRecurrence: string;
397
+ frequency: string;
398
+ everyWeekday: string;
399
+ weeklyOn: string;
400
+ monthlyOnDay: string;
401
+ monthlyOnThe: string;
402
+ first: string;
403
+ second: string;
404
+ third: string;
405
+ fourth: string;
406
+ last: string;
229
407
  daily: string;
230
408
  weekly: string;
231
409
  monthly: string;
@@ -259,20 +437,27 @@ interface Translations {
259
437
  week: string;
260
438
  day: string;
261
439
  year: string;
440
+ agenda: string;
441
+ agendaNoEvents: string;
262
442
  more: string;
263
443
  resources: string;
264
444
  resource: string;
445
+ selectResource: string;
265
446
  time: string;
266
447
  date: string;
267
448
  noResourcesVisible: string;
268
449
  addResourcesOrShowExisting: string;
269
- }
450
+ };
451
+ /** All translation keys, derived from the canonical English dictionary in `default.ts`. */
452
+ type Translations = Record<keyof typeof defaultTranslations, string>;
270
453
  type TranslationKey = keyof Translations;
271
454
  type TranslatorFunction = (key: TranslationKey | string) => string;
272
455
  /**
273
- * Available calendar view types.
456
+ * Available calendar view types. The built-in views (day, week, month, year)
457
+ * are `PluginView` specs in `features/calendar/components/views`; plugins may
458
+ * contribute additional view names, so this is a broad `string`.
274
459
  */
275
- type CalendarView = "month" | "week" | "day" | "year";
460
+ type CalendarView = string;
276
461
  /**
277
462
  * Time format options for displaying times in the calendar.
278
463
  */
@@ -305,38 +490,46 @@ interface CalendarClassesOverride {
305
490
  * @extends {Omit<CalendarEvent, 'start' | 'end'>}
306
491
  */
307
492
  interface IlamyCalendarPropEvent extends Omit<CalendarEvent, "start" | "end"> {
308
- start: Dayjs | Date | string;
309
- end: Dayjs | Date | string;
493
+ start: Dayjs3 | Date | string;
494
+ end: Dayjs3 | Date | string;
310
495
  }
311
496
  /**
312
497
  * Information passed to the onCellClick callback.
313
498
  * Uses named properties for extensibility.
314
499
  */
315
500
  interface DateRange {
316
- start: Dayjs;
317
- end: Dayjs;
501
+ start: Dayjs3;
502
+ end: Dayjs3;
318
503
  }
319
- interface CellClickInfo {
320
- /** Start date/time of the clicked cell */
321
- start: Dayjs;
322
- /** End date/time of the clicked cell */
323
- end: Dayjs;
324
- /** Resource ID if clicking on a resource calendar cell (optional) */
325
- resourceId?: string | number;
326
- /** Whether the clicked cell is an all-day cell (optional) */
504
+ interface CellInfo {
505
+ /** Start date/time of the cell */
506
+ start: Dayjs3;
507
+ /** End date/time of the cell */
508
+ end: Dayjs3;
509
+ /** Full resource object in resource calendars; undefined in a regular calendar */
510
+ resource?: Resource;
511
+ /** Whether this is an all-day cell (optional) */
327
512
  allDay?: boolean;
328
513
  }
329
514
  /**
515
+ * Input accepted by `openEventForm`. A partial event, optionally carrying the
516
+ * full resource of the clicked cell (`CellInfo` is assignable as-is). When no
517
+ * explicit `resourceId` is given, the carried resource's id is used.
518
+ */
519
+ type OpenEventFormInput = Partial<CalendarEvent> & {
520
+ resource?: Resource;
521
+ };
522
+ /**
330
523
  * Props passed to the custom render function for the current time indicator.
331
524
  * Allows users to customize how the current time indicator is displayed.
332
525
  */
333
526
  interface RenderCurrentTimeIndicatorProps {
334
527
  /** The current time as a dayjs object */
335
- currentTime: Dayjs;
528
+ currentTime: Dayjs3;
336
529
  /** The start of the visible time range */
337
- rangeStart: Dayjs;
530
+ rangeStart: Dayjs3;
338
531
  /** The end of the visible time range */
339
- rangeEnd: Dayjs;
532
+ rangeEnd: Dayjs3;
340
533
  /** Progress percentage (0-100) representing position in the range */
341
534
  progress: number;
342
535
  /**
@@ -379,7 +572,7 @@ interface IlamyCalendarProps {
379
572
  * The initial date to display when the calendar loads.
380
573
  * If not provided, the calendar will default to today's date.
381
574
  */
382
- initialDate?: Dayjs | Date | string;
575
+ initialDate?: Dayjs3 | Date | string;
383
576
  /**
384
577
  * Custom render function for calendar events.
385
578
  * If provided, it will override the default event rendering.
@@ -394,7 +587,21 @@ interface IlamyCalendarProps {
394
587
  * Callback when a calendar cell is clicked.
395
588
  * Provides cell information including start/end dates and optional resourceId.
396
589
  */
397
- onCellClick?: (info: CellClickInfo) => void;
590
+ onCellClick?: (info: CellInfo) => void;
591
+ /**
592
+ * Predicate to disable individual cells based on custom logic (holidays,
593
+ * days-off, past dates, on-call windows, etc.). Return `true` to disable a
594
+ * cell — disabled cells block event creation clicks, reject drag-drops, and
595
+ * are grayed out. Composes with `businessHours` (a cell is disabled if either
596
+ * business hours or this predicate disables it).
597
+ */
598
+ isCellDisabled?: (info: CellInfo) => boolean;
599
+ /**
600
+ * Returns extra CSS classes for a cell based on custom logic (unavailability
601
+ * styling, on-call windows, etc.). Unlike `isCellDisabled`, this is purely
602
+ * visual — cells remain clickable and accept drag-drops.
603
+ */
604
+ getCellClassName?: (info: CellInfo) => string;
398
605
  /**
399
606
  * Callback when the calendar view changes (month, week, day, year).
400
607
  * Useful for syncing with external state or analytics.
@@ -419,7 +626,7 @@ interface IlamyCalendarProps {
419
626
  * Callback when the current date changes (navigation).
420
627
  * Provides the new current date and the current visible range.
421
628
  */
422
- onDateChange?: (date: Dayjs, range: DateRange) => void;
629
+ onDateChange?: (date: Dayjs3, range: DateRange) => void;
423
630
  /**
424
631
  * Locale to use for formatting dates and times.
425
632
  * If not provided, the default locale will be used.
@@ -593,7 +800,7 @@ interface IlamyCalendarProps {
593
800
  * Custom render function for the hour labels in the gutter/header.
594
801
  * Receives a Dayjs object for the hour and should return a React node.
595
802
  */
596
- renderHour?: (date: Dayjs) => React3.ReactNode;
803
+ renderHour?: (date: Dayjs3) => React3.ReactNode;
597
804
  /**
598
805
  * Granularity of the time grid in minutes for day, week, and resource hour views.
599
806
  * Quarter-hour increments only: `15`, `30`, or `60`.
@@ -629,32 +836,66 @@ interface IlamyCalendarProps {
629
836
  * ```
630
837
  */
631
838
  scrollTime?: string;
839
+ /**
840
+ * Optional plugins that add behavior/UI (e.g. recurrence). The core ships
841
+ * with no plugins by default — pass `recurrencePlugin()` to enable recurring
842
+ * events.
843
+ */
844
+ plugins?: IlamyPlugin[];
845
+ /**
846
+ * Resources (people, rooms, equipment) to display as a resource axis.
847
+ * When set: events are shown per matching resource (`resourceIds`, falling
848
+ * back to `resourceId`); events with no resource assignment are hidden; the
849
+ * year view is hidden from the view switcher.
850
+ */
851
+ resources?: Resource[];
852
+ /** Custom render function for resource header cells. */
853
+ renderResource?: (resource: Resource) => React3.ReactNode;
854
+ /**
855
+ * How resources are arranged. Only applies when `resources` is set.
856
+ * - "horizontal": resources are rows, time is columns (default)
857
+ * - "vertical": resources are columns, time is rows
858
+ */
859
+ orientation?: "horizontal" | "vertical";
860
+ /**
861
+ * Granularity of week-view time slots when `resources` is set.
862
+ * - "hourly": one column per hour (default)
863
+ * - "daily": one column per day. Note: `hiddenDays` is ignored in daily
864
+ * mode (non-contiguous days would break multi-day event positioning).
865
+ */
866
+ weekViewGranularity?: "hourly" | "daily";
632
867
  }
633
868
  declare const IlamyCalendar: React4.FC<IlamyCalendarProps>;
634
- declare const isRecurringEvent: (event: CalendarEvent) => boolean;
635
- interface GenerateRecurringEventsProps {
636
- event: CalendarEvent;
637
- currentEvents: CalendarEvent[];
638
- startDate: Dayjs;
639
- endDate: Dayjs;
640
- }
641
- declare const generateRecurringEvents: ({ event, currentEvents, startDate, endDate }: GenerateRecurringEventsProps) => CalendarEvent[];
642
869
  import React5 from "react";
870
+ /**
871
+ * @deprecated Since v2.0 `IlamyCalendar` accepts `resources`, `renderResource`,
872
+ * `orientation`, and `weekViewGranularity` directly — use it instead. This
873
+ * alias will be removed in the next major.
874
+ */
875
+ type IlamyResourceCalendarProps = IlamyCalendarProps;
876
+ /** @deprecated Since v2.0 — use `IlamyCalendar` with the `resources` prop. */
643
877
  declare const IlamyResourceCalendar: React5.FC<IlamyResourceCalendarProps>;
878
+ import React6 from "react";
644
879
  /**
645
- * Publicly exposed calendar context properties.
880
+ * The public calendar API surface exposed by useIlamyCalendarContext() — for consumers and plugin
881
+ * components. The full internal context is intentionally not exported.
646
882
  */
647
- interface UseIlamyCalendarContextReturn {
648
- readonly currentDate: Dayjs;
883
+ interface IlamyCalendarApi {
884
+ readonly currentDate: Dayjs3;
885
+ /** The active view's current visible date range (what is on screen). */
886
+ readonly currentRange: DateRange;
649
887
  readonly view: CalendarView;
650
888
  readonly events: CalendarEvent[];
889
+ readonly rawEvents: CalendarEvent[];
651
890
  readonly isEventFormOpen: boolean;
652
891
  readonly selectedEvent: CalendarEvent | null;
653
- readonly selectedDate: Dayjs | null;
892
+ readonly selectedDate: Dayjs3 | null;
654
893
  readonly firstDayOfWeek: number;
655
894
  readonly resources: Resource[];
656
- readonly setCurrentDate: (date: Dayjs) => void;
657
- readonly selectDate: (date: Dayjs) => void;
895
+ /** Axis the views lay out along: 'horizontal' (columns) or 'vertical' (rows). */
896
+ readonly orientation: "horizontal" | "vertical";
897
+ readonly setCurrentDate: (date: Dayjs3) => void;
898
+ readonly selectDate: (date: Dayjs3) => void;
658
899
  readonly setView: (view: CalendarView) => void;
659
900
  readonly nextPeriod: () => void;
660
901
  readonly prevPeriod: () => void;
@@ -662,15 +903,42 @@ interface UseIlamyCalendarContextReturn {
662
903
  readonly addEvent: (event: CalendarEvent) => void;
663
904
  readonly updateEvent: (eventId: string | number, event: Partial<CalendarEvent>) => void;
664
905
  readonly deleteEvent: (eventId: string | number) => void;
665
- readonly openEventForm: (eventData?: Partial<CalendarEvent>) => void;
906
+ readonly openEventForm: (eventData?: OpenEventFormInput) => void;
666
907
  readonly closeEventForm: () => void;
908
+ /**
909
+ * Handle a click on an existing event: runs the consumer's `onEventClick`
910
+ * callback if provided, otherwise opens the event for editing. Lets plugin
911
+ * views (e.g. agenda) handle event clicks identically to the built-in views.
912
+ */
913
+ readonly onEventClick: (event: CalendarEvent) => void;
914
+ /**
915
+ * The consumer's custom current-time-indicator renderer, if provided. Lets
916
+ * plugin views (e.g. agenda) render the indicator consistently with the
917
+ * built-in views via the shared `@ilamy/ui` CurrentTimeIndicator.
918
+ */
919
+ readonly renderCurrentTimeIndicator?: (props: RenderCurrentTimeIndicatorProps) => React6.ReactNode;
920
+ /**
921
+ * Events whose resource membership (`resourceIds`, falling back to
922
+ * `resourceId`) contains the given resource. On a calendar without
923
+ * resources this simply filters by the events' own resource fields.
924
+ */
667
925
  readonly getEventsForResource: (resourceId: string | number) => CalendarEvent[];
668
926
  readonly businessHours?: BusinessHours | BusinessHours[];
927
+ readonly t: TranslatorFunction;
928
+ readonly timeFormat: TimeFormat;
929
+ readonly timezone?: string;
930
+ readonly currentLocale: string;
931
+ readonly getEventsForDateRange: (start: Dayjs3, end: Dayjs3) => CalendarEvent[];
932
+ readonly applyScopedEdit: (event: CalendarEvent, updates: Partial<CalendarEvent>, scope: unknown) => void;
933
+ readonly applyScopedDelete: (event: CalendarEvent, scope: unknown) => void;
934
+ readonly getEventManager: (event: CalendarEvent) => IlamyPlugin | undefined;
935
+ readonly renderSlot: (slotName: string, context: unknown) => React6.ReactNode[];
936
+ readonly collect: (point: string, context: unknown) => unknown[];
937
+ readonly getViews: () => PluginView[];
669
938
  }
670
939
  /**
671
940
  * Public hook exported for library users.
672
941
  * Returns a limited set of commonly used properties and methods.
673
942
  */
674
- declare function useIlamyCalendarContext(): UseIlamyCalendarContextReturn;
675
- declare const defaultTranslations: Translations;
676
- export { useIlamyCalendarContext, isRecurringEvent, generateRecurringEvents, defaultTranslations, Weekday, WeekDays, UseIlamyCalendarContextReturn, TranslatorFunction, Translations, TranslationKey, TimeFormat, SlotDuration, Resource, RenderCurrentTimeIndicatorProps, RRuleOptions, RRule, IlamyResourceCalendarProps, IlamyResourceCalendar, IlamyCalendarProps, IlamyCalendar, EventFormProps, CellClickInfo, CalendarView, CalendarEvent, BusinessHours };
943
+ declare function useIlamyCalendarContext(): IlamyCalendarApi;
944
+ export { useIlamyCalendarContext, defaultTranslations, _default as dayjs, WeekDays, ViewHeaderContext, ViewConfig, VerticalColumnSpec, TranslatorFunction, Translations, TranslationKey, TimeFormat, SlotDuration, SLOT_EVENT_MUTATION_SCOPE, SLOT_EVENT_FORM, Resource, RenderCurrentTimeIndicatorProps, PluginView, PluginMutationResult, PluginMutationArgs, PluginDateRange, OpenEventFormInput, ManipulateType3 as ManipulateType, IlamyResourceCalendarProps, IlamyResourceCalendar, IlamyPlugin, IlamyCalendarProps, IlamyCalendarApi, IlamyCalendar, HorizontalRowSpec, HorizontalCellSpec, EventMutationScopeSlotContext, EventFormSlotContext, EventFormProps, Dayjs3 as Dayjs, ColumnSpec, CellInfo, CalendarView, CalendarEvent, CalendarClassesOverride, BusinessHours };