@liteforge/calendar 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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +395 -0
  3. package/dist/calendar.d.ts +6 -0
  4. package/dist/calendar.d.ts.map +1 -0
  5. package/dist/calendar.js +318 -0
  6. package/dist/calendar.js.map +1 -0
  7. package/dist/components/toolbar.d.ts +18 -0
  8. package/dist/components/toolbar.d.ts.map +1 -0
  9. package/dist/components/toolbar.js +84 -0
  10. package/dist/components/toolbar.js.map +1 -0
  11. package/dist/date-utils.d.ts +104 -0
  12. package/dist/date-utils.d.ts.map +1 -0
  13. package/dist/date-utils.js +323 -0
  14. package/dist/date-utils.js.map +1 -0
  15. package/dist/index.d.ts +12 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +14 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/interactions/drag-drop.d.ts +30 -0
  20. package/dist/interactions/drag-drop.d.ts.map +1 -0
  21. package/dist/interactions/drag-drop.js +207 -0
  22. package/dist/interactions/drag-drop.js.map +1 -0
  23. package/dist/interactions/index.d.ts +10 -0
  24. package/dist/interactions/index.d.ts.map +1 -0
  25. package/dist/interactions/index.js +7 -0
  26. package/dist/interactions/index.js.map +1 -0
  27. package/dist/interactions/resize.d.ts +25 -0
  28. package/dist/interactions/resize.d.ts.map +1 -0
  29. package/dist/interactions/resize.js +116 -0
  30. package/dist/interactions/resize.js.map +1 -0
  31. package/dist/interactions/slot-selection.d.ts +25 -0
  32. package/dist/interactions/slot-selection.d.ts.map +1 -0
  33. package/dist/interactions/slot-selection.js +151 -0
  34. package/dist/interactions/slot-selection.js.map +1 -0
  35. package/dist/recurring.d.ts +15 -0
  36. package/dist/recurring.d.ts.map +1 -0
  37. package/dist/recurring.js +158 -0
  38. package/dist/recurring.js.map +1 -0
  39. package/dist/styles.d.ts +6 -0
  40. package/dist/styles.d.ts.map +1 -0
  41. package/dist/styles.js +632 -0
  42. package/dist/styles.js.map +1 -0
  43. package/dist/types.d.ts +169 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +5 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/views/agenda-view.d.ts +19 -0
  48. package/dist/views/agenda-view.d.ts.map +1 -0
  49. package/dist/views/agenda-view.js +114 -0
  50. package/dist/views/agenda-view.js.map +1 -0
  51. package/dist/views/day-view.d.ts +30 -0
  52. package/dist/views/day-view.d.ts.map +1 -0
  53. package/dist/views/day-view.js +432 -0
  54. package/dist/views/day-view.js.map +1 -0
  55. package/dist/views/month-view.d.ts +17 -0
  56. package/dist/views/month-view.d.ts.map +1 -0
  57. package/dist/views/month-view.js +123 -0
  58. package/dist/views/month-view.js.map +1 -0
  59. package/dist/views/shared.d.ts +30 -0
  60. package/dist/views/shared.d.ts.map +1 -0
  61. package/dist/views/shared.js +281 -0
  62. package/dist/views/shared.js.map +1 -0
  63. package/dist/views/week-view.d.ts +24 -0
  64. package/dist/views/week-view.d.ts.map +1 -0
  65. package/dist/views/week-view.js +377 -0
  66. package/dist/views/week-view.js.map +1 -0
  67. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SchildW3rk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,395 @@
