@mrintel/villain-ui 0.3.0 → 0.7.1

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 (140) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +3490 -1296
  3. package/dist/components/buttons/Button.svelte +27 -33
  4. package/dist/components/buttons/Button.svelte.d.ts +4 -1
  5. package/dist/components/buttons/ButtonGroup.svelte +17 -30
  6. package/dist/components/buttons/FloatingActionButton.svelte +20 -44
  7. package/dist/components/buttons/FloatingActionButton.svelte.d.ts +2 -1
  8. package/dist/components/buttons/IconButton.svelte +23 -53
  9. package/dist/components/buttons/IconButton.svelte.d.ts +2 -1
  10. package/dist/components/buttons/LinkButton.svelte +24 -37
  11. package/dist/components/buttons/LinkButton.svelte.d.ts +4 -1
  12. package/dist/components/buttons/buttonClasses.d.ts +5 -0
  13. package/dist/components/buttons/buttonClasses.js +8 -3
  14. package/dist/components/cards/Card.svelte +54 -46
  15. package/dist/components/cards/Card.svelte.d.ts +9 -2
  16. package/dist/components/cards/Container.svelte +17 -33
  17. package/dist/components/cards/Divider.svelte +36 -52
  18. package/dist/components/cards/Divider.svelte.d.ts +2 -0
  19. package/dist/components/cards/Grid.svelte +55 -44
  20. package/dist/components/cards/Panel.svelte +18 -32
  21. package/dist/components/cards/Panel.svelte.d.ts +2 -1
  22. package/dist/components/cards/SectionHeader.svelte +24 -38
  23. package/dist/components/cards/SectionHeader.svelte.d.ts +1 -0
  24. package/dist/components/data/Avatar.svelte +48 -67
  25. package/dist/components/data/Badge.svelte +45 -32
  26. package/dist/components/data/Badge.svelte.d.ts +7 -1
  27. package/dist/components/data/CalendarGrid.svelte +433 -0
  28. package/dist/components/data/CalendarGrid.svelte.d.ts +25 -0
  29. package/dist/components/data/CalendarGrid.types.d.ts +7 -0
  30. package/dist/components/data/CalendarGrid.types.js +1 -0
  31. package/dist/components/data/CodeBlock.svelte +119 -121
  32. package/dist/components/data/CodeBlock.svelte.d.ts +8 -0
  33. package/dist/components/data/List.svelte +87 -64
  34. package/dist/components/data/List.svelte.d.ts +7 -0
  35. package/dist/components/data/Pagination.svelte +121 -123
  36. package/dist/components/data/Pagination.svelte.d.ts +5 -0
  37. package/dist/components/data/Sparkline.svelte +117 -0
  38. package/dist/components/data/Sparkline.svelte.d.ts +43 -0
  39. package/dist/components/data/Stat.svelte +92 -103
  40. package/dist/components/data/Table.svelte +443 -76
  41. package/dist/components/data/Table.svelte.d.ts +23 -2
  42. package/dist/components/data/Table.types.d.ts +14 -0
  43. package/dist/components/data/Table.types.js +1 -0
  44. package/dist/components/data/Tag.svelte +51 -53
  45. package/dist/components/data/Tag.svelte.d.ts +5 -1
  46. package/dist/components/data/index.d.ts +4 -0
  47. package/dist/components/data/index.js +2 -0
  48. package/dist/components/forms/Checkbox.svelte +39 -51
  49. package/dist/components/forms/Checkbox.svelte.d.ts +3 -1
  50. package/dist/components/forms/DatePicker.svelte +61 -0
  51. package/dist/components/forms/DatePicker.svelte.d.ts +15 -0
  52. package/dist/components/forms/DateTimePicker.svelte +63 -0
  53. package/dist/components/forms/DateTimePicker.svelte.d.ts +16 -0
  54. package/dist/components/forms/FileUpload.svelte +136 -164
  55. package/dist/components/forms/FileUpload.svelte.d.ts +1 -0
  56. package/dist/components/forms/Input.svelte +284 -57
  57. package/dist/components/forms/Input.svelte.d.ts +10 -3
  58. package/dist/components/forms/InputGroup.svelte +7 -7
  59. package/dist/components/forms/RadioGroup.svelte +77 -87
  60. package/dist/components/forms/RadioGroup.svelte.d.ts +3 -1
  61. package/dist/components/forms/RangeSlider.svelte +90 -116
  62. package/dist/components/forms/Select.svelte +106 -71
  63. package/dist/components/forms/Select.svelte.d.ts +3 -1
  64. package/dist/components/forms/Step.svelte +25 -0
  65. package/dist/components/forms/Step.svelte.d.ts +12 -0
  66. package/dist/components/forms/StepContext.d.ts +3 -0
  67. package/dist/components/forms/StepContext.js +5 -0
  68. package/dist/components/forms/Stepper.types.d.ts +37 -0
  69. package/dist/components/forms/Stepper.types.js +1 -0
  70. package/dist/components/forms/StepperForm.svelte +183 -0
  71. package/dist/components/forms/StepperForm.svelte.d.ts +17 -0
  72. package/dist/components/forms/Switch.svelte +44 -56
  73. package/dist/components/forms/Switch.svelte.d.ts +3 -1
  74. package/dist/components/forms/Textarea.svelte +52 -57
  75. package/dist/components/forms/Textarea.svelte.d.ts +3 -1
  76. package/dist/components/forms/TimePicker.svelte +63 -0
  77. package/dist/components/forms/TimePicker.svelte.d.ts +16 -0
  78. package/dist/components/forms/formClasses.d.ts +3 -0
  79. package/dist/components/forms/formClasses.js +3 -0
  80. package/dist/components/forms/index.d.ts +6 -0
  81. package/dist/components/forms/index.js +5 -0
  82. package/dist/components/navigation/Breadcrumbs.svelte +56 -59
  83. package/dist/components/navigation/Breadcrumbs.svelte.d.ts +1 -0
  84. package/dist/components/navigation/ContextMenu.svelte +133 -83
  85. package/dist/components/navigation/ContextMenu.svelte.d.ts +8 -1
  86. package/dist/components/navigation/DropdownMenu.svelte +139 -80
  87. package/dist/components/navigation/DropdownMenu.svelte.d.ts +8 -1
  88. package/dist/components/navigation/Menu.svelte +72 -48
  89. package/dist/components/navigation/Navbar.svelte +111 -32
  90. package/dist/components/navigation/Navbar.svelte.d.ts +6 -0
  91. package/dist/components/navigation/Sidebar.svelte +236 -35
  92. package/dist/components/navigation/Sidebar.svelte.d.ts +2 -0
  93. package/dist/components/navigation/Stepper.svelte +204 -0
  94. package/dist/components/navigation/Stepper.svelte.d.ts +34 -0
  95. package/dist/components/navigation/Tabs.svelte +86 -54
  96. package/dist/components/navigation/Tabs.svelte.d.ts +5 -1
  97. package/dist/components/navigation/index.d.ts +1 -0
  98. package/dist/components/navigation/index.js +1 -0
  99. package/dist/components/overlays/Alert.svelte +81 -99
  100. package/dist/components/overlays/Alert.svelte.d.ts +5 -1
  101. package/dist/components/overlays/CommandPalette.svelte +182 -217
  102. package/dist/components/overlays/Drawer.svelte +158 -167
  103. package/dist/components/overlays/Drawer.svelte.d.ts +3 -1
  104. package/dist/components/overlays/Dropdown.svelte +62 -30
  105. package/dist/components/overlays/Dropdown.svelte.d.ts +2 -0
  106. package/dist/components/overlays/Modal.svelte +125 -130
  107. package/dist/components/overlays/Modal.svelte.d.ts +3 -1
  108. package/dist/components/overlays/Popover.svelte +106 -131
  109. package/dist/components/overlays/ProgressBar.svelte +29 -45
  110. package/dist/components/overlays/SkeletonLoader.svelte +66 -82
  111. package/dist/components/overlays/Spinner.svelte +33 -43
  112. package/dist/components/overlays/Toast.svelte +111 -140
  113. package/dist/components/overlays/Toast.svelte.d.ts +3 -0
  114. package/dist/components/overlays/Tooltip.svelte +94 -115
  115. package/dist/components/overlays/Tooltip.svelte.d.ts +3 -1
  116. package/dist/components/typography/Code.svelte +10 -14
  117. package/dist/components/typography/Heading.svelte +15 -22
  118. package/dist/components/typography/Heading.svelte.d.ts +1 -0
  119. package/dist/components/typography/Text.svelte +21 -24
  120. package/dist/components/typography/Text.svelte.d.ts +2 -1
  121. package/dist/components/utilities/Accordion.svelte +54 -67
  122. package/dist/components/utilities/Accordion.svelte.d.ts +4 -1
  123. package/dist/components/utilities/Carousel.svelte +124 -152
  124. package/dist/components/utilities/Collapse.svelte +46 -60
  125. package/dist/components/utilities/Hero.svelte +42 -0
  126. package/dist/components/utilities/Hero.svelte.d.ts +10 -0
  127. package/dist/components/utilities/Portal.svelte +47 -72
  128. package/dist/components/utilities/ScrollArea.svelte +33 -41
  129. package/dist/components/utilities/SystemConsole.svelte +310 -0
  130. package/dist/components/utilities/SystemConsole.svelte.d.ts +20 -0
  131. package/dist/components/utilities/SystemInterface.svelte +726 -0
  132. package/dist/components/utilities/SystemInterface.svelte.d.ts +19 -0
  133. package/dist/components/utilities/index.d.ts +4 -0
  134. package/dist/components/utilities/index.js +3 -0
  135. package/dist/components/utilities/utilities.types.d.ts +46 -0
  136. package/dist/components/utilities/utilities.types.js +4 -0
  137. package/dist/index.d.ts +57 -5
  138. package/dist/index.js +5 -5
  139. package/dist/theme.css +2889 -218
  140. package/package.json +83 -76
