@innosolutions/inno-calendar 1.0.57 → 1.0.59
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/AGENT.md +1721 -1610
- package/README.md +235 -235
- package/dist/agenda-widget-BxZU4eGL.cjs +2 -0
- package/dist/agenda-widget-BxZU4eGL.cjs.map +1 -0
- package/dist/{agenda-widget-1kak6FM9.js → agenda-widget-wrZfO67A.js} +1308 -1223
- package/dist/agenda-widget-wrZfO67A.js.map +1 -0
- package/dist/components/event/event-card.d.ts.map +1 -1
- package/dist/components/index.cjs +1 -1
- package/dist/components/index.mjs +2 -2
- package/dist/components/primitives/scroll-navigator.d.ts +1 -1
- package/dist/components/primitives/scroll-navigator.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +200 -200
- package/dist/presets/index.cjs +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/{tailwind-calendar-DjtOowce.js → tailwind-calendar-CVuxWXLY.js} +2 -2
- package/dist/{tailwind-calendar-DjtOowce.js.map → tailwind-calendar-CVuxWXLY.js.map} +1 -1
- package/dist/{tailwind-calendar-DpEkgg5k.cjs → tailwind-calendar-DoG6s3PJ.cjs} +2 -2
- package/dist/{tailwind-calendar-DpEkgg5k.cjs.map → tailwind-calendar-DoG6s3PJ.cjs.map} +1 -1
- package/dist/week-view-Bzpbti1B.cjs +11 -0
- package/dist/week-view-Bzpbti1B.cjs.map +1 -0
- package/dist/{week-view-CKx6bJdJ.js → week-view-C1FxF_nk.js} +880 -867
- package/dist/week-view-C1FxF_nk.js.map +1 -0
- package/package.json +138 -138
- package/dist/agenda-widget-1kak6FM9.js.map +0 -1
- package/dist/agenda-widget-C8CFFI1c.cjs +0 -2
- package/dist/agenda-widget-C8CFFI1c.cjs.map +0 -1
- package/dist/week-view-CKx6bJdJ.js.map +0 -1
- package/dist/week-view-DXlwhFjn.cjs +0 -11
- package/dist/week-view-DXlwhFjn.cjs.map +0 -1
package/AGENT.md
CHANGED
|
@@ -1,1610 +1,1721 @@
|
|
|
1
|
-
# @innosolutions/inno-calendar — AI Agent Reference
|
|
2
|
-
|
|
3
|
-
> **Version 1.0.
|
|
4
|
-
> Headless-first, fully customizable React calendar for enterprise applications.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Table of Contents
|
|
9
|
-
|
|
10
|
-
1. [What This Package Is](#1-what-this-package-is)
|
|
11
|
-
2. [npm Scripts](#2-npm-scripts)
|
|
12
|
-
3. [Package Exports](#3-package-exports)
|
|
13
|
-
4. [Core Types](#4-core-types)
|
|
14
|
-
5. [InnoCalendar Props](#5-innocalendar-props)
|
|
15
|
-
6. [Slots System](#6-slots-system)
|
|
16
|
-
7. [ClassNames API](#7-classnames-api)
|
|
17
|
-
8. [EventCard & EventBlock](#8-eventcard--eventblock)
|
|
18
|
-
9. [EventPopover Component](#9-eventpopover-component)
|
|
19
|
-
10. [Preferences System](#10-preferences-system)
|
|
20
|
-
11. [Widget Components](#11-widget-components)
|
|
21
|
-
12. [Filter Components](#12-filter-components)
|
|
22
|
-
13. [Settings Components](#13-settings-components)
|
|
23
|
-
14. [Context & Hooks](#14-context--hooks)
|
|
24
|
-
15. [Drag & Drop](#15-drag--drop)
|
|
25
|
-
16. [Core Utilities](#16-core-utilities)
|
|
26
|
-
17. [Presets](#17-presets)
|
|
27
|
-
18. [CSS & Theming](#18-css--theming)
|
|
28
|
-
19. [Constants](#19-constants)
|
|
29
|
-
20. [Integration Guide](#20-integration-guide)
|
|
30
|
-
21. [Full Export Catalog](#21-full-export-catalog)
|
|
31
|
-
22. [File Naming Conventions](#22-file-naming-conventions)
|
|
32
|
-
23. [Styling Patterns](#23-styling-patterns)
|
|
33
|
-
24. [Biome Configuration](#24-biome-configuration)
|
|
34
|
-
25. [State Synchronization Guide](#25-state-synchronization-guide)
|
|
35
|
-
26. [Critical Rules](#26-critical-rules)
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## 1. What This Package Is
|
|
40
|
-
|
|
41
|
-
A **headless-first** React calendar component library — all view logic lives in hooks and contexts; every UI element is an optional, replaceable component.
|
|
42
|
-
|
|
43
|
-
### Feature Set
|
|
44
|
-
|
|
45
|
-
| Category | Features |
|
|
46
|
-
|---|---|
|
|
47
|
-
| **Views** | Day, Week, Month, Year, Agenda, Resource-Day, Resource-Week, Timeline-Day, Timeline-3Day, Timeline-Week |
|
|
48
|
-
| **Interaction** | Drag-to-select (time & day mode), event click, slot click, drag-and-drop reposition, event resize |
|
|
49
|
-
| **Customization** | 25+ component slots, 30+ classNames keys, render props, custom popover |
|
|
50
|
-
| **Data** | Generic `CalendarEvent<TData>`, adapter pattern, BYO data fetching |
|
|
51
|
-
| **Preferences** | localStorage persistence, locking, session mode, per-instance storage keys |
|
|
52
|
-
| **Filtering** | Built-in schedule type filter, user/participant filter, text search |
|
|
53
|
-
| **UI Extras** | Loading overlay, focus-event deep-linking, imperative ref API, settings panel, filter sidebar |
|
|
54
|
-
| **Embeddable** | AgendaWidget (standalone card), AgendaDropdown (bell-icon notification panel) |
|
|
55
|
-
| **Presets** | DefaultCalendar (styled), TailwindCalendar (Tailwind-optimized) |
|
|
56
|
-
|
|
57
|
-
### Tech Stack
|
|
58
|
-
|
|
59
|
-
| Layer | Technology |
|
|
60
|
-
|---|---|
|
|
61
|
-
| Runtime | React 18+/19, TypeScript 5.9 |
|
|
62
|
-
| Build | Vite 7 (library mode), vite-plugin-dts |
|
|
63
|
-
| Styling | TailwindCSS 4+, class-variance-authority (CVA), clsx, tailwind-merge |
|
|
64
|
-
| UI Primitives | Radix UI (optional peer deps: popover, tooltip, dropdown-menu,
|
|
65
|
-
| Icons | lucide-react |
|
|
66
|
-
| Date handling | Native Date API (no external date library) |
|
|
67
|
-
| Linting | Biome 2.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## 2. npm Scripts
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
npm run dev # Vite dev mode
|
|
75
|
-
npm run build # Production build (Vite + dts declarations)
|
|
76
|
-
npm run typecheck # tsc --noEmit
|
|
77
|
-
npm run lint # Biome lint check
|
|
78
|
-
npm run format # Biome format
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## 3. Package Exports
|
|
84
|
-
|
|
85
|
-
Defined in `package.json`:
|
|
86
|
-
|
|
87
|
-
```jsonc
|
|
88
|
-
{
|
|
89
|
-
"main": "./dist/index.cjs",
|
|
90
|
-
"module": "./dist/index.
|
|
91
|
-
"types": "./dist/index.d.ts",
|
|
92
|
-
"exports": {
|
|
93
|
-
".": {
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
},
|
|
98
|
-
"./
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
interface
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
|
278
|
-
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
// ===
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
|
910
|
-
|
|
911
|
-
| `
|
|
912
|
-
| `
|
|
913
|
-
| `
|
|
914
|
-
| `
|
|
915
|
-
| `
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
:
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
|
1083
|
-
|
|
1084
|
-
|
|
|
1085
|
-
|
|
|
1086
|
-
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
###
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
```
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
###
|
|
1205
|
-
|
|
1206
|
-
```
|
|
1207
|
-
const [
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
```
|
|
1241
|
-
|
|
1242
|
-
###
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
```
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
- **
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
###
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1
|
+
# @innosolutions/inno-calendar — AI Agent Reference
|
|
2
|
+
|
|
3
|
+
> **Version 1.0.58** | React 18+/19 | TypeScript 5.9 | Vite 7 library-mode
|
|
4
|
+
> Headless-first, fully customizable React calendar for enterprise applications.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
1. [What This Package Is](#1-what-this-package-is)
|
|
11
|
+
2. [npm Scripts](#2-npm-scripts)
|
|
12
|
+
3. [Package Exports](#3-package-exports)
|
|
13
|
+
4. [Core Types](#4-core-types)
|
|
14
|
+
5. [InnoCalendar Props](#5-innocalendar-props)
|
|
15
|
+
6. [Slots System](#6-slots-system)
|
|
16
|
+
7. [ClassNames API](#7-classnames-api)
|
|
17
|
+
8. [EventCard & EventBlock](#8-eventcard--eventblock)
|
|
18
|
+
9. [EventPopover Component](#9-eventpopover-component)
|
|
19
|
+
10. [Preferences System](#10-preferences-system)
|
|
20
|
+
11. [Widget Components](#11-widget-components)
|
|
21
|
+
12. [Filter Components](#12-filter-components)
|
|
22
|
+
13. [Settings Components](#13-settings-components)
|
|
23
|
+
14. [Context & Hooks](#14-context--hooks)
|
|
24
|
+
15. [Drag & Drop](#15-drag--drop)
|
|
25
|
+
16. [Core Utilities](#16-core-utilities)
|
|
26
|
+
17. [Presets](#17-presets)
|
|
27
|
+
18. [CSS & Theming](#18-css--theming)
|
|
28
|
+
19. [Constants](#19-constants)
|
|
29
|
+
20. [Integration Guide](#20-integration-guide)
|
|
30
|
+
21. [Full Export Catalog](#21-full-export-catalog)
|
|
31
|
+
22. [File Naming Conventions](#22-file-naming-conventions)
|
|
32
|
+
23. [Styling Patterns](#23-styling-patterns)
|
|
33
|
+
24. [Biome Configuration](#24-biome-configuration)
|
|
34
|
+
25. [State Synchronization Guide](#25-state-synchronization-guide)
|
|
35
|
+
26. [Critical Rules](#26-critical-rules)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 1. What This Package Is
|
|
40
|
+
|
|
41
|
+
A **headless-first** React calendar component library — all view logic lives in hooks and contexts; every UI element is an optional, replaceable component.
|
|
42
|
+
|
|
43
|
+
### Feature Set
|
|
44
|
+
|
|
45
|
+
| Category | Features |
|
|
46
|
+
|---|---|
|
|
47
|
+
| **Views** | Day, Week, Month, Year, Agenda, Resource-Day, Resource-Week, Timeline-Day, Timeline-3Day, Timeline-Week |
|
|
48
|
+
| **Interaction** | Drag-to-select (time & day mode), event click, slot click, drag-and-drop reposition, event resize |
|
|
49
|
+
| **Customization** | 25+ component slots, 30+ classNames keys, render props, custom popover |
|
|
50
|
+
| **Data** | Generic `CalendarEvent<TData>`, adapter pattern, BYO data fetching |
|
|
51
|
+
| **Preferences** | localStorage persistence, locking, session mode, per-instance storage keys |
|
|
52
|
+
| **Filtering** | Built-in schedule type filter, user/participant filter, text search |
|
|
53
|
+
| **UI Extras** | Loading overlay, focus-event deep-linking, imperative ref API, settings panel, filter sidebar |
|
|
54
|
+
| **Embeddable** | AgendaWidget (standalone card), AgendaDropdown (bell-icon notification panel) |
|
|
55
|
+
| **Presets** | DefaultCalendar (styled), TailwindCalendar (Tailwind-optimized) |
|
|
56
|
+
|
|
57
|
+
### Tech Stack
|
|
58
|
+
|
|
59
|
+
| Layer | Technology |
|
|
60
|
+
|---|---|
|
|
61
|
+
| Runtime | React 18+/19, TypeScript 5.9 |
|
|
62
|
+
| Build | Vite 7 (library mode), vite-plugin-dts |
|
|
63
|
+
| Styling | TailwindCSS 4+, class-variance-authority (CVA), clsx, tailwind-merge |
|
|
64
|
+
| UI Primitives | Radix UI (`@radix-ui/react-dialog` as direct dep; optional peer deps: popover, tooltip, dropdown-menu, scroll-area, select, avatar) |
|
|
65
|
+
| Icons | lucide-react |
|
|
66
|
+
| Date handling | Native Date API (no external date library) |
|
|
67
|
+
| Linting | Biome 2.3 |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 2. npm Scripts
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm run dev # Vite dev mode
|
|
75
|
+
npm run build # Production build (Vite + dts declarations)
|
|
76
|
+
npm run typecheck # tsc --noEmit
|
|
77
|
+
npm run lint # Biome lint check
|
|
78
|
+
npm run format # Biome format
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 3. Package Exports
|
|
84
|
+
|
|
85
|
+
Defined in `package.json`:
|
|
86
|
+
|
|
87
|
+
```jsonc
|
|
88
|
+
{
|
|
89
|
+
"main": "./dist/index.cjs",
|
|
90
|
+
"module": "./dist/index.mjs",
|
|
91
|
+
"types": "./dist/index.d.ts",
|
|
92
|
+
"exports": {
|
|
93
|
+
".": {
|
|
94
|
+
"types": "./dist/index.d.ts",
|
|
95
|
+
"import": "./dist/index.mjs",
|
|
96
|
+
"require": "./dist/index.cjs"
|
|
97
|
+
},
|
|
98
|
+
"./utils": {
|
|
99
|
+
"types": "./dist/utils.d.ts",
|
|
100
|
+
"import": "./dist/utils.mjs",
|
|
101
|
+
"require": "./dist/utils.cjs"
|
|
102
|
+
},
|
|
103
|
+
"./core": {
|
|
104
|
+
"types": "./dist/core/index.d.ts",
|
|
105
|
+
"import": "./dist/core/index.mjs",
|
|
106
|
+
"require": "./dist/core/index.cjs"
|
|
107
|
+
},
|
|
108
|
+
"./components": {
|
|
109
|
+
"types": "./dist/components/index.d.ts",
|
|
110
|
+
"import": "./dist/components/index.mjs",
|
|
111
|
+
"require": "./dist/components/index.cjs"
|
|
112
|
+
},
|
|
113
|
+
"./presets": {
|
|
114
|
+
"types": "./dist/presets/index.d.ts",
|
|
115
|
+
"import": "./dist/presets/index.mjs",
|
|
116
|
+
"require": "./dist/presets/index.cjs"
|
|
117
|
+
},
|
|
118
|
+
"./lib": {
|
|
119
|
+
"types": "./dist/lib/index.d.ts",
|
|
120
|
+
"import": "./dist/lib/index.mjs",
|
|
121
|
+
"require": "./dist/lib/index.cjs"
|
|
122
|
+
},
|
|
123
|
+
"./styles": "./dist/styles/index.css",
|
|
124
|
+
"./styles.css": "./dist/styles/index.css"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Consumer import patterns:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
// Components and types
|
|
133
|
+
import { InnoCalendar, type CalendarEvent } from '@innosolutions/inno-calendar';
|
|
134
|
+
// Core-only (headless hooks, types, utils)
|
|
135
|
+
import { useCalendar, type TCalendarView } from '@innosolutions/inno-calendar/core';
|
|
136
|
+
// Components only
|
|
137
|
+
import { EventCard } from '@innosolutions/inno-calendar/components';
|
|
138
|
+
// Presets only
|
|
139
|
+
import { DefaultCalendar } from '@innosolutions/inno-calendar/presets';
|
|
140
|
+
// Styles (required for built-in components)
|
|
141
|
+
import '@innosolutions/inno-calendar/styles';
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 4. Core Types
|
|
147
|
+
|
|
148
|
+
All types are defined in `src/core/types.ts` (1449 lines).
|
|
149
|
+
|
|
150
|
+
### CalendarEvent\<TData\>
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
interface CalendarEvent<TData = Record<string, unknown>> extends IBaseEvent {
|
|
154
|
+
// Required (from IBaseEvent)
|
|
155
|
+
id: string;
|
|
156
|
+
title: string;
|
|
157
|
+
startDate: Date;
|
|
158
|
+
endDate: Date;
|
|
159
|
+
|
|
160
|
+
// Optional visual/behavioral
|
|
161
|
+
description?: string;
|
|
162
|
+
color?: TEventColor;
|
|
163
|
+
hexColor?: string;
|
|
164
|
+
isAllDay?: boolean;
|
|
165
|
+
isMultiDay?: boolean;
|
|
166
|
+
isCanceled?: boolean;
|
|
167
|
+
isRecurring?: boolean;
|
|
168
|
+
resourceId?: string;
|
|
169
|
+
|
|
170
|
+
// Built-in filtering (optional)
|
|
171
|
+
scheduleTypeId?: number;
|
|
172
|
+
scheduleTypeName?: string;
|
|
173
|
+
participants?: ICalendarUser[];
|
|
174
|
+
|
|
175
|
+
// Consumer data bag (RECOMMENDED for all domain fields)
|
|
176
|
+
data?: TData;
|
|
177
|
+
|
|
178
|
+
// @deprecated — still functional, will be removed in next major
|
|
179
|
+
meetingTookPlace?: boolean;
|
|
180
|
+
isAccepted?: boolean;
|
|
181
|
+
companyId?: number;
|
|
182
|
+
cancelReason?: string | null;
|
|
183
|
+
scheduleTypeCode?: string;
|
|
184
|
+
opportunityId?: number;
|
|
185
|
+
propertyId?: number;
|
|
186
|
+
projectId?: number;
|
|
187
|
+
contactId?: number;
|
|
188
|
+
user?: ICalendarUser;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### IResource\<TData\>
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
interface IResource<TData = Record<string, unknown>> {
|
|
196
|
+
id: string;
|
|
197
|
+
name: string;
|
|
198
|
+
title?: string;
|
|
199
|
+
avatar?: string;
|
|
200
|
+
color?: TEventColor | string;
|
|
201
|
+
data?: TData;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### IScheduleType\<TData\>
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
interface IScheduleType<TData = Record<string, unknown>> {
|
|
209
|
+
id: number;
|
|
210
|
+
name: string;
|
|
211
|
+
color?: TEventColor | string;
|
|
212
|
+
icon?: string;
|
|
213
|
+
isDefault?: boolean;
|
|
214
|
+
isActive?: boolean;
|
|
215
|
+
code?: string;
|
|
216
|
+
resourceKey?: string;
|
|
217
|
+
colorHex?: string;
|
|
218
|
+
defaultMinutes?: number;
|
|
219
|
+
data?: TData;
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### ICalendarUser\<TData\>
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
interface ICalendarUser<TData = Record<string, unknown>> {
|
|
227
|
+
id: string;
|
|
228
|
+
name: string;
|
|
229
|
+
email?: string;
|
|
230
|
+
avatar?: string;
|
|
231
|
+
data?: TData;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### ICalendarRefHandle
|
|
236
|
+
|
|
237
|
+
Imperative handle exposed via `React.forwardRef` on `<InnoCalendar>`:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
interface ICalendarRefHandle {
|
|
241
|
+
scrollToToday: () => void;
|
|
242
|
+
scrollToWorkingHours: () => void;
|
|
243
|
+
getViewRect: () => DOMRect | null;
|
|
244
|
+
focusEvent: (eventId: string) => void;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Usage:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
const ref = useRef<ICalendarRefHandle>(null);
|
|
252
|
+
<InnoCalendar ref={ref} events={events} />
|
|
253
|
+
// Later:
|
|
254
|
+
ref.current?.scrollToToday();
|
|
255
|
+
ref.current?.focusEvent('appointment-42');
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### ICalendarPreferences
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
interface ICalendarPreferences {
|
|
262
|
+
startHour: number; // 0–23
|
|
263
|
+
endHour: number; // 0–24
|
|
264
|
+
firstDayOfWeek: 0|1|2|3|4|5|6;
|
|
265
|
+
slotDuration: number;
|
|
266
|
+
showWeekends: boolean;
|
|
267
|
+
timeFormat: '12h' | '24h';
|
|
268
|
+
badgeVariant: TBadgeVariant;
|
|
269
|
+
showCanceledEvents: boolean;
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### View Types
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
type TCalendarView =
|
|
277
|
+
| 'day' | 'week' | 'month' | 'year' | 'agenda'
|
|
278
|
+
| 'resource-day' | 'resource-week'
|
|
279
|
+
| 'timeline-day' | 'timeline-3day' | 'timeline-week';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Other Key Types
|
|
283
|
+
|
|
284
|
+
| Type | Purpose |
|
|
285
|
+
|---|---|
|
|
286
|
+
| `TEventColor` | `'blue'│'green'│'red'│'yellow'│'purple'│'orange'│'pink'│'teal'│'gray'│'indigo'` |
|
|
287
|
+
| `TBadgeVariant` | `'dot'│'colored'│'mixed'` |
|
|
288
|
+
| `TSlotDuration` | `15│30│60` |
|
|
289
|
+
| `TWorkingHours` | `Record<number, IWorkingHoursDay>` (0=Sun..6=Sat) |
|
|
290
|
+
| `ISelectionResult` | `{ startDate: Date; endDate: Date; resourceId?: string }` |
|
|
291
|
+
| `IDropResult<TData>` | Drag-drop result with event, newStartDate, newEndDate, newResourceId |
|
|
292
|
+
| `IDateRange` | `{ startDate: Date; endDate: Date }` |
|
|
293
|
+
| `IEventPosition` | `{ top, height, left, width, zIndex }` |
|
|
294
|
+
| `IPositionedEvent<TData>` | Event + IEventPosition + column info |
|
|
295
|
+
| `ICalendarFilters` | `{ scheduleTypeIds?, resourceIds?, search?, showCanceled?, dateRange?, [key]: unknown }` |
|
|
296
|
+
| `TSelectionMode` | `'time'│'day'` |
|
|
297
|
+
| `TEventDetailMode` | `'popover'│'dialog'│'sheet'│'custom'` — controls how event details are shown |
|
|
298
|
+
| `ICalendarHeaderConfig` | Object with 7 optional boolean keys controlling header section visibility |
|
|
299
|
+
|
|
300
|
+
### Callback Types
|
|
301
|
+
|
|
302
|
+
| Type | Signature |
|
|
303
|
+
|---|---|
|
|
304
|
+
| `TOnEventClick<TData>` | `(event, e?) => void` |
|
|
305
|
+
| `TOnSlotSelect` | `(selection: ISelectionResult) => void` |
|
|
306
|
+
| `TOnEventDrop<TData>` | `(event, newStart, newEnd, newResourceId?) => void` |
|
|
307
|
+
| `TOnEventResize<TData>` | `(event, newStart, newEnd) => void` |
|
|
308
|
+
| `TOnViewChange` | `(view: TCalendarView) => void` |
|
|
309
|
+
| `TOnDateChange` | `(date: Date) => void` |
|
|
310
|
+
| `TOnFiltersChange` | `(filters: ICalendarFilters) => void` |
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 5. InnoCalendar Props
|
|
315
|
+
|
|
316
|
+
`<InnoCalendar>` is the primary entry point. It wraps `InnoCalendarProvider` + `SlotSelectionProvider` + `DragDropProvider` internally.
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
interface InnoCalendarProps<TEventData> {
|
|
320
|
+
// === DATA ===
|
|
321
|
+
events: CalendarEvent<TEventData>[];
|
|
322
|
+
users?: ICalendarUser[];
|
|
323
|
+
scheduleTypes?: IScheduleType[];
|
|
324
|
+
|
|
325
|
+
// === INITIAL STATE ===
|
|
326
|
+
initialView?: TCalendarView; // default: 'week'
|
|
327
|
+
initialDate?: Date; // default: new Date()
|
|
328
|
+
initialSelectedUserId?: string | 'all'; // default: 'all'
|
|
329
|
+
initialScheduleTypeIds?: number[];
|
|
330
|
+
initialParticipantIds?: string[];
|
|
331
|
+
initialWorkingHoursView?: 'default' | 'enabled' | 'disabled';
|
|
332
|
+
initialSearchQuery?: string;
|
|
333
|
+
|
|
334
|
+
// === PREFERENCES ===
|
|
335
|
+
preferencesConfig?: IPreferencesConfig;
|
|
336
|
+
|
|
337
|
+
// === CALLBACKS ===
|
|
338
|
+
onEventClick?: (event: CalendarEvent<TEventData>) => void;
|
|
339
|
+
onSlotClick?: (date: Date, hour?: number) => void;
|
|
340
|
+
onSlotSelect?: (selection: ISelectionResult) => void;
|
|
341
|
+
onAddEvent?: () => void;
|
|
342
|
+
onEventDrop?: (result: IDropResult<TEventData>) => void;
|
|
343
|
+
onDateChange?: (date: Date, view: TCalendarView) => void;
|
|
344
|
+
onViewChange?: (view: TCalendarView) => void;
|
|
345
|
+
|
|
346
|
+
// === UI OPTIONS ===
|
|
347
|
+
className?: string;
|
|
348
|
+
showHeader?: boolean; // default: true
|
|
349
|
+
minSelectionMinutes?: number; // default: 30
|
|
350
|
+
showMoreMode?: 'dayView' | 'popover' | 'expand'; // default: 'expand'
|
|
351
|
+
isLoading?: boolean; // default: false
|
|
352
|
+
|
|
353
|
+
// === CUSTOM RENDERING ===
|
|
354
|
+
renderPopover?: (props: { event; onClose }) => ReactNode;
|
|
355
|
+
slots?: ICalendarSlots<TEventData>;
|
|
356
|
+
classNames?: ICalendarClassNames;
|
|
357
|
+
|
|
358
|
+
// === HEADER CONFIGURATION ===
|
|
359
|
+
headerConfig?: ICalendarHeaderConfig; // fine-grained header visibility
|
|
360
|
+
// see ICalendarHeaderConfig below
|
|
361
|
+
|
|
362
|
+
// === EVENT DETAIL MODE ===
|
|
363
|
+
eventDetailMode?: TEventDetailMode; // default: 'popover'
|
|
364
|
+
renderEventDetail?: (props: { event; onClose }) => ReactNode; // for 'custom' + override in dialog/sheet
|
|
365
|
+
|
|
366
|
+
// === CONTENT SLOTS ===
|
|
367
|
+
settingsContent?: ReactNode;
|
|
368
|
+
filterContent?: ReactNode;
|
|
369
|
+
headerActions?: ReactNode;
|
|
370
|
+
|
|
371
|
+
// === DEEP LINKING ===
|
|
372
|
+
focusEventId?: string | null;
|
|
373
|
+
|
|
374
|
+
// @deprecated — use showMoreMode instead
|
|
375
|
+
showMoreEventsInPopover?: boolean;
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
#### ICalendarHeaderConfig
|
|
380
|
+
|
|
381
|
+
Fine-grained visibility control for calendar header sections. Each key defaults to `true` when omitted.
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
interface ICalendarHeaderConfig {
|
|
385
|
+
showToday?: boolean; // Today button
|
|
386
|
+
showDateNavigator?: boolean; // Prev/Next arrows + date label
|
|
387
|
+
showCalendarViews?: boolean; // Day/Week/Month/Agenda dropdown
|
|
388
|
+
showResourceViews?: boolean; // Timeline/Resource dropdown
|
|
389
|
+
showSettings?: boolean; // Settings gear icon
|
|
390
|
+
showAddEvent?: boolean; // "+" add event button
|
|
391
|
+
showFilters?: boolean; // Filter row below header
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
#### TEventDetailMode
|
|
396
|
+
|
|
397
|
+
Controls how event details are displayed when clicking an event:
|
|
398
|
+
|
|
399
|
+
- `'popover'` — Radix popover anchored to the event card (default)
|
|
400
|
+
- `'dialog'` — Centered modal dialog overlay
|
|
401
|
+
- `'sheet'` — Slide-in side panel from the right
|
|
402
|
+
- `'custom'` — No built-in container; delegates to `renderEventDetail`
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
type TEventDetailMode = 'popover' | 'dialog' | 'sheet' | 'custom';
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Ref Support
|
|
409
|
+
|
|
410
|
+
`InnoCalendar` is wrapped with `forwardRef` and exposes `ICalendarRefHandle`:
|
|
411
|
+
|
|
412
|
+
```tsx
|
|
413
|
+
const calendarRef = useRef<ICalendarRefHandle>(null);
|
|
414
|
+
<InnoCalendar ref={calendarRef} events={events} />
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## 6. Slots System
|
|
420
|
+
|
|
421
|
+
Every visual region can be replaced via `slots`:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
interface ICalendarSlots<TEventData, TScheduleTypeData, TResourceData> {
|
|
425
|
+
// Structural
|
|
426
|
+
header?: ComponentType<IHeaderSlotProps>;
|
|
427
|
+
footer?: ComponentType<IFooterSlotProps<TEventData>>;
|
|
428
|
+
viewWrapper?: ComponentType<IViewWrapperSlotProps>;
|
|
429
|
+
|
|
430
|
+
// Day Cell (month/year views)
|
|
431
|
+
dayCell?: ComponentType<IDayCellSlotPropsExtended<TEventData>>;
|
|
432
|
+
dayCellHeader?: ComponentType<IDayCellAdornmentSlotProps<TEventData>>;
|
|
433
|
+
dayCellFooter?: ComponentType<IDayCellAdornmentSlotProps<TEventData>>;
|
|
434
|
+
dayCellStartAdornment?: ComponentType<IDayCellAdornmentSlotProps<TEventData>>;
|
|
435
|
+
dayCellEndAdornment?: ComponentType<IDayCellAdornmentSlotProps<TEventData>>;
|
|
436
|
+
|
|
437
|
+
// Time Grid (day/week views)
|
|
438
|
+
timeGutter?: ComponentType<ITimeGutterSlotProps>;
|
|
439
|
+
timeSlotBackground?: ComponentType<ITimeSlotBackgroundSlotProps>;
|
|
440
|
+
columnHeader?: ComponentType<IColumnHeaderSlotProps>;
|
|
441
|
+
currentTimeIndicator?: ComponentType<ICurrentTimeIndicatorSlotProps>;
|
|
442
|
+
multiDayBanner?: ComponentType<IMultiDayBannerSlotProps<TEventData>>;
|
|
443
|
+
|
|
444
|
+
// Events
|
|
445
|
+
eventCard?: ComponentType<IEventCardSlotProps<TEventData>>;
|
|
446
|
+
eventPopover?: ComponentType<IEventPopoverSlotProps<TEventData>>;
|
|
447
|
+
|
|
448
|
+
// Resource/Timeline
|
|
449
|
+
resourceHeader?: ComponentType<IResourceHeaderSlotProps<TResourceData>>;
|
|
450
|
+
rowHeader?: ComponentType<IRowHeaderSlotProps<TResourceData>>;
|
|
451
|
+
|
|
452
|
+
// Filters
|
|
453
|
+
filter?: ComponentType<IFilterSlotProps<TScheduleTypeData>>;
|
|
454
|
+
|
|
455
|
+
// Empty States
|
|
456
|
+
emptyCell?: ComponentType<IEmptyCellSlotProps>;
|
|
457
|
+
emptyState?: ComponentType<IEmptyStateSlotProps>;
|
|
458
|
+
|
|
459
|
+
// @deprecated
|
|
460
|
+
timeSlot?: ComponentType<ITimeSlotSlotProps>;
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Slot Props Interfaces
|
|
465
|
+
|
|
466
|
+
| Slot | Props Interface | Key Fields |
|
|
467
|
+
|---|---|---|
|
|
468
|
+
| `header` | `IHeaderSlotProps` | currentDate, view, onNavigate, onViewChange |
|
|
469
|
+
| `footer` | `IFooterSlotProps` | view, currentDate, events |
|
|
470
|
+
| `viewWrapper` | `IViewWrapperSlotProps` | view, children |
|
|
471
|
+
| `dayCell` | `IDayCellSlotPropsExtended` | date, events, isToday, isCurrentMonth, isWeekend, view, children, onDayClick |
|
|
472
|
+
| `dayCellHeader/Footer` | `IDayCellAdornmentSlotProps` | date, events, isToday, isCurrentMonth, isWeekend, view |
|
|
473
|
+
| `timeGutter` | `ITimeGutterSlotProps` | hour, formattedLabel, isFirst |
|
|
474
|
+
| `timeSlotBackground` | `ITimeSlotBackgroundSlotProps` | date, hour, minute, isWorkingHour, isToday |
|
|
475
|
+
| `columnHeader` | `IColumnHeaderSlotProps` | date, isToday, onDayClick, columnIndex |
|
|
476
|
+
| `currentTimeIndicator` | `ICurrentTimeIndicatorSlotProps` | currentTime, topOffset |
|
|
477
|
+
| `multiDayBanner` | `IMultiDayBannerSlotProps` | events, rangeStart, onEventClick |
|
|
478
|
+
| `eventCard` | `IEventCardSlotProps` | event, view, isCompact, onClick |
|
|
479
|
+
| `eventPopover` | `IEventPopoverSlotProps` | event, onClose, onEdit, onDelete |
|
|
480
|
+
| `resourceHeader` | `IResourceHeaderSlotProps` | resource |
|
|
481
|
+
| `rowHeader` | `IRowHeaderSlotProps` | resource, rowIndex |
|
|
482
|
+
| `filter` | `IFilterSlotProps` | scheduleTypes, filters, onFiltersChange |
|
|
483
|
+
| `emptyCell` | `IEmptyCellSlotProps` | date, isToday |
|
|
484
|
+
| `emptyState` | `IEmptyStateSlotProps` | view, dateRange |
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## 7. ClassNames API
|
|
489
|
+
|
|
490
|
+
`ICalendarClassNames` provides 34 CSS class override keys. Classes are merged with defaults via `cn()`.
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
interface ICalendarClassNames {
|
|
494
|
+
// Structural
|
|
495
|
+
root?: string;
|
|
496
|
+
header?: string;
|
|
497
|
+
footer?: string;
|
|
498
|
+
viewContainer?: string;
|
|
499
|
+
|
|
500
|
+
// Month View
|
|
501
|
+
monthGrid?: string;
|
|
502
|
+
weekdayHeader?: string;
|
|
503
|
+
weekdayLabel?: string;
|
|
504
|
+
dayCell?: string;
|
|
505
|
+
dayCellToday?: string;
|
|
506
|
+
dayCellOutside?: string;
|
|
507
|
+
dayCellWeekend?: string;
|
|
508
|
+
dayCellNumber?: string;
|
|
509
|
+
dayCellContent?: string;
|
|
510
|
+
dayCellFooter?: string;
|
|
511
|
+
|
|
512
|
+
// Week/Day View
|
|
513
|
+
timeGutter?: string;
|
|
514
|
+
timeGutterLabel?: string;
|
|
515
|
+
timeSlot?: string;
|
|
516
|
+
timeSlotWorking?: string;
|
|
517
|
+
timeSlotNonWorking?: string;
|
|
518
|
+
columnHeader?: string;
|
|
519
|
+
columnHeaderToday?: string;
|
|
520
|
+
currentTimeIndicator?: string;
|
|
521
|
+
scrollContainer?: string;
|
|
522
|
+
|
|
523
|
+
// Events
|
|
524
|
+
eventCard?: string;
|
|
525
|
+
eventCardCompact?: string;
|
|
526
|
+
eventPopover?: string;
|
|
527
|
+
multiDayBanner?: string;
|
|
528
|
+
moreEventsIndicator?: string;
|
|
529
|
+
|
|
530
|
+
// Timeline
|
|
531
|
+
resourceHeader?: string;
|
|
532
|
+
resourceRow?: string;
|
|
533
|
+
timelineCell?: string;
|
|
534
|
+
|
|
535
|
+
// Agenda
|
|
536
|
+
agendaList?: string;
|
|
537
|
+
agendaDayGroup?: string;
|
|
538
|
+
agendaDayHeader?: string;
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## 8. EventCard & EventBlock
|
|
545
|
+
|
|
546
|
+
Located in `src/components/event/event-card.tsx`.
|
|
547
|
+
|
|
548
|
+
### EventCard
|
|
549
|
+
|
|
550
|
+
Full-size event card used in day/week/timeline views. Renders differently based on `badgeVariant`:
|
|
551
|
+
|
|
552
|
+
| Badge Variant | Rendering |
|
|
553
|
+
|---|---|
|
|
554
|
+
| `'colored'` | Filled background with accent color, white/dark text |
|
|
555
|
+
| `'dot'` | White background with colored left-border accent |
|
|
556
|
+
| `'mixed'` | Light tinted background with colored left-border |
|
|
557
|
+
|
|
558
|
+
Key props:
|
|
559
|
+
|
|
560
|
+
| Prop | Type | Default | Description |
|
|
561
|
+
|---|---|---|---|
|
|
562
|
+
| `event` | `CalendarEvent<TData>` | required | Event data |
|
|
563
|
+
| `variant` | `'full'\|'compact'\|'dot'` | `'full'` | Visual layout |
|
|
564
|
+
| `badgeVariant` | `TBadgeVariant` | `'colored'` | Color treatment |
|
|
565
|
+
| `onClick` | `(event) => void` | — | Click callback |
|
|
566
|
+
| `showTime` | `boolean` | `true` | Show time display |
|
|
567
|
+
| `showDescription` | `boolean` | `false` | Show event description |
|
|
568
|
+
| `showParticipants` | `boolean` | `false` | Show participant avatars |
|
|
569
|
+
| `disablePopover` | `boolean` | `false` | Skip built-in popover, fire `onClick` |
|
|
570
|
+
| `renderPopover` | `(props) => ReactNode` | — | Custom content inside the default popover shell |
|
|
571
|
+
| `enableDrag` | `boolean` | `false` | Enable HTML5 drag & drop |
|
|
572
|
+
| `enablePageTransition` | `boolean` | `false` | Enable page transition animation |
|
|
573
|
+
| `pageTransitionDuration` | `number` | `400` | Page transition duration in ms |
|
|
574
|
+
| `eventDetailMode` | `TEventDetailMode` | `'popover'` | Container for event details: popover, dialog, sheet, custom |
|
|
575
|
+
| `renderEventDetail` | `(props) => ReactNode` | — | Custom renderer for 'custom' mode; also inner content for dialog/sheet |
|
|
576
|
+
| `style` | `CSSProperties` | — | Inline styles |
|
|
577
|
+
| `className` | `string` | — | Additional CSS classes |
|
|
578
|
+
|
|
579
|
+
Built-in cards display enrichment data read from `event.data` first, with fallback to deprecated top-level fields:
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
// Runtime enrichment reading pattern:
|
|
583
|
+
const eventData = event.data as Record<string, unknown> | undefined;
|
|
584
|
+
const meetingTookPlace = (eventData?.meetingTookPlace as boolean) ?? event.meetingTookPlace ?? false;
|
|
585
|
+
const typeName = eventData?.typeName as string | undefined;
|
|
586
|
+
const siteName = eventData?.siteName as string | undefined;
|
|
587
|
+
const nrParticipant = eventData?.nrParticipant as number | undefined;
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### EventBlock
|
|
591
|
+
|
|
592
|
+
Positioned event block for day/week time grid. Renders with absolute positioning inside the time column.
|
|
593
|
+
|
|
594
|
+
### MultiDayEventBar
|
|
595
|
+
|
|
596
|
+
Horizontal bar for multi-day/all-day events in the banner strip above day/week time grids.
|
|
597
|
+
|
|
598
|
+
### Exports
|
|
599
|
+
|
|
600
|
+
```typescript
|
|
601
|
+
export { EventCard, type EventCardProps }
|
|
602
|
+
export { EventBlock, type EventBlockProps }
|
|
603
|
+
export { MultiDayEventBar, type MultiDayEventBarProps }
|
|
604
|
+
export { getEventColorClasses } // Utility: TEventColor → { bg, text, border }
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## 9. EventPopover Component
|
|
610
|
+
|
|
611
|
+
Located in `src/components/event/event-popover.tsx` (~1400 lines).
|
|
612
|
+
|
|
613
|
+
Full-featured event detail popover with action buttons, participant list, and domain data display.
|
|
614
|
+
|
|
615
|
+
### Key Props
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
interface EventPopoverProps<TData = Record<string, unknown>> {
|
|
619
|
+
event: IPopoverEvent<TData>;
|
|
620
|
+
children: ReactNode;
|
|
621
|
+
open?: boolean;
|
|
622
|
+
onOpenChange?: (open: boolean) => void;
|
|
623
|
+
isLoading?: boolean;
|
|
624
|
+
|
|
625
|
+
// Action callbacks
|
|
626
|
+
onEdit?: (event: IPopoverEvent<TData>) => void;
|
|
627
|
+
onDelete?: (event: IPopoverEvent<TData>) => void;
|
|
628
|
+
onCancel?: (event: IPopoverEvent<TData>) => void;
|
|
629
|
+
onAccept?: (event: IPopoverEvent<TData>) => void;
|
|
630
|
+
onDecline?: (event: IPopoverEvent<TData>) => void;
|
|
631
|
+
onConfirmMeeting?: (event: IPopoverEvent<TData>) => void;
|
|
632
|
+
|
|
633
|
+
// Permission flags
|
|
634
|
+
canEdit?: boolean;
|
|
635
|
+
canDelete?: boolean;
|
|
636
|
+
canCancel?: boolean;
|
|
637
|
+
|
|
638
|
+
// Current user state
|
|
639
|
+
isCurrentUserParticipant?: boolean;
|
|
640
|
+
isCurrentUserClient?: boolean;
|
|
641
|
+
currentUserAcceptStatus?: boolean | null;
|
|
642
|
+
|
|
643
|
+
// Loading states
|
|
644
|
+
isAcceptLoading?: boolean;
|
|
645
|
+
isDeclineLoading?: boolean;
|
|
646
|
+
isConfirmLoading?: boolean;
|
|
647
|
+
isDeleteLoading?: boolean;
|
|
648
|
+
|
|
649
|
+
// Render customization
|
|
650
|
+
renderParticipant?: (participant: IEventParticipant, index: number) => ReactNode;
|
|
651
|
+
renderHeaderActions?: (props: { onClose: () => void }) => ReactNode;
|
|
652
|
+
renderCancelReason?: (event: IPopoverEvent<TData>) => ReactNode;
|
|
653
|
+
renderDeleteConfirmation?: (props: {
|
|
654
|
+
onConfirm: () => void;
|
|
655
|
+
onCancel: () => void;
|
|
656
|
+
isLoading?: boolean;
|
|
657
|
+
}) => ReactNode;
|
|
658
|
+
|
|
659
|
+
// Formatting
|
|
660
|
+
formatDate?: (date: Date, format?: string) => string;
|
|
661
|
+
formatTimeRange?: (start: Date, end: Date) => string;
|
|
662
|
+
|
|
663
|
+
// Styling
|
|
664
|
+
className?: string;
|
|
665
|
+
width?: number;
|
|
666
|
+
|
|
667
|
+
// i18n labels
|
|
668
|
+
labels?: Partial<IEventPopoverLabels>;
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### IEventPopoverLabels
|
|
673
|
+
|
|
674
|
+
All label strings are customizable for i18n:
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
interface IEventPopoverLabels {
|
|
678
|
+
edit?: string;
|
|
679
|
+
delete?: string;
|
|
680
|
+
cancel?: string;
|
|
681
|
+
close?: string;
|
|
682
|
+
going?: string;
|
|
683
|
+
notGoing?: string;
|
|
684
|
+
confirmMeeting?: string;
|
|
685
|
+
completed?: string;
|
|
686
|
+
canceled?: string;
|
|
687
|
+
participants?: string;
|
|
688
|
+
guest?: string;
|
|
689
|
+
guests?: string;
|
|
690
|
+
confirmed?: string;
|
|
691
|
+
organizer?: string;
|
|
692
|
+
client?: string;
|
|
693
|
+
more?: string;
|
|
694
|
+
noDateProvided?: string;
|
|
695
|
+
eventNotFound?: string;
|
|
696
|
+
cancellationNote?: string;
|
|
697
|
+
canceledOn?: string;
|
|
698
|
+
acceptThisEvent?: string;
|
|
699
|
+
acceptAllEvents?: string;
|
|
700
|
+
deleteConfirmTitle?: string;
|
|
701
|
+
deleteConfirmDescription?: string;
|
|
702
|
+
}
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
## 10. Preferences System
|
|
708
|
+
|
|
709
|
+
Located in `src/core/preferences/`.
|
|
710
|
+
|
|
711
|
+
### IPreferencesConfig
|
|
712
|
+
|
|
713
|
+
Passed via `<InnoCalendar preferencesConfig={...}>`:
|
|
714
|
+
|
|
715
|
+
```typescript
|
|
716
|
+
interface IPreferencesConfig {
|
|
717
|
+
modes?: TPreferenceModes; // Per-key control mode
|
|
718
|
+
locked?: TLockedPreferences; // Values for locked preferences
|
|
719
|
+
defaults?: TPartialPreferences; // Custom defaults
|
|
720
|
+
storageKey?: string; // Custom localStorage key
|
|
721
|
+
disableStorage?: boolean; // Disable localStorage entirely
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
### Preference Modes
|
|
726
|
+
|
|
727
|
+
| Mode | Behavior |
|
|
728
|
+
|---|---|
|
|
729
|
+
| `'user'` | User can modify, persisted to localStorage (default) |
|
|
730
|
+
| `'locked'` | Developer-controlled, user cannot modify |
|
|
731
|
+
| `'session'` | User can modify during session, not persisted |
|
|
732
|
+
|
|
733
|
+
### IPreferences
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
interface IPreferences {
|
|
737
|
+
view: TCalendarView;
|
|
738
|
+
badgeVariant: TBadgeVariant;
|
|
739
|
+
slotDuration: TSlotDuration;
|
|
740
|
+
visibleHours: IVisibleHoursConfig; // { from: number; to: number }
|
|
741
|
+
workingHours: TWorkingHoursConfig; // { [dayIndex]: { from, to } }
|
|
742
|
+
showWorkingHoursOnly: boolean;
|
|
743
|
+
showWeekends: boolean;
|
|
744
|
+
firstDayOfWeek: 0|1|2|3|4|5|6;
|
|
745
|
+
}
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
### useCalendarPreferences Hook
|
|
749
|
+
|
|
750
|
+
Returns `IUsePreferencesReturn`:
|
|
751
|
+
|
|
752
|
+
```typescript
|
|
753
|
+
interface IUsePreferencesReturn {
|
|
754
|
+
preferences: IPreferences;
|
|
755
|
+
setPreference: <K extends TPreferenceKey>(key: K, value: IPreferences[K]) => void;
|
|
756
|
+
setPreferences: (updates: TPartialPreferences) => void;
|
|
757
|
+
resetPreferences: () => void;
|
|
758
|
+
resetPreference: (key: TPreferenceKey) => void;
|
|
759
|
+
isLocked: (key: TPreferenceKey) => boolean;
|
|
760
|
+
isPersisted: (key: TPreferenceKey) => boolean;
|
|
761
|
+
getMode: (key: TPreferenceKey) => TPreferenceMode;
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
### Example: Locking slot duration
|
|
766
|
+
|
|
767
|
+
```tsx
|
|
768
|
+
<InnoCalendar
|
|
769
|
+
events={events}
|
|
770
|
+
preferencesConfig={{
|
|
771
|
+
modes: { slotDuration: 'locked' },
|
|
772
|
+
locked: { slotDuration: 30 },
|
|
773
|
+
}}
|
|
774
|
+
/>
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
---
|
|
778
|
+
|
|
779
|
+
## 11. Widget Components
|
|
780
|
+
|
|
781
|
+
Located in `src/components/widget/`.
|
|
782
|
+
|
|
783
|
+
### AgendaWidget
|
|
784
|
+
|
|
785
|
+
Embeddable agenda card for dashboards. Can work standalone or tap into an existing `InnoCalendarProvider`.
|
|
786
|
+
|
|
787
|
+
```typescript
|
|
788
|
+
interface AgendaWidgetProps {
|
|
789
|
+
events: CalendarEvent[];
|
|
790
|
+
maxItems?: number;
|
|
791
|
+
onEventClick?: (event: CalendarEvent) => void;
|
|
792
|
+
className?: string;
|
|
793
|
+
// ... additional display options
|
|
794
|
+
}
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### AgendaDropdown
|
|
798
|
+
|
|
799
|
+
Bell-style notification dropdown for upcoming events:
|
|
800
|
+
|
|
801
|
+
```typescript
|
|
802
|
+
interface AgendaDropdownProps {
|
|
803
|
+
events: CalendarEvent[];
|
|
804
|
+
onEventClick?: (event: CalendarEvent) => void;
|
|
805
|
+
className?: string;
|
|
806
|
+
// ... trigger customization
|
|
807
|
+
}
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
---
|
|
811
|
+
|
|
812
|
+
## 12. Filter Components
|
|
813
|
+
|
|
814
|
+
Located in `src/components/filters/`.
|
|
815
|
+
|
|
816
|
+
### CalendarFilterSidebar
|
|
817
|
+
|
|
818
|
+
Full filter panel with schedule type and user filters:
|
|
819
|
+
|
|
820
|
+
```typescript
|
|
821
|
+
interface CalendarFilterSidebarProps {
|
|
822
|
+
scheduleTypes: IScheduleTypeOption[];
|
|
823
|
+
users: IUserOption[];
|
|
824
|
+
labels?: CalendarFilterSidebarLabels;
|
|
825
|
+
// Controlled state or context-driven
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
### ScheduleTypeFilter
|
|
830
|
+
|
|
831
|
+
Standalone schedule type filter component with checkbox list.
|
|
832
|
+
|
|
833
|
+
### UserFilter
|
|
834
|
+
|
|
835
|
+
Standalone user/participant filter with avatar support.
|
|
836
|
+
|
|
837
|
+
---
|
|
838
|
+
|
|
839
|
+
## 13. Settings Components
|
|
840
|
+
|
|
841
|
+
Located in `src/components/settings/`.
|
|
842
|
+
|
|
843
|
+
| Component | Props | What It Controls |
|
|
844
|
+
|---|---|---|
|
|
845
|
+
| `BadgeVariantSetting` | `BadgeVariantSettingProps` | Dot / Colored / Mixed badge display |
|
|
846
|
+
| `SlotDurationSetting` | `SlotDurationSettingProps` | 15 / 30 / 60 minute time slot granularity |
|
|
847
|
+
| `VisibleHoursSetting` | `VisibleHoursSettingProps` | Start/end hour range for day/week views |
|
|
848
|
+
| `WorkingHoursSetting` | `WorkingHoursSettingProps` | Per-day working hours with enable/disable toggle |
|
|
849
|
+
|
|
850
|
+
All settings components read/write preferences through the preferences context.
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
## 14. Context & Hooks
|
|
855
|
+
|
|
856
|
+
### Context Providers
|
|
857
|
+
|
|
858
|
+
| Provider | Purpose |
|
|
859
|
+
|---|---|
|
|
860
|
+
| `InnoCalendarProvider` | Main state: events, date, view, filters, search, preferences, time config |
|
|
861
|
+
| `CalendarProvider` | Lower-level provider (used by `Calendar` component) |
|
|
862
|
+
| `SlotSelectionProvider` | Drag-to-select state management |
|
|
863
|
+
| `DragDropProvider` | Event drag-and-drop state management |
|
|
864
|
+
|
|
865
|
+
### Primary Hooks
|
|
866
|
+
|
|
867
|
+
| Hook | Return Type | Purpose |
|
|
868
|
+
|---|---|---|
|
|
869
|
+
| `useInnoCalendar()` | `IInnoCalendarContext` | Full context access (events, view, date, filters, search, preferences) |
|
|
870
|
+
| `useCalendarContext()` | `IInnoCalendarContext` | Alias for `useInnoCalendar` |
|
|
871
|
+
| `useCalendar()` | `UseCalendarReturn` | Core calendar state (date, view, navigation, event helpers) |
|
|
872
|
+
| `useSlotSelection()` | `UseSlotSelectionReturn` | Drag-to-select hook |
|
|
873
|
+
| `useCalendarTimeConfig()` | `UseCalendarTimeConfigReturn` | Slot duration, visible hours, working hours |
|
|
874
|
+
| `usePreferences()` | `UsePreferencesReturn` | Basic preferences hook |
|
|
875
|
+
| `useAdvancedPreferences()` | `IUsePreferencesReturn` | Full preferences with locking support |
|
|
876
|
+
| `useDragDrop()` | `IDragDropContext` | Drag-drop state and handlers |
|
|
877
|
+
|
|
878
|
+
### Selective Context Hooks
|
|
879
|
+
|
|
880
|
+
These read only a slice of the context for performance:
|
|
881
|
+
|
|
882
|
+
| Hook | Returns |
|
|
883
|
+
|---|---|
|
|
884
|
+
| `useCalendarDate()` | Current date + navigation |
|
|
885
|
+
| `useCalendarView()` | Current view + view change |
|
|
886
|
+
| `useCalendarEvents()` | Events array + setEvents |
|
|
887
|
+
| `useCalendarFilters()` | Filter state + setters |
|
|
888
|
+
| `useCalendarPreferences()` | Preferences from context |
|
|
889
|
+
| `useInnoCalendarView()` | View from InnoCalendar context |
|
|
890
|
+
| `useInnoCalendarEvents()` | Events from InnoCalendar context |
|
|
891
|
+
| `useInnoCalendarFilters()` | Filters from InnoCalendar context |
|
|
892
|
+
| `useInnoCalendarTimeConfig()` | Time config from InnoCalendar context |
|
|
893
|
+
|
|
894
|
+
### Optional Hooks (no throw if outside provider)
|
|
895
|
+
|
|
896
|
+
| Hook | Returns |
|
|
897
|
+
|---|---|
|
|
898
|
+
| `useOptionalCalendar()` | `context │ undefined` |
|
|
899
|
+
| `useOptionalCalendarContext()` | `context │ undefined` |
|
|
900
|
+
| `useOptionalInnoCalendar()` | `context │ undefined` |
|
|
901
|
+
| `useOptionalDragDrop()` | `context │ undefined` |
|
|
902
|
+
| `useOptionalSlotSelection()` | `context │ undefined` |
|
|
903
|
+
|
|
904
|
+
### Legacy Aliases (backward compat)
|
|
905
|
+
|
|
906
|
+
| Alias | Maps To |
|
|
907
|
+
|---|---|
|
|
908
|
+
| `IntegratedCalendarProvider` | `InnoCalendarProvider` |
|
|
909
|
+
| `useIntegratedCalendar()` | `useInnoCalendar()` |
|
|
910
|
+
| `useIntegratedCalendarEvents()` | `useInnoCalendarEvents()` |
|
|
911
|
+
| `useIntegratedCalendarFilters()` | `useInnoCalendarFilters()` |
|
|
912
|
+
| `useIntegratedCalendarView()` | `useInnoCalendarView()` |
|
|
913
|
+
| `useIntegratedCalendarTimeConfig()` | `useInnoCalendarTimeConfig()` |
|
|
914
|
+
| `useOptionalIntegratedCalendar()` | `useOptionalInnoCalendar()` |
|
|
915
|
+
| `IntegratedCalendar` | `InnoCalendar` |
|
|
916
|
+
|
|
917
|
+
---
|
|
918
|
+
|
|
919
|
+
## 15. Drag & Drop
|
|
920
|
+
|
|
921
|
+
Located in `src/core/context/drag-drop-context.tsx`.
|
|
922
|
+
|
|
923
|
+
### DragDropProvider
|
|
924
|
+
|
|
925
|
+
Manages drag state for event repositioning. Wraps the calendar tree automatically when using `<InnoCalendar>`.
|
|
926
|
+
|
|
927
|
+
```typescript
|
|
928
|
+
interface IDragState<TData = Record<string, unknown>> {
|
|
929
|
+
event: CalendarEvent<TData>;
|
|
930
|
+
originalStartDate: Date;
|
|
931
|
+
originalEndDate: Date;
|
|
932
|
+
previewDate?: Date; // current preview position
|
|
933
|
+
previewHour?: number; // for time-based views
|
|
934
|
+
previewMinute?: number;
|
|
935
|
+
originalResourceId?: string; // for resource/timeline views
|
|
936
|
+
targetResourceId?: string; // current drag target resource
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
interface IDropResult<TData = Record<string, unknown>> {
|
|
940
|
+
event: CalendarEvent<TData>;
|
|
941
|
+
newStartDate: Date;
|
|
942
|
+
newEndDate: Date; // maintains original duration
|
|
943
|
+
newResourceId?: string; // set when dropped on different resource
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
interface IDragDropContext<TData = Record<string, unknown>> {
|
|
947
|
+
dragState: IDragState<TData> | null;
|
|
948
|
+
isDragging: boolean;
|
|
949
|
+
startDrag: (event: CalendarEvent<any>) => void;
|
|
950
|
+
updateDragPreview: (date: Date, hour?: number, minute?: number, resourceId?: string) => void;
|
|
951
|
+
endDrag: () => IDropResult<TData> | null;
|
|
952
|
+
cancelDrag: () => void;
|
|
953
|
+
}
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
### Timeline / Resource View Drag & Drop
|
|
957
|
+
|
|
958
|
+
`TimelineView` supports HTML5 drag & drop out of the box:
|
|
959
|
+
|
|
960
|
+
- Events render with `enableDrag={true}` by default
|
|
961
|
+
- Each resource row acts as a drop zone
|
|
962
|
+
- Dragging across rows updates `targetResourceId` in the drag state
|
|
963
|
+
- Dropping calls `endDrag()` which fires `onEventDrop` on `DragDropProvider`
|
|
964
|
+
|
|
965
|
+
```tsx
|
|
966
|
+
<InnoCalendar
|
|
967
|
+
events={events}
|
|
968
|
+
initialView="timeline-week"
|
|
969
|
+
onEventDrop={(result) => {
|
|
970
|
+
console.log(result.event.id, result.newStartDate, result.newResourceId);
|
|
971
|
+
// Update your backend
|
|
972
|
+
}}
|
|
973
|
+
/>
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
---
|
|
977
|
+
|
|
978
|
+
## 16. Core Utilities
|
|
979
|
+
|
|
980
|
+
Located in `src/core/utils/`. All exported from `src/core/utils/index.ts`.
|
|
981
|
+
|
|
982
|
+
### date-utils.ts
|
|
983
|
+
|
|
984
|
+
Date manipulation using native Date API:
|
|
985
|
+
|
|
986
|
+
| Function | Signature |
|
|
987
|
+
|---|---|
|
|
988
|
+
| `startOfDay` | `(date: Date) => Date` |
|
|
989
|
+
| `endOfDay` | `(date: Date) => Date` |
|
|
990
|
+
| `startOfWeek` | `(date: Date, weekStartsOn?: 0\|1\|2\|3\|4\|5\|6) => Date` |
|
|
991
|
+
| `endOfWeek` | `(date: Date, weekStartsOn?: 0\|1\|2\|3\|4\|5\|6) => Date` |
|
|
992
|
+
| `startOfMonth` | `(date: Date) => Date` |
|
|
993
|
+
| `endOfMonth` | `(date: Date) => Date` |
|
|
994
|
+
| `startOfYear` | `(date: Date) => Date` |
|
|
995
|
+
| `endOfYear` | `(date: Date) => Date` |
|
|
996
|
+
| `addDays` | `(date: Date, days: number) => Date` |
|
|
997
|
+
| `subDays` | `(date: Date, days: number) => Date` |
|
|
998
|
+
| `addWeeks` | `(date: Date, weeks: number) => Date` |
|
|
999
|
+
| `subWeeks` | `(date: Date, weeks: number) => Date` |
|
|
1000
|
+
| `addMonths` | `(date: Date, months: number) => Date` |
|
|
1001
|
+
| `subMonths` | `(date: Date, months: number) => Date` |
|
|
1002
|
+
| `addYears` | `(date: Date, years: number) => Date` |
|
|
1003
|
+
| `subYears` | `(date: Date, years: number) => Date` |
|
|
1004
|
+
| `addHours` | `(date: Date, hours: number) => Date` |
|
|
1005
|
+
| `addMinutes` | `(date: Date, minutes: number) => Date` |
|
|
1006
|
+
| `setTime` | `(date: Date, hours: number, minutes?: number, seconds?: number) => Date` |
|
|
1007
|
+
| `getDecimalHours` | `(date: Date) => number` |
|
|
1008
|
+
| `isSameDay` | `(a: Date, b: Date) => boolean` |
|
|
1009
|
+
| `isSameWeek` | `(a: Date, b: Date, weekStartsOn?) => boolean` |
|
|
1010
|
+
| `isSameMonth` | `(a: Date, b: Date) => boolean` |
|
|
1011
|
+
| `isSameYear` | `(a: Date, b: Date) => boolean` |
|
|
1012
|
+
| `isToday` | `(date: Date) => boolean` |
|
|
1013
|
+
| `isWeekend` | `(date: Date) => boolean` |
|
|
1014
|
+
| `getDayOfWeek` | `(date: Date) => number` |
|
|
1015
|
+
| `isBefore` | `(a: Date, b: Date) => boolean` |
|
|
1016
|
+
| `isAfter` | `(a: Date, b: Date) => boolean` |
|
|
1017
|
+
| `isBetween` | `(date: Date, start: Date, end: Date) => boolean` |
|
|
1018
|
+
| `minDate` | `(dates: Date[]) => Date \| undefined` |
|
|
1019
|
+
| `maxDate` | `(dates: Date[]) => Date \| undefined` |
|
|
1020
|
+
| `differenceInMilliseconds` | `(a: Date, b: Date) => number` |
|
|
1021
|
+
| `differenceInMinutes` | `(a: Date, b: Date) => number` |
|
|
1022
|
+
| `differenceInHours` | `(a: Date, b: Date) => number` |
|
|
1023
|
+
| `differenceInDays` | `(a: Date, b: Date) => number` |
|
|
1024
|
+
| `getWeekDays` | `(date: Date, weekStartsOn?) => Date[]` |
|
|
1025
|
+
| `getWeekNumber` | `(date: Date) => number` |
|
|
1026
|
+
| `getDaysInMonth` | `(date: Date) => number` |
|
|
1027
|
+
| `getYearMonths` | `(year: number) => Date[]` |
|
|
1028
|
+
| `formatTime` | `(date: Date, format?: '12h'\|'24h') => string` |
|
|
1029
|
+
| `formatDateISO` | `(date: Date) => string` |
|
|
1030
|
+
| `formatHourLabel` | `(hour: number, format?: '12h'\|'24h') => string` |
|
|
1031
|
+
| `parseISO` | `(dateString: string) => Date` |
|
|
1032
|
+
| `eachDayOfInterval` | `(start: Date, end: Date) => Date[]` |
|
|
1033
|
+
| `eachHourOfInterval` | `(start: Date, end: Date) => Date[]` |
|
|
1034
|
+
| `getWeekdayNames` | `(locale?, format?) => string[]` |
|
|
1035
|
+
| `getMonthNames` | `(locale?, format?) => string[]` |
|
|
1036
|
+
| `getVisibleHoursArray` | `(visibleHours) => number[]` |
|
|
1037
|
+
| `generateMonthGrid` | `(date: Date, weekStartsOn?) => Array<{ date, isCurrentMonth, isWeekend }>` |
|
|
1038
|
+
| `detectAllDayEvent` | `(event) => boolean` |
|
|
1039
|
+
| `separateEventsByDuration` | `<TEvent>(events) => { singleDay, multiDay }` |
|
|
1040
|
+
| `getEventsInRange` | `<TEvent>(events, rangeStart, rangeEnd) => TEvent[]` |
|
|
1041
|
+
| `isWorkingHour` | `(date, hour, workingHours?) => boolean` |
|
|
1042
|
+
| `getWorkingHoursForDay` | `(date, workingHours) => { from, to } \| null` |
|
|
1043
|
+
|
|
1044
|
+
### event-utils.ts
|
|
1045
|
+
|
|
1046
|
+
Event filtering, sorting, classification, and color utilities:
|
|
1047
|
+
|
|
1048
|
+
| Function | Purpose |
|
|
1049
|
+
|---|---|
|
|
1050
|
+
| `isMultiDayEvent` | Checks if event spans midnight |
|
|
1051
|
+
| `getEventsForDay` | Filters events that overlap a given day |
|
|
1052
|
+
| `getAllDayEvents` | Filters all-day events from array |
|
|
1053
|
+
| `getTimedEvents` | Filters timed (non-all-day) events |
|
|
1054
|
+
| `getMultiDayEvents` | Filters multi-day events |
|
|
1055
|
+
| `filterEventsByDateRange` | Filters events overlapping a date range |
|
|
1056
|
+
| `filterEventsByScheduleType` | Client-side schedule type filter |
|
|
1057
|
+
| `filterEventsByResource` | Client-side resource filter |
|
|
1058
|
+
| `filterEventsBySearch` | Text search across event fields |
|
|
1059
|
+
| `filterOutCanceled` | Remove canceled events |
|
|
1060
|
+
| `applyEventFilters` | Composite filter applying multiple criteria |
|
|
1061
|
+
| `sortEventsByStart` | Sort by start date |
|
|
1062
|
+
| `sortEventsByEnd` | Sort by end date |
|
|
1063
|
+
| `sortEventsByDuration` | Sort by event duration |
|
|
1064
|
+
| `groupEventsByDate` | Groups events by calendar date |
|
|
1065
|
+
| `groupEventsByScheduleType` | Groups events by schedule type |
|
|
1066
|
+
| `groupEventsByResource` | Groups events by resourceId |
|
|
1067
|
+
| `getEventDurationMinutes` | Returns event duration in minutes |
|
|
1068
|
+
| `getEventColor` | Resolves event color with fallback |
|
|
1069
|
+
| `formatEventTimeDisplay` | Formats event time for display |
|
|
1070
|
+
|
|
1071
|
+
### grid-utils.ts
|
|
1072
|
+
|
|
1073
|
+
Grid layout calculations, view navigation, and cell generation:
|
|
1074
|
+
|
|
1075
|
+
| Function | Purpose |
|
|
1076
|
+
|---|---|
|
|
1077
|
+
| `getViewDateRange` | Returns date range for any view |
|
|
1078
|
+
| `navigateNext` | Advance date by one view step |
|
|
1079
|
+
| `navigatePrev` | Go back one view step |
|
|
1080
|
+
| `navigateToday` | Returns today's Date |
|
|
1081
|
+
| `generateMonthCells` | Creates cell array for month grid |
|
|
1082
|
+
| `generateWeekCells` | Creates cell array for week view |
|
|
1083
|
+
| `generateYearCells` | Creates cell array for year view |
|
|
1084
|
+
| `generateTimeSlots` | Creates time slot array for given hour range and slot duration |
|
|
1085
|
+
| `generateHourLabels` | Creates hour label array for gutter |
|
|
1086
|
+
| `getViewTitle` | Formatted title string for current view + date |
|
|
1087
|
+
|
|
1088
|
+
### position-utils.ts
|
|
1089
|
+
|
|
1090
|
+
Event overlap and positioning:
|
|
1091
|
+
|
|
1092
|
+
| Function | Purpose |
|
|
1093
|
+
|---|---|
|
|
1094
|
+
| `calculateEventPosition` | Computes position for a single event in a column |
|
|
1095
|
+
| `calculateOverlappingPositions` | Computes non-overlapping layout for multiple events |
|
|
1096
|
+
| `yToTime` | Converts vertical pixel offset to Date |
|
|
1097
|
+
| `timeToY` | Converts Date to vertical pixel offset |
|
|
1098
|
+
| `eventsOverlap` | Checks if two events overlap in time |
|
|
1099
|
+
| `getOverlappingGroups` | Groups events that share time ranges |
|
|
1100
|
+
| `calculateSelectionOverlay` | Computes drag selection overlay dimensions |
|
|
1101
|
+
|
|
1102
|
+
---
|
|
1103
|
+
|
|
1104
|
+
## 17. Presets
|
|
1105
|
+
|
|
1106
|
+
Located in `src/presets/`.
|
|
1107
|
+
|
|
1108
|
+
### DefaultCalendar
|
|
1109
|
+
|
|
1110
|
+
Pre-configured calendar with sensible defaults:
|
|
1111
|
+
|
|
1112
|
+
```tsx
|
|
1113
|
+
import { DefaultCalendar } from '@innosolutions/inno-calendar';
|
|
1114
|
+
|
|
1115
|
+
<DefaultCalendar events={events} />
|
|
1116
|
+
```
|
|
1117
|
+
|
|
1118
|
+
### TailwindCalendar
|
|
1119
|
+
|
|
1120
|
+
Tailwind-optimized calendar preset with carefully chosen utility classes:
|
|
1121
|
+
|
|
1122
|
+
```tsx
|
|
1123
|
+
import { TailwindCalendar } from '@innosolutions/inno-calendar';
|
|
1124
|
+
|
|
1125
|
+
<TailwindCalendar events={events} />
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
---
|
|
1129
|
+
|
|
1130
|
+
## 18. CSS & Theming
|
|
1131
|
+
|
|
1132
|
+
Styles are in `src/styles/calendar.css` (imported via `@innosolutions/inno-calendar/styles`).
|
|
1133
|
+
|
|
1134
|
+
### CSS Custom Properties
|
|
1135
|
+
|
|
1136
|
+
```css
|
|
1137
|
+
:root {
|
|
1138
|
+
/* Surfaces */
|
|
1139
|
+
--inno-border-color: #e5e7eb;
|
|
1140
|
+
--inno-background: #ffffff;
|
|
1141
|
+
--inno-foreground: #111827;
|
|
1142
|
+
--inno-muted: #f3f4f6;
|
|
1143
|
+
--inno-muted-foreground: #6b7280;
|
|
1144
|
+
--inno-primary: #3b82f6;
|
|
1145
|
+
--inno-primary-foreground: #ffffff;
|
|
1146
|
+
|
|
1147
|
+
/* Event Colors */
|
|
1148
|
+
--inno-event-blue: #3b82f6;
|
|
1149
|
+
--inno-event-green: #22c55e;
|
|
1150
|
+
--inno-event-red: #ef4444;
|
|
1151
|
+
--inno-event-yellow: #eab308;
|
|
1152
|
+
--inno-event-purple: #a855f7;
|
|
1153
|
+
--inno-event-orange: #f97316;
|
|
1154
|
+
--inno-event-pink: #ec4899;
|
|
1155
|
+
--inno-event-teal: #14b8a6;
|
|
1156
|
+
--inno-event-gray: #6b7280;
|
|
1157
|
+
--inno-event-indigo: #6366f1;
|
|
1158
|
+
|
|
1159
|
+
/* Layout */
|
|
1160
|
+
--inno-hour-height: 96px;
|
|
1161
|
+
--inno-header-height: 56px;
|
|
1162
|
+
--inno-sidebar-width: 200px;
|
|
1163
|
+
}
|
|
1164
|
+
```
|
|
1165
|
+
|
|
1166
|
+
### Dark Mode
|
|
1167
|
+
|
|
1168
|
+
Override with `.dark` class:
|
|
1169
|
+
|
|
1170
|
+
```css
|
|
1171
|
+
.dark {
|
|
1172
|
+
--inno-border-color: #374151;
|
|
1173
|
+
--inno-background: #111827;
|
|
1174
|
+
--inno-foreground: #f9fafb;
|
|
1175
|
+
--inno-muted: #1f2937;
|
|
1176
|
+
--inno-muted-foreground: #9ca3af;
|
|
1177
|
+
}
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
### Key CSS Classes
|
|
1181
|
+
|
|
1182
|
+
| Class | Purpose |
|
|
1183
|
+
|---|---|
|
|
1184
|
+
| `.inno-calendar-root` | Root container with scrollbar styles |
|
|
1185
|
+
| `.inno-calendar-loading-overlay` | Translucent loading indicator overlay |
|
|
1186
|
+
| `.inno-calendar-spinner` | Spinner animation |
|
|
1187
|
+
| `.inno-calendar-selection` | Drag-to-select overlay |
|
|
1188
|
+
| `.inno-calendar-current-time` | Red current time indicator |
|
|
1189
|
+
| `.inno-calendar-event` | Event card styling |
|
|
1190
|
+
| `.inno-calendar-event-canceled` | Canceled event styling |
|
|
1191
|
+
| `.inno-calendar-disabled-hour` | Disabled/non-working hours pattern |
|
|
1192
|
+
| `.inno-calendar-no-scrollbar` | Hide scrollbar utility |
|
|
1193
|
+
| `.inno-scroll-nav` | D-pad controller container |
|
|
1194
|
+
| `.inno-scroll-nav-btn` | Directional buttons (up, down, left, right) |
|
|
1195
|
+
| `.ic-expansion-backdrop` | Backdrop for expanded month cell |
|
|
1196
|
+
| `.ic-expansion-panel` | Expanded events panel in month view |
|
|
1197
|
+
|
|
1198
|
+
---
|
|
1199
|
+
|
|
1200
|
+
## 19. Constants
|
|
1201
|
+
|
|
1202
|
+
Located in `src/core/constants.ts`.
|
|
1203
|
+
|
|
1204
|
+
### View List
|
|
1205
|
+
|
|
1206
|
+
```typescript
|
|
1207
|
+
const CALENDAR_VIEWS: TCalendarView[] = [
|
|
1208
|
+
'day', 'week', 'month', 'year', 'agenda',
|
|
1209
|
+
'resource-day', 'resource-week',
|
|
1210
|
+
'timeline-day', 'timeline-week'
|
|
1211
|
+
];
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
### Default Preferences
|
|
1215
|
+
|
|
1216
|
+
```typescript
|
|
1217
|
+
const DEFAULT_PREFERENCES: ICalendarPreferences = {
|
|
1218
|
+
startHour: 8,
|
|
1219
|
+
endHour: 18,
|
|
1220
|
+
firstDayOfWeek: 1, // Monday
|
|
1221
|
+
slotDuration: 30,
|
|
1222
|
+
showWeekends: true,
|
|
1223
|
+
timeFormat: '24h',
|
|
1224
|
+
badgeVariant: 'colored',
|
|
1225
|
+
showCanceledEvents: false,
|
|
1226
|
+
};
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
### Color Palette
|
|
1230
|
+
|
|
1231
|
+
```typescript
|
|
1232
|
+
const EVENT_COLORS: Record<TEventColor, string> = {
|
|
1233
|
+
blue: '#3b82f6', green: '#22c55e', red: '#ef4444',
|
|
1234
|
+
yellow: '#eab308', purple: '#a855f7', orange: '#f97316',
|
|
1235
|
+
pink: '#ec4899', teal: '#14b8a6', gray: '#6b7280', indigo: '#6366f1',
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
const EVENT_COLOR_CLASSES: Record<TEventColor, { bg, text, border }>;
|
|
1239
|
+
const HEX_TO_EVENT_COLOR: Record<string, TEventColor>;
|
|
1240
|
+
```
|
|
1241
|
+
|
|
1242
|
+
### Grid Constants
|
|
1243
|
+
|
|
1244
|
+
| Constant | Value |
|
|
1245
|
+
|---|---|
|
|
1246
|
+
| `DEFAULT_HOUR_HEIGHT` | 64px |
|
|
1247
|
+
| `DEFAULT_SLOT_HEIGHT` | 32px |
|
|
1248
|
+
| `DEFAULT_HEADER_HEIGHT` | 56px |
|
|
1249
|
+
| `DEFAULT_RESOURCE_WIDTH` | 200px |
|
|
1250
|
+
| `MIN_EVENT_HEIGHT` | 20px |
|
|
1251
|
+
| `HOURS_IN_DAY` | 24 |
|
|
1252
|
+
| `MINUTES_IN_HOUR` | 60 |
|
|
1253
|
+
| `MS_PER_MINUTE` | 60000 |
|
|
1254
|
+
| `MS_PER_HOUR` | 3600000 |
|
|
1255
|
+
| `MS_PER_DAY` | 86400000 |
|
|
1256
|
+
|
|
1257
|
+
### Time Defaults
|
|
1258
|
+
|
|
1259
|
+
```typescript
|
|
1260
|
+
const DEFAULT_VISIBLE_HOURS: IVisibleHours = { startHour: 0, endHour: 24 };
|
|
1261
|
+
const DEFAULT_BUSINESS_HOURS: IVisibleHours = { startHour: 8, endHour: 18 };
|
|
1262
|
+
```
|
|
1263
|
+
|
|
1264
|
+
---
|
|
1265
|
+
|
|
1266
|
+
## 20. Integration Guide
|
|
1267
|
+
|
|
1268
|
+
### Minimal Setup
|
|
1269
|
+
|
|
1270
|
+
```tsx
|
|
1271
|
+
import { InnoCalendar, type CalendarEvent } from '@innosolutions/inno-calendar';
|
|
1272
|
+
import '@innosolutions/inno-calendar/styles';
|
|
1273
|
+
|
|
1274
|
+
const events: CalendarEvent[] = [
|
|
1275
|
+
{
|
|
1276
|
+
id: '1',
|
|
1277
|
+
title: 'Team Meeting',
|
|
1278
|
+
startDate: new Date('2026-02-12T09:00:00'),
|
|
1279
|
+
endDate: new Date('2026-02-12T10:00:00'),
|
|
1280
|
+
color: 'blue',
|
|
1281
|
+
},
|
|
1282
|
+
];
|
|
1283
|
+
|
|
1284
|
+
function App() {
|
|
1285
|
+
return (
|
|
1286
|
+
<InnoCalendar
|
|
1287
|
+
events={events}
|
|
1288
|
+
onEventClick={(event) => console.log('Clicked:', event.title)}
|
|
1289
|
+
onSlotSelect={(sel) => console.log('Selected:', sel.startDate, sel.endDate)}
|
|
1290
|
+
/>
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1293
|
+
```
|
|
1294
|
+
|
|
1295
|
+
### With Custom Popover
|
|
1296
|
+
|
|
1297
|
+
```tsx
|
|
1298
|
+
<InnoCalendar
|
|
1299
|
+
events={events}
|
|
1300
|
+
renderPopover={({ event, onClose }) => (
|
|
1301
|
+
<div className="p-4 space-y-2">
|
|
1302
|
+
<h3 className="font-bold">{event.title}</h3>
|
|
1303
|
+
<p>{event.description}</p>
|
|
1304
|
+
<button onClick={onClose}>Close</button>
|
|
1305
|
+
</div>
|
|
1306
|
+
)}
|
|
1307
|
+
/>
|
|
1308
|
+
```
|
|
1309
|
+
|
|
1310
|
+
### With Loading State
|
|
1311
|
+
|
|
1312
|
+
```tsx
|
|
1313
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
1314
|
+
|
|
1315
|
+
<InnoCalendar
|
|
1316
|
+
events={events}
|
|
1317
|
+
isLoading={isLoading}
|
|
1318
|
+
onDateChange={async (date, view) => {
|
|
1319
|
+
setIsLoading(true);
|
|
1320
|
+
const newEvents = await fetchEvents(date, view);
|
|
1321
|
+
setEvents(newEvents);
|
|
1322
|
+
setIsLoading(false);
|
|
1323
|
+
}}
|
|
1324
|
+
/>
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1327
|
+
### With Deep-Linking
|
|
1328
|
+
|
|
1329
|
+
```tsx
|
|
1330
|
+
// URL: /calendar?eventId=appointment-42
|
|
1331
|
+
const eventId = useSearchParams().get('eventId');
|
|
1332
|
+
|
|
1333
|
+
<InnoCalendar events={events} focusEventId={eventId} />
|
|
1334
|
+
```
|
|
1335
|
+
|
|
1336
|
+
### Imperative Control
|
|
1337
|
+
|
|
1338
|
+
```tsx
|
|
1339
|
+
const ref = useRef<ICalendarRefHandle>(null);
|
|
1340
|
+
|
|
1341
|
+
<Button onClick={() => ref.current?.scrollToWorkingHours()}>
|
|
1342
|
+
Go to Work Hours
|
|
1343
|
+
</Button>
|
|
1344
|
+
|
|
1345
|
+
<InnoCalendar ref={ref} events={events} />
|
|
1346
|
+
```
|
|
1347
|
+
|
|
1348
|
+
### Resource / Timeline Views
|
|
1349
|
+
|
|
1350
|
+
```tsx
|
|
1351
|
+
const resources: IResource[] = [
|
|
1352
|
+
{ id: 'room-a', name: 'Meeting Room A', color: 'blue' },
|
|
1353
|
+
{ id: 'room-b', name: 'Board Room', color: 'green' },
|
|
1354
|
+
];
|
|
1355
|
+
|
|
1356
|
+
<InnoCalendar
|
|
1357
|
+
events={events}
|
|
1358
|
+
initialView="timeline-week"
|
|
1359
|
+
onEventDrop={(result) => {
|
|
1360
|
+
// result.newResourceId is set when event is dragged to a different row
|
|
1361
|
+
api.updateEvent(result.event.id, {
|
|
1362
|
+
startDate: result.newStartDate,
|
|
1363
|
+
endDate: result.newEndDate,
|
|
1364
|
+
resourceId: result.newResourceId,
|
|
1365
|
+
});
|
|
1366
|
+
}}
|
|
1367
|
+
/>
|
|
1368
|
+
```
|
|
1369
|
+
|
|
1370
|
+
### Header Configuration
|
|
1371
|
+
|
|
1372
|
+
```tsx
|
|
1373
|
+
// Hide resource views and settings — only show calendar views + Today + navigation
|
|
1374
|
+
<InnoCalendar
|
|
1375
|
+
events={events}
|
|
1376
|
+
headerConfig={{
|
|
1377
|
+
showResourceViews: false,
|
|
1378
|
+
showSettings: false,
|
|
1379
|
+
showFilters: false,
|
|
1380
|
+
}}
|
|
1381
|
+
/>
|
|
1382
|
+
```
|
|
1383
|
+
|
|
1384
|
+
### Event Detail Mode
|
|
1385
|
+
|
|
1386
|
+
```tsx
|
|
1387
|
+
// Show event details in a slide-in sheet instead of default popover
|
|
1388
|
+
<InnoCalendar
|
|
1389
|
+
events={events}
|
|
1390
|
+
eventDetailMode="sheet"
|
|
1391
|
+
/>
|
|
1392
|
+
|
|
1393
|
+
// Fully custom event detail container
|
|
1394
|
+
<InnoCalendar
|
|
1395
|
+
events={events}
|
|
1396
|
+
eventDetailMode="custom"
|
|
1397
|
+
renderEventDetail={({ event, onClose }) => (
|
|
1398
|
+
<MyCustomDrawer event={event} onClose={onClose} />
|
|
1399
|
+
)}
|
|
1400
|
+
/>
|
|
1401
|
+
```
|
|
1402
|
+
|
|
1403
|
+
### With Preferences Locking
|
|
1404
|
+
|
|
1405
|
+
```tsx
|
|
1406
|
+
<InnoCalendar
|
|
1407
|
+
events={events}
|
|
1408
|
+
preferencesConfig={{
|
|
1409
|
+
defaults: { view: 'month', badgeVariant: 'dot' },
|
|
1410
|
+
modes: {
|
|
1411
|
+
slotDuration: 'locked',
|
|
1412
|
+
showWeekends: 'locked',
|
|
1413
|
+
},
|
|
1414
|
+
locked: {
|
|
1415
|
+
slotDuration: 30,
|
|
1416
|
+
showWeekends: false,
|
|
1417
|
+
},
|
|
1418
|
+
}}
|
|
1419
|
+
/>
|
|
1420
|
+
```
|
|
1421
|
+
|
|
1422
|
+
### Widget Embedding
|
|
1423
|
+
|
|
1424
|
+
```tsx
|
|
1425
|
+
import { AgendaWidget, AgendaDropdown } from '@innosolutions/inno-calendar';
|
|
1426
|
+
|
|
1427
|
+
// Dashboard card
|
|
1428
|
+
<AgendaWidget events={todayEvents} onEventClick={openEvent} />
|
|
1429
|
+
|
|
1430
|
+
// Navbar notification bell
|
|
1431
|
+
<AgendaDropdown events={upcomingEvents} onEventClick={openEvent} />
|
|
1432
|
+
```
|
|
1433
|
+
|
|
1434
|
+
### Custom Slot Example
|
|
1435
|
+
|
|
1436
|
+
```tsx
|
|
1437
|
+
<InnoCalendar
|
|
1438
|
+
events={events}
|
|
1439
|
+
slots={{
|
|
1440
|
+
dayCellFooter: ({ date, events }) => (
|
|
1441
|
+
<div className="text-xs text-muted-foreground border-t mt-1 pt-1">
|
|
1442
|
+
{events.length} events
|
|
1443
|
+
</div>
|
|
1444
|
+
),
|
|
1445
|
+
columnHeader: ({ date, isToday, onDayClick }) => (
|
|
1446
|
+
<button
|
|
1447
|
+
className={cn('text-center', isToday && 'font-bold text-primary')}
|
|
1448
|
+
onClick={() => onDayClick?.(date)}
|
|
1449
|
+
>
|
|
1450
|
+
{date.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric' })}
|
|
1451
|
+
</button>
|
|
1452
|
+
),
|
|
1453
|
+
}}
|
|
1454
|
+
/>
|
|
1455
|
+
```
|
|
1456
|
+
|
|
1457
|
+
---
|
|
1458
|
+
|
|
1459
|
+
## 21. Full Export Catalog
|
|
1460
|
+
|
|
1461
|
+
### From `src/components/`
|
|
1462
|
+
|
|
1463
|
+
**Main Components:**
|
|
1464
|
+
- `InnoCalendar`, `InnoCalendarProps`
|
|
1465
|
+
- `Calendar`, `CalendarProps`
|
|
1466
|
+
- `IntegratedCalendar` (alias), `IntegratedCalendarProps` (alias)
|
|
1467
|
+
|
|
1468
|
+
**Event Components:**
|
|
1469
|
+
- `EventCard`, `EventCardProps`
|
|
1470
|
+
- `EventBlock`, `EventBlockProps`
|
|
1471
|
+
- `EventPopover`, `EventPopoverProps`, `IEventPopoverLabels`, `IPopoverEvent`, `IEventParticipant`
|
|
1472
|
+
- `MultiDayEventBar`, `MultiDayEventBarProps`
|
|
1473
|
+
- `getEventColorClasses`
|
|
1474
|
+
|
|
1475
|
+
**Header Components:**
|
|
1476
|
+
- `CalendarHeader`, `CalendarHeaderProps`
|
|
1477
|
+
- `DateNavigator`, `DateNavigatorProps`
|
|
1478
|
+
- `TodayButton`, `TodayButtonProps`
|
|
1479
|
+
|
|
1480
|
+
**View Components:**
|
|
1481
|
+
- `DayView`, `DayViewProps`
|
|
1482
|
+
- `WeekView`, `WeekViewProps`
|
|
1483
|
+
- `MonthView`, `MonthViewProps`
|
|
1484
|
+
- `YearView`, `YearViewProps`
|
|
1485
|
+
- `AgendaView`, `AgendaViewProps`
|
|
1486
|
+
- `TimelineView`, `TimelineViewProps`
|
|
1487
|
+
- `DayEventsExpansion`, `DayEventsExpansionProps`
|
|
1488
|
+
|
|
1489
|
+
**Primitive Components:**
|
|
1490
|
+
- `DaySlot`, `DaySlotProps`
|
|
1491
|
+
- `MultiDayBanner`, `MultiDayBannerProps`
|
|
1492
|
+
- `TimeSlot`
|
|
1493
|
+
|
|
1494
|
+
> **Internal-only Primitives** (not re-exported via public barrel): `CalendarTimeline`, `ScrollNavigator`, `ScrollNavigatorProps`, `SelectableSlot`, `SelectableSlotProps`, `TimeSlotProps`, `WeekAllDayRow`, `WeekAllDayRowProps`
|
|
1495
|
+
|
|
1496
|
+
**Settings Components:**
|
|
1497
|
+
- `BadgeVariantSetting`, `BadgeVariantSettingProps`
|
|
1498
|
+
- `SlotDurationSetting`, `SlotDurationSettingProps`
|
|
1499
|
+
- `VisibleHoursSetting`, `VisibleHoursSettingProps`
|
|
1500
|
+
- `WorkingHoursSetting`, `WorkingHoursSettingProps`
|
|
1501
|
+
- `DEFAULT_WEEK_WORKING_HOURS`, `IDayWorkingHours`, `IWeekWorkingHours`, `TDayOfWeek`
|
|
1502
|
+
|
|
1503
|
+
**Filter Components:**
|
|
1504
|
+
- `CalendarFilterSidebar`, `CalendarFilterSidebarProps`, `CalendarFilterSidebarLabels`
|
|
1505
|
+
- `ScheduleTypeFilter`, `ScheduleTypeFilterProps`, `IScheduleTypeOption`
|
|
1506
|
+
- `UserFilter`, `UserFilterProps`, `IUserOption`
|
|
1507
|
+
|
|
1508
|
+
**Widget Components:**
|
|
1509
|
+
- `AgendaWidget`, `AgendaWidgetProps`
|
|
1510
|
+
- `AgendaDropdown`, `AgendaDropdownProps`
|
|
1511
|
+
|
|
1512
|
+
**UI Primitives:**
|
|
1513
|
+
- `Button`, `ButtonProps`, `buttonVariants`
|
|
1514
|
+
- `Dialog`, `DialogClose`, `DialogContent`, `DialogDescription`, `DialogHeader`, `DialogTitle`, `DialogTrigger`
|
|
1515
|
+
- `Popover`, `PopoverAnchor`, `PopoverContent`, `PopoverTrigger`
|
|
1516
|
+
- `Sheet`, `SheetClose`, `SheetContent`, `SheetDescription`, `SheetHeader`, `SheetTitle`, `SheetTrigger`
|
|
1517
|
+
- `Tooltip`, `TooltipContent`, `TooltipProvider`, `TooltipTrigger`
|
|
1518
|
+
|
|
1519
|
+
> **Internal-only UI** (not re-exported via public barrel, available via direct `./ui` import within the package): `Badge`, `BadgeProps`, `badgeVariants`, `DropdownMenu` family, `DialogOverlay`, `DialogPortal`, `Label`, `LabelProps`, `Select`, `SelectProps`, `SheetOverlay`, `SheetPortal`
|
|
1520
|
+
|
|
1521
|
+
### From `src/core/`
|
|
1522
|
+
|
|
1523
|
+
**Types** (60+ type exports) — see Section 4.
|
|
1524
|
+
|
|
1525
|
+
**Context Providers:**
|
|
1526
|
+
- `InnoCalendarProvider`, `InnoCalendarProviderProps`
|
|
1527
|
+
- `CalendarProvider`, `CalendarProviderProps`
|
|
1528
|
+
- `SlotSelectionProvider`, `SlotSelectionProviderProps`
|
|
1529
|
+
- `DragDropProvider`, `DragDropProviderProps`
|
|
1530
|
+
- `IntegratedCalendarProvider` (alias), `IntegratedCalendarProviderProps` (alias)
|
|
1531
|
+
|
|
1532
|
+
**Hooks** — see Section 14.
|
|
1533
|
+
|
|
1534
|
+
**Constants** — see Section 19.
|
|
1535
|
+
|
|
1536
|
+
**Utilities** — see Section 16. All re-exported via `export * from './utils'`.
|
|
1537
|
+
|
|
1538
|
+
**Preferences:**
|
|
1539
|
+
- `IPreferences`, `IPreferencesConfig`, `IUsePreferencesReturn`
|
|
1540
|
+
- `TPreferenceMode`, `TPreferenceModes`, `TLockedPreferences`, `TPartialPreferences`, `TPreferenceKey`
|
|
1541
|
+
- `IVisibleHoursConfig`, `TWorkingHoursConfig`
|
|
1542
|
+
- `PREFERENCES_STORAGE_KEY`, default constants
|
|
1543
|
+
- `useAdvancedPreferences` (re-exported as alias)
|
|
1544
|
+
|
|
1545
|
+
### From `src/presets/`
|
|
1546
|
+
|
|
1547
|
+
- `DefaultCalendar`, `DefaultCalendarProps`
|
|
1548
|
+
- `TailwindCalendar`, `TailwindCalendarProps`
|
|
1549
|
+
- `RenderEventProps`, `RenderEventPopoverProps`, `RenderFilterSidebarProps`, `RenderHeaderProps`
|
|
1550
|
+
|
|
1551
|
+
### From `src/lib/`
|
|
1552
|
+
|
|
1553
|
+
- `cn` — `clsx(...inputs) | twMerge` className composer
|
|
1554
|
+
|
|
1555
|
+
---
|
|
1556
|
+
|
|
1557
|
+
## 22. File Naming Conventions
|
|
1558
|
+
|
|
1559
|
+
**All files and folders use kebab-case.**
|
|
1560
|
+
|
|
1561
|
+
| Type | Pattern | Example |
|
|
1562
|
+
|---|---|---|
|
|
1563
|
+
| Components | `kebab-case.tsx` | `event-card.tsx` |
|
|
1564
|
+
| Hooks | `use-kebab-case.ts` | `use-calendar.ts` |
|
|
1565
|
+
| Context | `kebab-case.tsx` | `calendar-context.tsx` |
|
|
1566
|
+
| Types | `types.ts` | `types.ts` |
|
|
1567
|
+
| Utilities | `kebab-case.ts` | `date-utils.ts` |
|
|
1568
|
+
| Constants | `constants.ts` | `constants.ts` |
|
|
1569
|
+
| Barrel exports | `index.ts` | `index.ts` |
|
|
1570
|
+
| Styles | `kebab-case.css` | `calendar.css` |
|
|
1571
|
+
|
|
1572
|
+
---
|
|
1573
|
+
|
|
1574
|
+
## 23. Styling Patterns
|
|
1575
|
+
|
|
1576
|
+
### className Composition
|
|
1577
|
+
|
|
1578
|
+
```tsx
|
|
1579
|
+
import { cn } from '../../lib/utils';
|
|
1580
|
+
|
|
1581
|
+
<div className={cn('base-styles', isActive && 'active-styles', className)} />
|
|
1582
|
+
```
|
|
1583
|
+
|
|
1584
|
+
### CVA for Variants
|
|
1585
|
+
|
|
1586
|
+
```tsx
|
|
1587
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
1588
|
+
|
|
1589
|
+
const buttonVariants = cva('base-classes', {
|
|
1590
|
+
variants: {
|
|
1591
|
+
variant: { default: '...', outline: '...' },
|
|
1592
|
+
size: { sm: '...', md: '...' },
|
|
1593
|
+
},
|
|
1594
|
+
defaultVariants: { variant: 'default', size: 'md' },
|
|
1595
|
+
});
|
|
1596
|
+
```
|
|
1597
|
+
|
|
1598
|
+
---
|
|
1599
|
+
|
|
1600
|
+
## 24. Biome Configuration
|
|
1601
|
+
|
|
1602
|
+
From `biome.json` (schema v2.3.13):
|
|
1603
|
+
|
|
1604
|
+
- **Formatter**: tabs, single quotes, JSX double quotes, 100 line width, trailing commas (ES5), semicolons always
|
|
1605
|
+
- **Linter**: recommended + `noUnusedVariables`, `noExplicitAny` (warn), `noNonNullAssertion` (warn), `useConst` (error), `noExcessiveCognitiveComplexity` (max 15, warn)
|
|
1606
|
+
- **Organize imports**: enabled via assist actions
|
|
1607
|
+
|
|
1608
|
+
```bash
|
|
1609
|
+
npm run lint # Check
|
|
1610
|
+
npm run format # Auto-fix
|
|
1611
|
+
```
|
|
1612
|
+
|
|
1613
|
+
---
|
|
1614
|
+
|
|
1615
|
+
## 25. State Synchronization Guide
|
|
1616
|
+
|
|
1617
|
+
How state flows through the calendar and guidance for integrating with consumer projects.
|
|
1618
|
+
|
|
1619
|
+
### Data Flow
|
|
1620
|
+
|
|
1621
|
+
```
|
|
1622
|
+
Consumer App
|
|
1623
|
+
└─ <InnoCalendar events={events} onEventDrop={...} ...>
|
|
1624
|
+
└─ DragDropProvider (drag state, onEventDrop callback)
|
|
1625
|
+
└─ InnoCalendarProvider (view, date, preferences, filtered events)
|
|
1626
|
+
└─ SlotSelectionProvider (drag-to-select state)
|
|
1627
|
+
└─ InnerCalendar (renders header + active view)
|
|
1628
|
+
├─ CalendarHeader (nav, view switcher, settings)
|
|
1629
|
+
└─ Active View (DayView, WeekView, TimelineView, etc.)
|
|
1630
|
+
└─ EventCard (popover/dialog/sheet/custom)
|
|
1631
|
+
```
|
|
1632
|
+
|
|
1633
|
+
### Events: BYO Approach
|
|
1634
|
+
|
|
1635
|
+
The package **never fetches data**. The consumer owns the events array and updates it:
|
|
1636
|
+
|
|
1637
|
+
```tsx
|
|
1638
|
+
// Using React Query
|
|
1639
|
+
const { data: events } = useQuery(['events', dateRange], fetchEvents);
|
|
1640
|
+
const updateEvent = useMutation(api.updateEvent, {
|
|
1641
|
+
onSuccess: () => queryClient.invalidateQueries(['events']),
|
|
1642
|
+
});
|
|
1643
|
+
|
|
1644
|
+
<InnoCalendar
|
|
1645
|
+
events={events ?? []}
|
|
1646
|
+
onEventDrop={(result) => updateEvent.mutate({
|
|
1647
|
+
id: result.event.id,
|
|
1648
|
+
startDate: result.newStartDate,
|
|
1649
|
+
endDate: result.newEndDate,
|
|
1650
|
+
resourceId: result.newResourceId,
|
|
1651
|
+
})}
|
|
1652
|
+
onSlotSelect={(sel) => openCreateDialog(sel.startDate, sel.endDate)}
|
|
1653
|
+
/>
|
|
1654
|
+
```
|
|
1655
|
+
|
|
1656
|
+
### Preferences Persistence
|
|
1657
|
+
|
|
1658
|
+
Preferences (view, slot duration, badge variant, etc.) persist to `localStorage` by default. The key is configurable:
|
|
1659
|
+
|
|
1660
|
+
```tsx
|
|
1661
|
+
<InnoCalendar
|
|
1662
|
+
preferencesConfig={{
|
|
1663
|
+
storageKey: 'my-app-calendar-prefs', // default: 'inno-calendar-preferences'
|
|
1664
|
+
defaults: { view: 'week', badgeVariant: 'colored' },
|
|
1665
|
+
modes: { slotDuration: 'locked' }, // prevent user from changing
|
|
1666
|
+
locked: { slotDuration: 30 },
|
|
1667
|
+
}}
|
|
1668
|
+
/>
|
|
1669
|
+
```
|
|
1670
|
+
|
|
1671
|
+
### Cross-Project State Patterns
|
|
1672
|
+
|
|
1673
|
+
For apps that embed InnoCalendar (e.g., promosport-erp, generationimmo-erp):
|
|
1674
|
+
|
|
1675
|
+
1. **URL Sync** — Sync view/date with URL params so back-button works:
|
|
1676
|
+
```tsx
|
|
1677
|
+
<InnoCalendar
|
|
1678
|
+
initialView={searchParams.get('view') as TCalendarView ?? 'week'}
|
|
1679
|
+
initialDate={searchParams.get('date') ? new Date(searchParams.get('date')!) : undefined}
|
|
1680
|
+
onViewChange={(v) => setSearchParams({ view: v })}
|
|
1681
|
+
onDateChange={(d) => setSearchParams({ date: d.toISOString() })}
|
|
1682
|
+
/>
|
|
1683
|
+
```
|
|
1684
|
+
|
|
1685
|
+
2. **Deep-linking events** — Navigate to a specific event from another page:
|
|
1686
|
+
```tsx
|
|
1687
|
+
<InnoCalendar events={events} focusEventId={eventIdFromUrl} />
|
|
1688
|
+
```
|
|
1689
|
+
|
|
1690
|
+
3. **External filter state** — The calendar's built-in filtering is opt-in. You can filter server-side and just pass filtered `events`:
|
|
1691
|
+
```tsx
|
|
1692
|
+
const filteredEvents = useFilteredEvents(allEvents, externalFilters);
|
|
1693
|
+
<InnoCalendar events={filteredEvents} />
|
|
1694
|
+
```
|
|
1695
|
+
|
|
1696
|
+
4. **Imperative control** — Use ref for programmatic scroll/navigation:
|
|
1697
|
+
```tsx
|
|
1698
|
+
const ref = useRef<ICalendarRefHandle>(null);
|
|
1699
|
+
ref.current?.scrollToToday();
|
|
1700
|
+
ref.current?.scrollToWorkingHours();
|
|
1701
|
+
ref.current?.focusEvent(eventId);
|
|
1702
|
+
```
|
|
1703
|
+
|
|
1704
|
+
---
|
|
1705
|
+
|
|
1706
|
+
## 26. Critical Rules
|
|
1707
|
+
|
|
1708
|
+
1. **CalendarEvent must stay domain-agnostic** — no new top-level fields. Use `data?: TData` for domain data.
|
|
1709
|
+
2. **Deprecated fields stay** until next major version — never remove them prematurely.
|
|
1710
|
+
3. **Built-in components read `event.data` first**, then fall back to deprecated top-level fields.
|
|
1711
|
+
4. **Core module has zero external dependencies** — only React + native APIs.
|
|
1712
|
+
5. **Follow existing patterns** before inventing new ones (composition, slot props, CVA).
|
|
1713
|
+
6. **kebab-case everywhere** — files, folders, no exceptions.
|
|
1714
|
+
7. **JSDoc on every public export** — summary + `@param` + `@example` + `@default`.
|
|
1715
|
+
8. **Run `npm run typecheck`** before committing.
|
|
1716
|
+
9. **Update AGENT.md, README.md, and copilot-instructions.md** when public API changes.
|
|
1717
|
+
10. **Section separators** in type files: `// ============================================================================`
|
|
1718
|
+
11. **Performance**: `useMemo`, `useCallback`, memoize context values, stable keys.
|
|
1719
|
+
12. **Accessibility**: semantic HTML, ARIA attributes, keyboard navigation (Arrow keys, Enter/Space, Escape, Tab).
|
|
1720
|
+
13. **No inline objects/arrays in JSX props** — extract or memoize them.
|
|
1721
|
+
14. **Generic type propagation** — maintain `<TData>` through hooks, context, and component boundaries.
|