calkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/llms.txt ADDED
@@ -0,0 +1,594 @@
1
+ # CalKit
2
+
3
+ > Vanilla JS web component library for date pickers, time pickers, booking calendars, and resource schedulers.
4
+
5
+ Package: calkit
6
+ Version: 0.1.0
7
+ Tags: <cal-datepicker>, <cal-timepicker>, <cal-booking>, <cal-scheduler>
8
+ Install (CDN script tag): <script src="https://cdn.jsdelivr.net/gh/SimonKefas/calkit/dist/calkit.umd.js"></script>
9
+ Install (Bundler ESM): import { CalDatepicker, CalBooking, CalTimepicker, CalScheduler } from 'calkit';
10
+
11
+ All date strings use "YYYY-MM-DD" format.
12
+ All time strings use "HH:MM" 24h format.
13
+ All color tokens use raw HSL channels consumed as hsl(var(--cal-...)).
14
+ All events are CustomEvents with { bubbles: true, composed: true }.
15
+
16
+ ---
17
+
18
+ ## Component: cal-datepicker
19
+
20
+ Tag: <cal-datepicker>
21
+ Class: CalDatepicker
22
+ Extends: CalendarBase → HTMLElement
23
+
24
+ ### Attributes (observedAttributes)
25
+
26
+ - mode: "single" | "multi" | "range" (default: "single")
27
+ - display: "inline" | "popover" (default: "inline")
28
+ - theme: "light" | "dark" | "auto" (default: "light")
29
+ - value: string (single: "2026-03-15", range: "2026-03-10/2026-03-15", multi: "2026-03-10,2026-03-12")
30
+ - min-date: string | null (default: null) — "YYYY-MM-DD" earliest selectable date
31
+ - max-date: string | null (default: null) — "YYYY-MM-DD" latest selectable date
32
+ - disabled-dates: string | null (default: null) — comma-separated "YYYY-MM-DD" list
33
+ - first-day: number (default: 0) — 0=Sunday, 1=Monday, ..., 6=Saturday
34
+ - locale: string | null (default: null)
35
+ - presets: string | null (default: null) — comma-separated keys: "today", "this-week", "next-7", "next-30"
36
+ - placeholder: string (default: "Select date") — popover trigger text
37
+ - dual: boolean attribute (default: absent) — show two months side-by-side in range mode
38
+ - loading: boolean attribute (default: absent) — show skeleton loading state
39
+
40
+ ### JS Properties
41
+
42
+ - value: string | null (mode="single"), string[] (mode="multi"), {start: string, end: string} | null (mode="range") — read/write
43
+ - loading: boolean — read/write, reflects attribute
44
+
45
+ ### Methods
46
+
47
+ - open(): void — open popover (popover display only)
48
+ - close(): void — close popover
49
+ - goToMonth(month: number, year: number): void — month is 0-indexed (0=Jan, 11=Dec)
50
+ - showStatus(type: "error"|"warning"|"info"|"success", message: string, opts?: {autoDismiss?: number, dismissible?: boolean}): void
51
+ - clearStatus(): void
52
+
53
+ ### Events
54
+
55
+ - cal:change
56
+ - mode="single": detail = {value: string} — "YYYY-MM-DD"
57
+ - mode="range": detail = {value: {start: string, end: string}}
58
+ - mode="multi": detail = {value: string[]} — sorted array of "YYYY-MM-DD"
59
+ - cal:month-change — detail = {year: number, month: number}
60
+ - cal:open — detail = {}
61
+ - cal:close — detail = {}
62
+ - cal:status — detail = {type: string|null, message: string|null}
63
+
64
+ ### Preset Keys
65
+
66
+ - "today" → {start: today, end: today}
67
+ - "this-week" → {start: Sunday, end: Saturday} of current week
68
+ - "next-7" → {start: today, end: today+6}
69
+ - "next-30" → {start: today, end: today+29}
70
+
71
+ ### Example
72
+
73
+ ```html
74
+ <cal-datepicker mode="range" dual presets="today,next-7,next-30" theme="light"></cal-datepicker>
75
+ <script>
76
+ const el = document.querySelector('cal-datepicker');
77
+ el.addEventListener('cal:change', (e) => {
78
+ const { start, end } = e.detail.value;
79
+ console.log(start, end);
80
+ });
81
+ </script>
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Component: cal-timepicker
87
+
88
+ Tag: <cal-timepicker>
89
+ Class: CalTimepicker
90
+ Extends: CalendarBase → HTMLElement
91
+
92
+ ### Attributes (observedAttributes)
93
+
94
+ - mode: "single" | "multi" | "range" (default: "single")
95
+ - display: "inline" | "popover" (default: "inline")
96
+ - theme: "light" | "dark" | "auto" (default: "light")
97
+ - start-time: string (default: "09:00") — "HH:MM"
98
+ - end-time: string (default: "17:00") — "HH:MM"
99
+ - interval: number (default: 30) — minutes between slots
100
+ - format: "12h" | "24h" (default: "24h")
101
+ - placeholder: string (default: "Select time") — popover trigger text
102
+ - value: string (single: "14:30", range: "09:00/12:00", multi: "09:00,10:30")
103
+ - duration-labels: boolean attribute (default: absent) — show duration labels
104
+ - loading: boolean attribute (default: absent)
105
+
106
+ ### JS Properties
107
+
108
+ - value: string | null (mode="single"), string[] (mode="multi"), {start: string, end: string} | null (mode="range") — read/write
109
+ - slots: Array<{time: string, label?: string, available?: boolean}> | null — custom slot definitions, overrides attribute-based generation
110
+ - unavailableTimes: string[] — array of "HH:MM" strings to mark unavailable (default: [])
111
+ - loading: boolean — read/write
112
+
113
+ ### Methods
114
+
115
+ - open(): void — open popover
116
+ - close(): void — close popover
117
+ - showStatus(type: "error"|"warning"|"info"|"success", message: string, opts?: {autoDismiss?: number, dismissible?: boolean}): void
118
+ - clearStatus(): void
119
+
120
+ ### Events
121
+
122
+ - cal:time-change
123
+ - mode="single": detail = {value: string} — "HH:MM"
124
+ - mode="range": detail = {value: {start: string, end: string}}
125
+ - mode="multi": detail = {value: string[]} — sorted array of "HH:MM"
126
+ - cal:open — detail = {}
127
+ - cal:close — detail = {}
128
+ - cal:status — detail = {type: string|null, message: string|null}
129
+
130
+ ### Example
131
+
132
+ ```html
133
+ <cal-timepicker start-time="08:00" end-time="20:00" interval="60" format="12h" duration-labels></cal-timepicker>
134
+ <script>
135
+ const el = document.querySelector('cal-timepicker');
136
+ el.addEventListener('cal:time-change', (e) => {
137
+ console.log(e.detail.value); // "14:00"
138
+ });
139
+ </script>
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Component: cal-booking
145
+
146
+ Tag: <cal-booking>
147
+ Class: CalBooking
148
+ Extends: CalendarBase → HTMLElement
149
+
150
+ ### Attributes (observedAttributes)
151
+
152
+ - theme: "light" | "dark" | "auto" (default: "light")
153
+ - display: "inline" | "popover" (default: "inline")
154
+ - min-date: string | null (default: null)
155
+ - max-date: string | null (default: null)
156
+ - first-day: number (default: 0)
157
+ - placeholder: string (default: "Select dates")
158
+ - dual: boolean attribute (default: absent) — two month panels
159
+ - show-labels-on-hover: boolean attribute (default: absent)
160
+ - time-slots: boolean attribute (default: absent) — enable date→time two-step selection
161
+ - time-start: string (default: "09:00") — time grid start when time-slots enabled
162
+ - time-end: string (default: "17:00") — time grid end
163
+ - time-interval: number (default: 60) — time slot interval in minutes
164
+ - time-format: "12h" | "24h" (default: "24h")
165
+ - duration-labels: boolean attribute (default: absent)
166
+ - loading: boolean attribute (default: absent)
167
+
168
+ ### JS Properties
169
+
170
+ - value: {start: string, end: string, startTime?: string, endTime?: string} | null — read/write
171
+ - bookings: Booking[] — array of existing bookings (default: [])
172
+ - dayData: Record<string, {label?: string, status?: string}> — static per-date metadata (default: {})
173
+ - labelFormula: ((dateStr: string) => {label?: string, status?: string} | null) | null — dynamic labels (highest priority, default: null)
174
+ - timeSlots: Array<{time: string, label?: string, available?: boolean}> | null — custom time slots (default: null)
175
+ - loading: boolean — read/write
176
+
177
+ ### Booking Object Shape
178
+
179
+ ```
180
+ {
181
+ id: string,
182
+ start: string, // "YYYY-MM-DD" — first day of booking
183
+ end: string, // "YYYY-MM-DD" — last day (checkout day)
184
+ label?: string, // displayed on hover / in cell
185
+ color?: "blue" | "green" | "red" | "orange" | "gray" // default: "blue"
186
+ }
187
+ ```
188
+
189
+ ### Cell Status Resolution (priority order)
190
+
191
+ 1. labelFormula(dateStr) — if returns {status, label}, overrides everything
192
+ 2. dayData[dateStr] — static {status, label}
193
+ 3. Derived from bookings — "available", "booked", "half-day", "checkin-only", "checkout-only"
194
+
195
+ ### Methods
196
+
197
+ - open(): void
198
+ - close(): void
199
+ - goToMonth(month: number, year: number): void
200
+ - showStatus(type: "error"|"warning"|"info"|"success", message: string, opts?: {autoDismiss?: number, dismissible?: boolean}): void
201
+ - clearStatus(): void
202
+
203
+ ### Events
204
+
205
+ - cal:change — detail = {value: {start: string, end: string, startTime?: string, endTime?: string}}
206
+ - cal:selection-invalid — detail = {start: string, end: string} — fires when selection overlaps booking
207
+ - cal:month-change — detail = {year: number, month: number}
208
+ - cal:open — detail = {}
209
+ - cal:close — detail = {}
210
+ - cal:status — detail = {type: string|null, message: string|null}
211
+
212
+ ### Overlap Validation
213
+
214
+ Selecting a range that overlaps any booking (where selStart < booking.end && selEnd > booking.start) will:
215
+ 1. Emit cal:selection-invalid
216
+ 2. Clear the selection
217
+ 3. Show an error status banner "Selection overlaps an existing booking" (auto-dismiss 4s)
218
+
219
+ Same-day boundaries are disallowed: a selection ending on a booking start date, or starting on a booking end date, triggers overlap.
220
+
221
+ ### Example
222
+
223
+ ```html
224
+ <cal-booking theme="light" dual time-slots time-format="12h"></cal-booking>
225
+ <script>
226
+ const el = document.querySelector('cal-booking');
227
+ el.bookings = [
228
+ { id: '1', start: '2026-03-05', end: '2026-03-10', label: 'Alice', color: 'blue' },
229
+ { id: '2', start: '2026-03-10', end: '2026-03-15', label: 'Bob', color: 'green' },
230
+ ];
231
+ el.labelFormula = (date) => {
232
+ const d = new Date(date);
233
+ return { label: (d.getDay() === 0 || d.getDay() === 6) ? '$150' : '$100' };
234
+ };
235
+ el.addEventListener('cal:change', (e) => {
236
+ console.log(e.detail.value);
237
+ // { start: "2026-03-16", end: "2026-03-20", startTime: "14:00", endTime: "11:00" }
238
+ });
239
+ </script>
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Component: cal-scheduler
245
+
246
+ Tag: <cal-scheduler>
247
+ Class: CalScheduler
248
+ Extends: CalendarBase → HTMLElement
249
+
250
+ ### Attributes (observedAttributes)
251
+
252
+ - theme: "light" | "dark" | "auto" (default: "light")
253
+ - view: "day" | "week" | "month" (default: "week")
254
+ - layout: "vertical" (default: "vertical")
255
+ - date: string (default: today()) — anchor date "YYYY-MM-DD"
256
+ - start-time: string (default: "08:00") — day grid start
257
+ - end-time: string (default: "18:00") — day grid end
258
+ - interval: number (default: 30) — slot interval in minutes
259
+ - format: "12h" | "24h" (default: "24h")
260
+ - first-day: number (default: 0)
261
+ - slot-height: number (default: 48) — pixels per time slot
262
+ - resource-mode: "tabs" | "columns" (default: "tabs")
263
+ - show-event-time: "true" | "false" (default: "true") — show time row in default event rendering
264
+ - show-fab: boolean attribute (default: absent) — floating action button
265
+ - draggable-events: boolean attribute (default: absent) — enable drag move/resize/create
266
+ - snap-interval: number | null (default: null, falls back to interval) — drag snap granularity in minutes
267
+ - min-duration: number | null (default: null, falls back to snap interval) — minimum event duration in minutes
268
+ - max-duration: number | null (default: null, no limit) — maximum event duration in minutes
269
+ - loading: boolean attribute (default: absent)
270
+
271
+ ### JS Properties
272
+
273
+ - resources: Resource[] — default: []
274
+ - events: Event[] — default: []
275
+ - eventActions: EventAction[] — default: []
276
+ - eventContent: ((event: Event, resource: Resource) => HTMLElement | string) | null — custom renderer (default: null)
277
+ - value: {date: string, startTime: string, endTime: string, resourceId: string, resource: Resource} | null — read-only, last selected slot
278
+ - loading: boolean — read/write
279
+
280
+ ### Event Object Shape
281
+
282
+ ```
283
+ {
284
+ id: string, // unique identifier
285
+ title: string, // display title
286
+ start: string, // "YYYY-MM-DD"
287
+ end?: string, // "YYYY-MM-DD" for multi-day events
288
+ startTime?: string, // "HH:MM" — omit for all-day events
289
+ endTime?: string, // "HH:MM" — omit for all-day events
290
+ resourceId?: string, // links to Resource.id
291
+ color?: "blue" | "green" | "red" | "orange" | "gray", // default: "blue"
292
+ locked?: boolean, // prevents drag move/resize (default: false)
293
+ metadata?: Record<string, string | number> // shown in detail popover
294
+ }
295
+ ```
296
+
297
+ All-day events: omit startTime and endTime. Rendered in collapsible all-day row (week view) or as chips (month view).
298
+
299
+ ### Resource Object Shape
300
+
301
+ ```
302
+ {
303
+ id: string,
304
+ name: string,
305
+ capacity?: number,
306
+ color?: "blue" | "green" | "red" | "orange" | "gray"
307
+ }
308
+ ```
309
+
310
+ ### EventAction Object Shape
311
+
312
+ ```
313
+ {
314
+ label: string, // button text, also used as action identifier in cal:event-action
315
+ type?: "danger" // applies red/destructive styling
316
+ }
317
+ ```
318
+
319
+ ### Methods
320
+
321
+ - goToDate(dateStr: string): void — navigate to date, emits cal:date-change
322
+ - setView(view: "day"|"week"|"month"): void — switch view, emits cal:view-change
323
+ - today(): void — navigate to today
324
+ - next(): void — advance by 1 day/week/month depending on current view
325
+ - prev(): void — go back by 1 day/week/month
326
+ - findAvailableSlot(opts: {date?: string, duration: number, resourceId?: string, minCapacity?: number}): {resourceId: string, date: string, startTime: string, endTime: string} | null — searches up to 14 days
327
+ - isSlotAvailable(date: string, startTime: string, endTime: string, resourceId: string): boolean — checks for time overlap with existing events
328
+ - showStatus(type: "error"|"warning"|"info"|"success", message: string, opts?: {autoDismiss?: number, dismissible?: boolean}): void
329
+ - clearStatus(): void
330
+
331
+ ### Events
332
+
333
+ - cal:slot-select — detail = {date: string, startTime: string|null, endTime: string|null, resourceId: string|null, resource: Resource|null}
334
+ Fires when an empty time slot is clicked. In month view, startTime/endTime are null.
335
+
336
+ - cal:slot-create — detail = {date: string, startTime: string, endTime: string, resourceId: string|null, resource: Resource|null}
337
+ Fires when drag-to-create completes (requires draggable-events).
338
+
339
+ - cal:event-click — detail = {event: Event, resourceId: string|null, resource: Resource|null}
340
+ Fires when an event block is clicked. Opens detail popover.
341
+
342
+ - cal:event-move — detail = {event: Event, from: {date, startTime, endTime, resourceId}, to: {date, startTime, endTime, resourceId}}
343
+ Fires when drag-to-move completes. The consumer must update events array.
344
+
345
+ - cal:event-resize — detail = {event: Event, from: {endTime: string}, to: {endTime: string}}
346
+ Fires when drag-to-resize completes. Only bottom-edge resize is supported.
347
+
348
+ - cal:event-action — detail = {action: string, event: Event, resourceId: string|null, resource: Resource|null}
349
+ Fires when an action button in the event detail popover is clicked.
350
+
351
+ - cal:fab-create — detail = {date: string, view: string}
352
+ Fires when the floating action button is clicked (requires show-fab).
353
+
354
+ - cal:date-change — detail = {date: string, view: string}
355
+ Fires on navigation (prev/next/today/goToDate).
356
+
357
+ - cal:view-change — detail = {view: string, date: string}
358
+ Fires when view changes (setView or nav button).
359
+
360
+ - cal:status — detail = {type: string|null, message: string|null}
361
+
362
+ ### Drag System Details
363
+
364
+ Enabled by `draggable-events` attribute. Uses pointer events with 4px threshold.
365
+
366
+ Move: creates a ghost clone at cursor position. Drop target resolved via data-date/data-time/data-resource-id attributes. Duration preserved. Emits cal:event-move.
367
+
368
+ Resize: bottom handle only. Floating time label follows cursor. Snaps to snap-interval (or interval). Enforces min-duration and max-duration. Emits cal:event-resize.
369
+
370
+ Create: drag on empty slot creates dashed preview block. Snaps to grid. Emits cal:slot-create on release.
371
+
372
+ Locked events (event.locked = true) cannot be moved or resized. They display a lock icon.
373
+
374
+ ### Resource Modes
375
+
376
+ - tabs: Resource tabs appear above grid. One resource visible at a time. "All" tab shows all.
377
+ - columns: All resources shown as side-by-side columns in day view.
378
+
379
+ ### Example
380
+
381
+ ```html
382
+ <cal-scheduler
383
+ view="week"
384
+ draggable-events
385
+ snap-interval="15"
386
+ show-fab
387
+ resource-mode="tabs"
388
+ format="12h"
389
+ theme="light"
390
+ ></cal-scheduler>
391
+ <script>
392
+ const sched = document.querySelector('cal-scheduler');
393
+ sched.resources = [
394
+ { id: 'r1', name: 'Room A', capacity: 10 },
395
+ { id: 'r2', name: 'Room B', capacity: 20 },
396
+ ];
397
+ sched.events = [
398
+ { id: '1', title: 'Standup', start: '2026-03-02', startTime: '09:00', endTime: '09:30', resourceId: 'r1', color: 'blue' },
399
+ { id: '2', title: 'Workshop', start: '2026-03-03', startTime: '13:00', endTime: '16:00', resourceId: 'r2', color: 'green', locked: true },
400
+ ];
401
+ sched.eventActions = [{ label: 'Edit' }, { label: 'Delete', type: 'danger' }];
402
+ sched.eventContent = (event, resource) => {
403
+ const el = document.createElement('div');
404
+ el.innerHTML = `<strong>${event.title}</strong><br><small>${resource?.name || ''}</small>`;
405
+ return el;
406
+ };
407
+
408
+ sched.addEventListener('cal:event-move', (e) => {
409
+ const { event, to } = e.detail;
410
+ const updated = sched.events.map(ev =>
411
+ ev.id === event.id ? { ...ev, start: to.date, startTime: to.startTime, endTime: to.endTime, resourceId: to.resourceId } : ev
412
+ );
413
+ sched.events = updated;
414
+ });
415
+
416
+ sched.addEventListener('cal:event-resize', (e) => {
417
+ const { event, to } = e.detail;
418
+ sched.events = sched.events.map(ev =>
419
+ ev.id === event.id ? { ...ev, endTime: to.endTime } : ev
420
+ );
421
+ });
422
+
423
+ sched.addEventListener('cal:slot-create', (e) => {
424
+ const { date, startTime, endTime, resourceId } = e.detail;
425
+ sched.events = [...sched.events, {
426
+ id: String(Date.now()), title: 'New Event',
427
+ start: date, startTime, endTime, resourceId, color: 'orange',
428
+ }];
429
+ });
430
+ </script>
431
+ ```
432
+
433
+ ---
434
+
435
+ ## Shared Base Class: CalendarBase
436
+
437
+ All components extend CalendarBase → HTMLElement.
438
+
439
+ ### Inherited Methods
440
+
441
+ - showStatus(type: "error"|"warning"|"info"|"success", message: string, opts?: {autoDismiss?: number, dismissible?: boolean}): void
442
+ Shows an inline status banner. autoDismiss is milliseconds.
443
+ - clearStatus(): void — clears the banner, emits cal:status with null values
444
+ - emit(name: string, detail?: object): void — dispatches CustomEvent with bubbles:true, composed:true
445
+
446
+ ### Inherited Event
447
+
448
+ - cal:status — detail = {type: string|null, message: string|null} — fires on showStatus and clearStatus
449
+
450
+ ---
451
+
452
+ ## Theming
453
+
454
+ Attribute: theme="light" | "dark" | "auto"
455
+
456
+ theme="auto" uses @media (prefers-color-scheme: dark) to switch.
457
+
458
+ All tokens are CSS custom properties set on :host. Values are raw HSL channels (e.g., "240 6% 10%") consumed as hsl(var(--cal-token)).
459
+
460
+ ### Core Tokens
461
+
462
+ - --cal-bg: background (light: 0 0% 100%, dark: 240 6% 10%)
463
+ - --cal-bg-muted: muted background (light: 240 5% 96%, dark: 240 4% 16%)
464
+ - --cal-fg: foreground text (light: 240 6% 10%, dark: 0 0% 98%)
465
+ - --cal-fg-muted: muted text (light: 240 4% 46%, dark: 240 4% 54%)
466
+ - --cal-border: borders (light: 240 6% 90%, dark: 240 4% 20%)
467
+ - --cal-accent: accent / selected state (light: 240 6% 10%, dark: 0 0% 98%)
468
+ - --cal-accent-fg: text on accent (light: 0 0% 100%, dark: 240 6% 10%)
469
+ - --cal-accent-subtle: subtle accent background (light: 240 5% 96%, dark: 240 4% 16%)
470
+ - --cal-hover: hover background (light: 240 5% 93%, dark: 240 4% 20%)
471
+ - --cal-ring: focus ring color (light: 240 6% 10%, dark: 0 0% 98%)
472
+ - --cal-radius: border radius (default: 8px)
473
+ - --cal-radius-sm: small border radius (default: 6px)
474
+ - --cal-cell-size: datepicker cell size (default: 36px)
475
+ - --cal-transition: transition timing (default: 150ms ease)
476
+
477
+ ### Booking Color Tokens (5 palettes)
478
+
479
+ Each palette has -bg, -fg, and -hover variants.
480
+
481
+ - --cal-booking-blue-bg / --cal-booking-blue-fg / --cal-booking-blue-hover
482
+ - --cal-booking-green-bg / --cal-booking-green-fg / --cal-booking-green-hover
483
+ - --cal-booking-red-bg / --cal-booking-red-fg / --cal-booking-red-hover
484
+ - --cal-booking-orange-bg / --cal-booking-orange-fg / --cal-booking-orange-hover
485
+ - --cal-booking-gray-bg / --cal-booking-gray-fg / --cal-booking-gray-hover
486
+
487
+ ### Scheduler Tokens
488
+
489
+ - --cal-sched-grid-line: grid line color
490
+ - --cal-sched-now-line: current time indicator color
491
+ - --cal-sched-slot-hover: slot hover background
492
+ - --cal-sched-header-bg: header/resource header background
493
+
494
+ ### Status Tokens (4 types × 3 variants)
495
+
496
+ - --cal-status-error-bg / --cal-status-error-fg / --cal-status-error-border
497
+ - --cal-status-warning-bg / --cal-status-warning-fg / --cal-status-warning-border
498
+ - --cal-status-info-bg / --cal-status-info-fg / --cal-status-info-border
499
+ - --cal-status-success-bg / --cal-status-success-fg / --cal-status-success-border
500
+
501
+ ### Override Example
502
+
503
+ ```css
504
+ cal-scheduler {
505
+ --cal-accent: 220 90% 56%;
506
+ --cal-accent-fg: 0 0% 100%;
507
+ --cal-radius: 12px;
508
+ --cal-sched-now-line: 142 70% 45%;
509
+ }
510
+ ```
511
+
512
+ ---
513
+
514
+ ## Data Shapes
515
+
516
+ ### Event
517
+
518
+ ```
519
+ {
520
+ id: string,
521
+ title: string,
522
+ start: string, // "YYYY-MM-DD"
523
+ end?: string, // "YYYY-MM-DD"
524
+ startTime?: string, // "HH:MM" — omit for all-day
525
+ endTime?: string, // "HH:MM" — omit for all-day
526
+ resourceId?: string,
527
+ color?: "blue" | "green" | "red" | "orange" | "gray",
528
+ locked?: boolean,
529
+ metadata?: Record<string, string | number>
530
+ }
531
+ ```
532
+
533
+ ### Resource
534
+
535
+ ```
536
+ {
537
+ id: string,
538
+ name: string,
539
+ capacity?: number,
540
+ color?: "blue" | "green" | "red" | "orange" | "gray"
541
+ }
542
+ ```
543
+
544
+ ### Booking
545
+
546
+ ```
547
+ {
548
+ id: string,
549
+ start: string,
550
+ end: string,
551
+ label?: string,
552
+ color?: "blue" | "green" | "red" | "orange" | "gray"
553
+ }
554
+ ```
555
+
556
+ ### TimeSlot
557
+
558
+ ```
559
+ {
560
+ time: string, // "HH:MM"
561
+ label?: string,
562
+ available?: boolean // default: true
563
+ }
564
+ ```
565
+
566
+ ### DayData
567
+
568
+ ```
569
+ {
570
+ [dateStr: string]: {
571
+ label?: string,
572
+ status?: string
573
+ }
574
+ }
575
+ ```
576
+
577
+ ### EventAction
578
+
579
+ ```
580
+ {
581
+ label: string,
582
+ type?: "danger"
583
+ }
584
+ ```
585
+
586
+ ---
587
+
588
+ ## Docs
589
+
590
+ - [cal-datepicker](docs/cal-datepicker.md)
591
+ - [cal-timepicker](docs/cal-timepicker.md)
592
+ - [cal-booking](docs/cal-booking.md)
593
+ - [cal-scheduler](docs/cal-scheduler.md)
594
+ - [Theming](docs/theming.md)
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "calkit",
3
+ "version": "0.1.0",
4
+ "description": "Vanilla JS web component library for date pickers, time pickers, booking calendars, and resource schedulers.",
5
+ "type": "module",
6
+ "main": "dist/calkit.umd.js",
7
+ "module": "dist/calkit.es.js",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/calkit.es.js",
11
+ "require": "./dist/calkit.umd.js"
12
+ },
13
+ "./datepicker": {
14
+ "import": "./dist/datepicker.es.js",
15
+ "require": "./dist/datepicker.umd.js"
16
+ },
17
+ "./timepicker": {
18
+ "import": "./dist/timepicker.es.js",
19
+ "require": "./dist/timepicker.umd.js"
20
+ },
21
+ "./booking": {
22
+ "import": "./dist/booking.es.js",
23
+ "require": "./dist/booking.umd.js"
24
+ },
25
+ "./scheduler": {
26
+ "import": "./dist/scheduler.es.js",
27
+ "require": "./dist/scheduler.umd.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "llms.txt"
34
+ ],
35
+ "keywords": [
36
+ "calendar",
37
+ "datepicker",
38
+ "timepicker",
39
+ "booking",
40
+ "scheduler",
41
+ "web-components",
42
+ "vanilla-js"
43
+ ],
44
+ "homepage": "https://github.com/SimonKefas/calkit",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/SimonKefas/calkit.git"
48
+ },
49
+ "license": "MIT",
50
+ "scripts": {
51
+ "dev": "vite",
52
+ "build": "vite build && vite build --config vite.datepicker.config.js && vite build --config vite.booking.config.js && vite build --config vite.timepicker.config.js && vite build --config vite.scheduler.config.js",
53
+ "preview": "vite preview"
54
+ },
55
+ "devDependencies": {
56
+ "vite": "^6.1.0"
57
+ }
58
+ }