1
+ # @liteforge/calendar
2
+
3
+ Signals-based scheduling calendar with multiple views, resources, and drag & drop for LiteForge.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @liteforge/calendar @liteforge/core @liteforge/runtime
9
+ ```
10
+
11
+ Peer dependencies: `@liteforge/core >= 0.1.0`, `@liteforge/runtime >= 0.1.0`
12
+
13
+ ## Overview
14
+
15
+ `@liteforge/calendar` provides a full-featured scheduling calendar with day, week, month, and agenda views. Supports resources (rooms, people), recurring events, and drag & drop.
16
+
17
+ ## Basic Usage
18
+
19
+ ```tsx
20
+ import { createCalendar } from '@liteforge/calendar'
21
+
22
+ const calendar = createCalendar({
23
+ events: () => appointments,
24
+ view: 'week',
25
+ onEventClick: (event) => openEventModal(event),
26
+ onSlotSelect: ({ start, end }) => createEvent(start, end)
27
+ })
28
+
29
+ // In JSX
30
+ <calendar.Root />
31
+ ```
32
+
33
+ ## API
34
+
35
+ ### createCalendar
36
+
37
+ Creates a reactive calendar instance.
38
+
39
+ ```ts
40
+ import { createCalendar } from '@liteforge/calendar'
41
+
42
+ const calendar = createCalendar<MyEvent>({
43
+ // Event data (signal or getter)
44
+ events: () => eventsQuery.data() ?? [],
45
+
46
+ // Initial view
47
+ view: 'week', // 'day' | 'week' | 'month' | 'agenda'
48
+
49
+ // Initial date
50
+ date: new Date(),
51
+
52
+ // Time configuration
53
+ time: {
54
+ dayStart: 8, // Start hour (0-23)
55
+ dayEnd: 20, // End hour (1-24)
56
+ slotDuration: 30, // Minutes per slot
57
+ weekStartsOn: 1 // 0 = Sunday, 1 = Monday
58
+ },
59
+
60
+ // Resources (rooms, people, etc.)
61
+ resources: [
62
+ { id: 'room-a', name: 'Room A', color: '#3b82f6' },
63
+ { id: 'room-b', name: 'Room B', color: '#10b981' }
64
+ ],
65
+
66
+ // Event field mapping (if different from defaults)
67
+ eventFields: {
68
+ id: 'id',
69
+ title: 'title',
70
+ start: 'startDate', // Map to your field names
71
+ end: 'endDate',
72
+ allDay: 'isAllDay',
73
+ resourceId: 'roomId',
74
+ color: 'eventColor'
75
+ },
76
+
77
+ // Callbacks
78
+ onEventClick: (event, e) => { ... },
79
+ onEventDoubleClick: (event, e) => { ... },
80
+ onSlotSelect: ({ start, end, resourceId }) => { ... },
81
+ onEventDrop: (event, { start, end, resourceId }) => { ... },
82
+ onEventResize: (event, { start, end }) => { ... },
83
+ onNavigate: (date, view) => { ... },
84
+
85
+ // Rendering
86
+ eventContent: (event) => (
87
+ <div class="custom-event">
88
+ <strong>{event.title}</strong>
89
+ <span>{event.location}</span>
90
+ </div>
91
+ ),
92
+
93
+ // Styling
94
+ classes: {
95
+ root: 'my-calendar',
96
+ header: 'calendar-header'
97
+ }
98
+ })
99
+ ```
100
+
101
+ ### Event Structure
102
+
103
+ Default event structure:
104
+
105
+ ```ts
106
+ interface CalendarEvent {
107
+ id: string | number
108
+ title: string
109
+ start: Date | string
110
+ end: Date | string
111
+ allDay?: boolean
112
+ resourceId?: string // For resource view
113
+ color?: string // Event color
114
+ recurring?: RecurringRule // For recurring events
115
+ }
116
+ ```
117
+
118
+ ### Calendar State
119
+
120
+ All state properties are signals:
121
+
122
+ ```ts
123
+ // View control
124
+ calendar.view() // Current view
125
+ calendar.setView('month')
126
+ calendar.date() // Current date
127
+ calendar.setDate(new Date())
128
+ calendar.today() // Go to today
129
+
130
+ // Navigation
131
+ calendar.next() // Next day/week/month
132
+ calendar.prev() // Previous day/week/month
133
+ calendar.goTo(date) // Navigate to specific date
134
+
135
+ // Date range
136
+ calendar.dateRange() // { start: Date, end: Date }
137
+
138
+ // Resources
139
+ calendar.resources() // All resources
140
+ calendar.selectedResources() // Currently filtered resources
141
+ calendar.selectResource(id)
142
+ calendar.deselectResource(id)
143
+ calendar.toggleResource(id)
144
+
145
+ // Events
146
+ calendar.events() // All events in current range
147
+ calendar.selectedEvent() // Currently selected event
148
+ calendar.selectEvent(event)
149
+ calendar.clearSelection()
150
+ ```
151
+
152
+ ### Views
153
+
154
+ **Day View:**
155
+ Single day with hourly slots.
156
+
157
+ **Week View:**
158
+ 7-day view with hourly slots per day.
159
+
160
+ **Month View:**
161
+ Full month grid with day cells.
162
+
163
+ **Agenda View:**
164
+ List of upcoming events.
165
+
166
+ ```ts
167
+ // Change view
168
+ calendar.setView('day')
169
+ calendar.setView('week')
170
+ calendar.setView('month')
171
+ calendar.setView('agenda')
172
+
173
+ // Custom view label
174
+ const viewLabels = {
175
+ day: 'Tag',
176
+ week: 'Woche',
177
+ month: 'Monat',
178
+ agenda: 'Liste'
179
+ }
180
+ ```
181
+
182
+ ### Resources
183
+
184
+ Group events by resource (rooms, people, equipment):
185
+
186
+ ```ts
187
+ const calendar = createCalendar({
188
+ events: () => appointments,
189
+ resources: [
190
+ {
191
+ id: 'dr-smith',
192
+ name: 'Dr. Smith',
193
+ color: '#3b82f6',
194
+ workingHours: {
195
+ monday: { start: '09:00', end: '17:00' },
196
+ tuesday: { start: '09:00', end: '17:00' }
197
+ // etc.
198
+ }
199
+ },
200
+ {
201
+ id: 'dr-jones',
202
+ name: 'Dr. Jones',
203
+ color: '#10b981'
204
+ }
205
+ ],
206
+ view: 'week' // Resources shown as columns in week view
207
+ })
208
+ ```
209
+
210
+ ### Recurring Events
211
+
212
+ ```ts
213
+ const recurringEvent = {
214
+ id: 'meeting-1',
215
+ title: 'Team Meeting',
216
+ start: '2024-01-15T10:00:00',
217
+ end: '2024-01-15T11:00:00',
218
+ recurring: {
219
+ frequency: 'weekly', // 'daily' | 'weekly' | 'monthly' | 'yearly'
220
+ interval: 1, // Every 1 week
221
+ byDay: ['MO', 'WE'], // Monday and Wednesday
222
+ until: '2024-12-31', // End date (optional)
223
+ count: 10 // Or number of occurrences
224
+ }
225
+ }
226
+
227
+ // Expand recurring events in a date range
228
+ import { expandRecurring } from '@liteforge/calendar'
229
+
230
+ const instances = expandRecurring(recurringEvent, {
231
+ start: new Date('2024-01-01'),
232
+ end: new Date('2024-03-31')
233
+ })
234
+ ```
235
+
236
+ ### Drag and Drop
237
+
238
+ Enable event dragging and resizing:
239
+
240
+ ```ts
241
+ const calendar = createCalendar({
242
+ events: () => appointments,
243
+
244
+ // Called when event is dropped to new time/resource
245
+ onEventDrop: async (event, { start, end, resourceId }) => {
246
+ await api.updateEvent(event.id, { start, end, resourceId })
247
+ refetchEvents()
248
+ },
249
+
250
+ // Called when event is resized
251
+ onEventResize: async (event, { start, end }) => {
252
+ await api.updateEvent(event.id, { start, end })
253
+ refetchEvents()
254
+ }
255
+ })
256
+ ```
257
+
258
+ ### Styling
259
+
260
+ **CSS Variables:**
261
+ ```css
262
+ :root {
263
+ --lf-calendar-border-color: #e5e7eb;
264
+ --lf-calendar-header-bg: #f9fafb;
265
+ --lf-calendar-today-bg: #eff6ff;
266
+ --lf-calendar-slot-height: 48px;
267
+ --lf-calendar-event-radius: 4px;
268
+ }
269
+ ```
270
+
271
+ **Custom classes:**
272
+ ```ts
273
+ const calendar = createCalendar({
274
+ events: () => appointments,
275
+ classes: {
276
+ root: 'rounded-lg shadow-lg',
277
+ header: 'bg-white border-b',
278
+ event: 'cursor-pointer hover:shadow-md'
279
+ }
280
+ })
281
+ ```
282
+
283
+ **Unstyled mode:**
284
+ ```ts
285
+ const calendar = createCalendar({
286
+ events: () => appointments,
287
+ unstyled: true // No default styles
288
+ })
289
+ ```
290
+
291
+ ## Date Utilities
292
+
293
+ The package exports date utilities for advanced usage:
294
+
295
+ ```ts
296
+ import {
297
+ startOfDay,
298
+ endOfDay,
299
+ startOfWeek,
300
+ endOfWeek,
301
+ startOfMonth,
302
+ endOfMonth,
303
+ addDays,
304
+ addWeeks,
305
+ addMonths,
306
+ isSameDay,
307
+ isToday,
308
+ formatTime,
309
+ formatDate
310
+ } from '@liteforge/calendar'
311
+ ```
312
+
313
+ ## Usage in Components
314
+
315
+ ```tsx
316
+ import { createComponent } from '@liteforge/runtime'
317
+ import { createQuery, createMutation } from '@liteforge/query'
318
+ import { createCalendar } from '@liteforge/calendar'
319
+
320
+ const AppointmentCalendar = createComponent({
321
+ component: () => {
322
+ const appointments = createQuery({
323
+ key: 'appointments',
324
+ fn: () => fetch('/api/appointments').then(r => r.json())
325
+ })
326
+
327
+ const updateAppointment = createMutation({
328
+ fn: (data) => fetch(`/api/appointments/${data.id}`, {
329
+ method: 'PATCH',
330
+ body: JSON.stringify(data)
331
+ }),
332
+ invalidate: ['appointments']
333
+ })
334
+
335
+ const calendar = createCalendar({
336
+ events: () => appointments.data() ?? [],
337
+ view: 'week',
338
+ resources: [
339
+ { id: 'room-1', name: 'Treatment Room 1' },
340
+ { id: 'room-2', name: 'Treatment Room 2' }
341
+ ],
342
+ onEventClick: (event) => {
343
+ openEditModal(event)
344
+ },
345
+ onSlotSelect: ({ start, end, resourceId }) => {
346
+ openCreateModal({ start, end, resourceId })
347
+ },
348
+ onEventDrop: (event, newTimes) => {
349
+ updateAppointment.mutate({ id: event.id, ...newTimes })
350
+ }
351
+ })
352
+
353
+ return (
354
+ <div>
355
+ <div class="toolbar">
356
+ <button onclick={() => calendar.prev()}>Previous</button>
357
+ <button onclick={() => calendar.today()}>Today</button>
358
+ <button onclick={() => calendar.next()}>Next</button>
359
+
360
+ <select onchange={(e) => calendar.setView(e.target.value)}>
361
+ <option value="day">Day</option>
362
+ <option value="week" selected>Week</option>
363
+ <option value="month">Month</option>
364
+ <option value="agenda">Agenda</option>
365
+ </select>
366
+ </div>
367
+
368
+ <calendar.Root />
369
+ </div>
370
+ )
371
+ }
372
+ })
373
+ ```
374
+
375
+ ## Types
376
+
377
+ ```ts
378
+ import type {
379
+ CalendarOptions,
380
+ CalendarResult,
381
+ CalendarEvent,
382
+ CalendarView,
383
+ CalendarClasses,
384
+ Resource,
385
+ WorkingHours,
386
+ TimeConfig,
387
+ RecurringRule,
388
+ DateRange,
389
+ SlotSelection
390
+ } from '@liteforge/calendar'
391
+ ```
392
+
393
+ ## License
394
+
395
+ MIT
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @liteforge/calendar - createCalendar Implementation
3
+ */
4
+ import type { CalendarOptions, CalendarResult, CalendarEvent } from './types.js';
5
+ export declare function createCalendar<T extends CalendarEvent>(options: CalendarOptions<T>): CalendarResult<T>;
6
+ //# sourceMappingURL=calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../src/calendar.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EAKd,MAAM,YAAY,CAAA;AAyDnB,wBAAgB,cAAc,CAAC,CAAC,SAAS,aAAa,EACpD,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAC1B,cAAc,CAAC,CAAC,CAAC,CAqWnB"}