@@ -0,0 +1,433 @@
1
+ <script lang="ts">let { month = $bindable(new Date()), events = [], selectedDate = $bindable(undefined), onDateSelect, onMonthChange, renderCell, weekStartsOn = 0, showWeekNumbers = false, highlightToday = true, class: className = '' } = $props();
2
+ const today = new Date();
3
+ today.setHours(0, 0, 0, 0);
4
+ // Get calendar days for the current month
5
+ const calendarDays = $derived.by(() => {
6
+ const year = month.getFullYear();
7
+ const monthIndex = month.getMonth();
8
+ const firstDay = new Date(year, monthIndex, 1);
9
+ const lastDay = new Date(year, monthIndex + 1, 0);
10
+ const startingDayOfWeek = firstDay.getDay();
11
+ const daysInMonth = lastDay.getDate();
12
+ // Adjust for week start day
13
+ const offset = weekStartsOn === 1 ? (startingDayOfWeek === 0 ? 6 : startingDayOfWeek - 1) : startingDayOfWeek;
14
+ const days = [];
15
+ // Previous month days
16
+ const prevMonthLastDay = new Date(year, monthIndex, 0);
17
+ for (let i = offset - 1; i >= 0; i--) {
18
+ days.push(new Date(year, monthIndex - 1, prevMonthLastDay.getDate() - i));
19
+ }
20
+ // Current month days
21
+ for (let i = 1; i <= daysInMonth; i++) {
22
+ days.push(new Date(year, monthIndex, i));
23
+ }
24
+ // Next month days to fill grid
25
+ const remainingCells = 42 - days.length; // 6 weeks * 7 days
26
+ for (let i = 1; i <= remainingCells; i++) {
27
+ days.push(new Date(year, monthIndex + 1, i));
28
+ }
29
+ return days;
30
+ });
31
+ // Group events by date string
32
+ const eventsByDate = $derived.by(() => {
33
+ const map = new Map();
34
+ events.forEach((event) => {
35
+ const eventDate = typeof event.date === 'string' ? new Date(event.date) : event.date;
36
+ const key = eventDate.toISOString().split('T')[0];
37
+ if (!map.has(key)) {
38
+ map.set(key, []);
39
+ }
40
+ map.get(key).push(event);
41
+ });
42
+ return map;
43
+ });
44
+ function isSameDay(date1, date2) {
45
+ return (date1.getFullYear() === date2.getFullYear() &&
46
+ date1.getMonth() === date2.getMonth() &&
47
+ date1.getDate() === date2.getDate());
48
+ }
49
+ function isSameMonth(date) {
50
+ return date.getMonth() === month.getMonth() && date.getFullYear() === month.getFullYear();
51
+ }
52
+ function getCellData(date) {
53
+ const dateKey = date.toISOString().split('T')[0];
54
+ const cellEvents = eventsByDate.get(dateKey) || [];
55
+ return {
56
+ date,
57
+ events: cellEvents,
58
+ isToday: highlightToday && isSameDay(date, today),
59
+ isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
60
+ isCurrentMonth: isSameMonth(date),
61
+ isEmpty: cellEvents.length === 0 && !isSameMonth(date)
62
+ };
63
+ }
64
+ function handleDateClick(date, isCurrentMonth) {
65
+ if (!isCurrentMonth) {
66
+ // Navigate to that month
67
+ const newMonth = new Date(date);
68
+ month = newMonth;
69
+ onMonthChange?.(newMonth);
70
+ }
71
+ selectedDate = date;
72
+ onDateSelect?.(date);
73
+ }
74
+ function handleKeyDown(event, date, index) {
75
+ const days = calendarDays;
76
+ let newIndex = index;
77
+ switch (event.key) {
78
+ case 'ArrowLeft':
79
+ event.preventDefault();
80
+ newIndex = index > 0 ? index - 1 : index;
81
+ break;
82
+ case 'ArrowRight':
83
+ event.preventDefault();
84
+ newIndex = index < days.length - 1 ? index + 1 : index;
85
+ break;
86
+ case 'ArrowUp':
87
+ event.preventDefault();
88
+ newIndex = index >= 7 ? index - 7 : index;
89
+ break;
90
+ case 'ArrowDown':
91
+ event.preventDefault();
92
+ newIndex = index + 7 < days.length ? index + 7 : index;
93
+ break;
94
+ case 'Home':
95
+ event.preventDefault();
96
+ newIndex = Math.floor(index / 7) * 7;
97
+ break;
98
+ case 'End':
99
+ event.preventDefault();
100
+ newIndex = Math.floor(index / 7) * 7 + 6;
101
+ break;
102
+ case 'Enter':
103
+ case ' ':
104
+ event.preventDefault();
105
+ handleDateClick(date, isSameMonth(date));
106
+ return;
107
+ default:
108
+ return;
109
+ }
110
+ if (newIndex !== index) {
111
+ const newDate = days[newIndex];
112
+ requestAnimationFrame(() => {
113
+ const cell = document.querySelector(`[data-date="${newDate.toISOString()}"]`);
114
+ cell?.focus();
115
+ });
116
+ }
117
+ }
118
+ function previousMonth() {
119
+ const newMonth = new Date(month.getFullYear(), month.getMonth() - 1, 1);
120
+ month = newMonth;
121
+ onMonthChange?.(newMonth);
122
+ }
123
+ function nextMonth() {
124
+ const newMonth = new Date(month.getFullYear(), month.getMonth() + 1, 1);
125
+ month = newMonth;
126
+ onMonthChange?.(newMonth);
127
+ }
128
+ const weekDayNames = $derived(weekStartsOn === 1
129
+ ? ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
130
+ : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']);
131
+ const monthNames = [
132
+ 'January',
133
+ 'February',
134
+ 'March',
135
+ 'April',
136
+ 'May',
137
+ 'June',
138
+ 'July',
139
+ 'August',
140
+ 'September',
141
+ 'October',
142
+ 'November',
143
+ 'December'
144
+ ];
145
+ const currentMonthYear = $derived(`${monthNames[month.getMonth()]} ${month.getFullYear()}`);
146
+ const variantColors = {
147
+ default: 'var(--color-base-3)',
148
+ success: 'var(--color-success)',
149
+ warning: 'var(--color-warning)',
150
+ error: 'var(--color-error)',
151
+ accent: 'var(--color-accent)'
152
+ };
153
+ export {};
154
+ </script>
155
+
156
+ <div class="calendar-grid {className}">
157
+ <!-- Header with month navigation -->
158
+ <div class="calendar-header">
159
+ <button
160
+ type="button"
161
+ onclick={previousMonth}
162
+ class="nav-button"
163
+ aria-label="Previous month"
164
+ >
165
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
166
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
167
+ </svg>
168
+ </button>
169
+
170
+ <h2 class="month-title">{currentMonthYear}</h2>
171
+
172
+ <button
173
+ type="button"
174
+ onclick={nextMonth}
175
+ class="nav-button"
176
+ aria-label="Next month"
177
+ >
178
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
179
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
180
+ </svg>
181
+ </button>
182
+ </div>
183
+
184
+ <!-- Calendar grid -->
185
+ <div role="grid" aria-label="Calendar" class="calendar-body">
186
+ <!-- Week day headers -->
187
+ <div role="row" class="week-header">
188
+ {#if showWeekNumbers}
189
+ <div class="week-number-header"></div>
190
+ {/if}
191
+ {#each weekDayNames as day}
192
+ <div role="columnheader" class="day-header">
193
+ {day}
194
+ </div>
195
+ {/each}
196
+ </div>
197
+
198
+ <!-- Date cells -->
199
+ {#each { length: 6 } as _, weekIndex}
200
+ <div role="row" class="calendar-week">
201
+ {#if showWeekNumbers}
202
+ <div class="week-number">W{weekIndex + 1}</div>
203
+ {/if}
204
+ {#each calendarDays.slice(weekIndex * 7, (weekIndex + 1) * 7) as date, dayIndex}
205
+ {@const cellData = getCellData(date)}
206
+ {@const globalIndex = weekIndex * 7 + dayIndex}
207
+ <button
208
+ role="gridcell"
209
+ type="button"
210
+ data-date={date.toISOString()}
211
+ class="calendar-cell"
212
+ class:current-month={cellData.isCurrentMonth}
213
+ class:other-month={!cellData.isCurrentMonth}
214
+ class:is-today={cellData.isToday}
215
+ class:is-selected={cellData.isSelected}
216
+ class:has-events={cellData.events.length > 0}
217
+ tabindex={globalIndex === 0 ? 0 : -1}
218
+ onclick={() => handleDateClick(date, cellData.isCurrentMonth)}
219
+ onkeydown={(e) => handleKeyDown(e, date, globalIndex)}
220
+ aria-label="{date.getDate()} {monthNames[date.getMonth()]} {date.getFullYear()}"
221
+ aria-selected={cellData.isSelected}
222
+ >
223
+ {#if renderCell}
224
+ {@render renderCell(cellData)}
225
+ {:else}
226
+ <div class="cell-content">
227
+ <span class="day-number">{date.getDate()}</span>
228
+ {#if cellData.events.length > 0}
229
+ <div class="event-indicators">
230
+ {#each cellData.events.slice(0, 3) as event}
231
+ <span
232
+ class="event-dot"
233
+ style="background-color: {variantColors[event.variant || 'default']}"
234
+ title={event.title}
235
+ ></span>
236
+ {/each}
237
+ {#if cellData.events.length > 3}
238
+ <span class="event-more">+{cellData.events.length - 3}</span>
239
+ {/if}
240
+ </div>
241
+ {/if}
242
+ </div>
243
+ {/if}
244
+ </button>
245
+ {/each}
246
+ </div>
247
+ {/each}
248
+ </div>
249
+ </div>
250
+
251
+ <style>
252
+ .calendar-grid {
253
+ width: 100%;
254
+ font-family: var(--font-body);
255
+ color: var(--color-text);
256
+ }
257
+
258
+ .calendar-header {
259
+ display: flex;
260
+ align-items: center;
261
+ justify-content: space-between;
262
+ padding: 1.5rem;
263
+ border-bottom: 1px solid var(--color-border);
264
+ }
265
+
266
+ .month-title {
267
+ font-family: var(--font-heading);
268
+ font-size: 1.5rem;
269
+ font-weight: 700;
270
+ color: var(--color-text);
271
+ margin: 0;
272
+ }
273
+
274
+ .nav-button {
275
+ display: flex;
276
+ align-items: center;
277
+ justify-content: center;
278
+ width: 2.5rem;
279
+ height: 2.5rem;
280
+ background: transparent;
281
+ border: 1px solid var(--color-border);
282
+ border-radius: var(--radius-md);
283
+ color: var(--color-text-soft);
284
+ cursor: pointer;
285
+ transition: all var(--duration-200) var(--ease-sharp);
286
+ }
287
+
288
+ .nav-button:hover {
289
+ background: var(--color-base-3);
290
+ color: var(--color-accent);
291
+ border-color: var(--color-accent);
292
+ }
293
+
294
+ .nav-button:active {
295
+ transform: scale(0.95);
296
+ }
297
+
298
+ .calendar-body {
299
+ padding: 1rem;
300
+ }
301
+
302
+ .week-header {
303
+ display: grid;
304
+ grid-template-columns: repeat(7, 1fr);
305
+ gap: 0.5rem;
306
+ margin-bottom: 0.5rem;
307
+ }
308
+
309
+ .week-header.with-numbers {
310
+ grid-template-columns: 2.5rem repeat(7, 1fr);
311
+ }
312
+
313
+ .day-header {
314
+ text-align: center;
315
+ font-size: 0.875rem;
316
+ font-weight: 600;
317
+ color: var(--color-text-soft);
318
+ text-transform: uppercase;
319
+ letter-spacing: 0.05em;
320
+ padding: 0.5rem;
321
+ }
322
+
323
+ .calendar-week {
324
+ display: grid;
325
+ grid-template-columns: repeat(7, 1fr);
326
+ gap: 0.5rem;
327
+ margin-bottom: 0.5rem;
328
+ }
329
+
330
+ .week-number-header,
331
+ .week-number {
332
+ display: flex;
333
+ align-items: center;
334
+ justify-content: center;
335
+ font-size: 0.75rem;
336
+ font-weight: 600;
337
+ color: var(--color-text-muted);
338
+ }
339
+
340
+ .calendar-cell {
341
+ position: relative;
342
+ aspect-ratio: 1;
343
+ background: var(--color-base-1);
344
+ border: 1px solid var(--color-border);
345
+ border-radius: var(--radius-md);
346
+ padding: 0.5rem;
347
+ cursor: pointer;
348
+ transition: all var(--duration-200) var(--ease-sharp);
349
+ font-family: inherit;
350
+ color: inherit;
351
+ }
352
+
353
+ .calendar-cell:hover {
354
+ background: var(--color-base-2);
355
+ border-color: var(--color-accent-soft);
356
+ transform: translateY(-2px);
357
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
358
+ }
359
+
360
+ .calendar-cell:focus-visible {
361
+ outline: 2px solid var(--color-accent);
362
+ outline-offset: 2px;
363
+ z-index: 1;
364
+ }
365
+
366
+ .calendar-cell.other-month {
367
+ opacity: 0.4;
368
+ }
369
+
370
+ .calendar-cell.is-today {
371
+ background: var(--color-accent-overlay-10);
372
+ border-color: var(--color-accent);
373
+ }
374
+
375
+ .calendar-cell.is-selected {
376
+ background: var(--color-accent);
377
+ border-color: var(--color-accent);
378
+ color: var(--color-text);
379
+ box-shadow: 0 0 20px var(--color-accent-glow);
380
+ }
381
+
382
+ .calendar-cell.is-selected .day-number {
383
+ color: var(--color-base-0);
384
+ font-weight: 700;
385
+ }
386
+
387
+ .cell-content {
388
+ display: flex;
389
+ flex-direction: column;
390
+ align-items: center;
391
+ justify-content: space-between;
392
+ height: 100%;
393
+ gap: 0.25rem;
394
+ }
395
+
396
+ .day-number {
397
+ font-size: 0.875rem;
398
+ font-weight: 600;
399
+ color: var(--color-text);
400
+ }
401
+
402
+ .event-indicators {
403
+ display: flex;
404
+ gap: 0.25rem;
405
+ align-items: center;
406
+ flex-wrap: wrap;
407
+ justify-content: center;
408
+ }
409
+
410
+ .event-dot {
411
+ width: 0.375rem;
412
+ height: 0.375rem;
413
+ border-radius: 50%;
414
+ background: var(--color-accent);
415
+ box-shadow: 0 0 6px currentColor;
416
+ }
417
+
418
+ .event-more {
419
+ font-size: 0.625rem;
420
+ color: var(--color-text-muted);
421
+ font-weight: 600;
422
+ }
423
+
424
+ /* Accessibility: Reduced motion */
425
+ @media (prefers-reduced-motion: reduce) {
426
+ .calendar-cell {
427
+ transition: none;
428
+ }
429
+
430
+ .calendar-cell:hover {
431
+ transform: none;
432
+ }
433
+ }</style>
@@ -0,0 +1,25 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { CalendarEvent } from './CalendarGrid.types';
3
+ interface CellData {
4
+ date: Date;
5
+ events: CalendarEvent[];
6
+ isToday: boolean;
7
+ isSelected: boolean;
8
+ isCurrentMonth: boolean;
9
+ isEmpty: boolean;
10
+ }
11
+ interface Props {
12
+ month?: Date;
13
+ events?: CalendarEvent[];
14
+ selectedDate?: Date;
15
+ onDateSelect?: (date: Date) => void;
16
+ onMonthChange?: (date: Date) => void;
17
+ renderCell?: Snippet<[CellData]>;
18
+ weekStartsOn?: 0 | 1;
19
+ showWeekNumbers?: boolean;
20
+ highlightToday?: boolean;
21
+ class?: string;
22
+ }
23
+ declare const CalendarGrid: import("svelte").Component<Props, {}, "month" | "selectedDate">;
24
+ type CalendarGrid = ReturnType<typeof CalendarGrid>;
25
+ export default CalendarGrid;
@@ -0,0 +1,7 @@
1
+ export interface CalendarEvent {
2
+ id: string;
3
+ date: Date | string;
4
+ title?: string;
5
+ variant?: 'default' | 'success' | 'warning' | 'error' | 'accent';
6
+ metadata?: any;
7
+ }
@@ -0,0 +1 @@
1
+ export {};