@mrintel/villain-ui 0.2.2 → 0.6.3

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 (159) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +3490 -1296
  3. package/dist/components/buttons/Button.svelte +27 -0
  4. package/dist/components/buttons/Button.svelte.d.ts +14 -0
  5. package/dist/components/buttons/ButtonGroup.svelte +17 -0
  6. package/dist/components/buttons/ButtonGroup.svelte.d.ts +8 -0
  7. package/dist/components/buttons/FloatingActionButton.svelte +20 -0
  8. package/dist/components/buttons/FloatingActionButton.svelte.d.ts +12 -0
  9. package/dist/components/buttons/IconButton.svelte +23 -0
  10. package/dist/components/buttons/IconButton.svelte.d.ts +14 -0
  11. package/dist/components/buttons/LinkButton.svelte +24 -0
  12. package/dist/components/buttons/LinkButton.svelte.d.ts +15 -0
  13. package/dist/components/buttons/buttonClasses.d.ts +15 -0
  14. package/dist/components/buttons/buttonClasses.js +15 -0
  15. package/dist/components/buttons/index.d.ts +5 -0
  16. package/dist/components/buttons/index.js +5 -0
  17. package/dist/components/cards/Card.svelte +60 -0
  18. package/dist/components/cards/Card.svelte.d.ts +15 -0
  19. package/dist/components/cards/Container.svelte +17 -0
  20. package/dist/components/cards/Container.svelte.d.ts +10 -0
  21. package/dist/components/cards/Divider.svelte +36 -0
  22. package/dist/components/cards/Divider.svelte.d.ts +11 -0
  23. package/dist/components/cards/Grid.svelte +55 -0
  24. package/dist/components/cards/Grid.svelte.d.ts +10 -0
  25. package/dist/components/cards/Panel.svelte +18 -0
  26. package/dist/components/cards/Panel.svelte.d.ts +11 -0
  27. package/dist/components/cards/SectionHeader.svelte +24 -0
  28. package/dist/components/cards/SectionHeader.svelte.d.ts +12 -0
  29. package/dist/components/cards/index.d.ts +6 -0
  30. package/dist/components/cards/index.js +6 -0
  31. package/dist/components/data/Avatar.svelte +48 -0
  32. package/dist/components/data/Avatar.svelte.d.ts +10 -0
  33. package/dist/components/data/Badge.svelte +45 -0
  34. package/dist/components/data/Badge.svelte.d.ts +14 -0
  35. package/dist/components/data/CalendarGrid.svelte +433 -0
  36. package/dist/components/data/CalendarGrid.svelte.d.ts +25 -0
  37. package/dist/components/data/CalendarGrid.types.d.ts +7 -0
  38. package/dist/components/data/CalendarGrid.types.js +1 -0
  39. package/dist/components/data/CodeBlock.svelte +119 -0
  40. package/dist/components/data/CodeBlock.svelte.d.ts +40 -0
  41. package/dist/components/data/List.svelte +87 -0
  42. package/dist/components/data/List.svelte.d.ts +15 -0
  43. package/dist/components/data/Pagination.svelte +121 -0
  44. package/dist/components/data/Pagination.svelte.d.ts +14 -0
  45. package/dist/components/data/Sparkline.svelte +117 -0
  46. package/dist/components/data/Sparkline.svelte.d.ts +43 -0
  47. package/dist/components/data/Stat.svelte +92 -0
  48. package/dist/components/data/Stat.svelte.d.ts +11 -0
  49. package/dist/components/data/Table.svelte +443 -0
  50. package/dist/components/data/Table.svelte.d.ts +30 -0
  51. package/dist/components/data/Table.types.d.ts +14 -0
  52. package/dist/components/data/Table.types.js +1 -0
  53. package/dist/components/data/Tag.svelte +51 -0
  54. package/dist/components/data/Tag.svelte.d.ts +13 -0
  55. package/dist/components/data/index.d.ts +12 -0
  56. package/dist/components/data/index.js +10 -0
  57. package/dist/components/forms/Checkbox.svelte +39 -0
  58. package/dist/components/forms/Checkbox.svelte.d.ts +12 -0
  59. package/dist/components/forms/DatePicker.svelte +61 -0
  60. package/dist/components/forms/DatePicker.svelte.d.ts +15 -0
  61. package/dist/components/forms/DateTimePicker.svelte +63 -0
  62. package/dist/components/forms/DateTimePicker.svelte.d.ts +16 -0
  63. package/dist/components/forms/FileUpload.svelte +136 -0
  64. package/dist/components/forms/FileUpload.svelte.d.ts +23 -0
  65. package/dist/components/forms/Input.svelte +282 -0
  66. package/dist/components/forms/Input.svelte.d.ts +19 -0
  67. package/dist/components/forms/InputGroup.svelte +7 -0
  68. package/dist/components/forms/InputGroup.svelte.d.ts +20 -0
  69. package/dist/components/forms/RadioGroup.svelte +77 -0
  70. package/dist/components/forms/RadioGroup.svelte.d.ts +17 -0
  71. package/dist/components/forms/RangeSlider.svelte +90 -0
  72. package/dist/components/forms/RangeSlider.svelte.d.ts +14 -0
  73. package/dist/components/forms/Select.svelte +106 -0
  74. package/dist/components/forms/Select.svelte.d.ts +18 -0
  75. package/dist/components/forms/Switch.svelte +44 -0
  76. package/dist/components/forms/Switch.svelte.d.ts +12 -0
  77. package/dist/components/forms/Textarea.svelte +52 -0
  78. package/dist/components/forms/Textarea.svelte.d.ts +15 -0
  79. package/dist/components/forms/TimePicker.svelte +63 -0
  80. package/dist/components/forms/TimePicker.svelte.d.ts +16 -0
  81. package/dist/components/forms/formClasses.d.ts +3 -0
  82. package/dist/components/forms/formClasses.js +3 -0
  83. package/dist/components/forms/index.d.ts +12 -0
  84. package/dist/components/forms/index.js +12 -0
  85. package/dist/components/navigation/Breadcrumbs.svelte +56 -0
  86. package/dist/components/navigation/Breadcrumbs.svelte.d.ts +15 -0
  87. package/dist/components/navigation/ContextMenu.svelte +133 -0
  88. package/dist/components/navigation/ContextMenu.svelte.d.ts +18 -0
  89. package/dist/components/navigation/DropdownMenu.svelte +139 -0
  90. package/dist/components/navigation/DropdownMenu.svelte.d.ts +17 -0
  91. package/dist/components/navigation/Menu.svelte +72 -0
  92. package/dist/components/navigation/Menu.svelte.d.ts +15 -0
  93. package/dist/components/navigation/Navbar.svelte +111 -0
  94. package/dist/components/navigation/Navbar.svelte.d.ts +15 -0
  95. package/dist/components/navigation/Sidebar.svelte +236 -0
  96. package/dist/components/navigation/Sidebar.svelte.d.ts +12 -0
  97. package/dist/components/navigation/Tabs.svelte +86 -0
  98. package/dist/components/navigation/Tabs.svelte.d.ts +19 -0
  99. package/dist/components/navigation/index.d.ts +7 -0
  100. package/dist/components/navigation/index.js +7 -0
  101. package/dist/components/overlays/Alert.svelte +81 -0
  102. package/dist/components/overlays/Alert.svelte.d.ts +15 -0
  103. package/dist/components/overlays/CommandPalette.svelte +182 -0
  104. package/dist/components/overlays/CommandPalette.svelte.d.ts +16 -0
  105. package/dist/components/overlays/Drawer.svelte +158 -0
  106. package/dist/components/overlays/Drawer.svelte.d.ts +16 -0
  107. package/dist/components/overlays/Dropdown.svelte +62 -0
  108. package/dist/components/overlays/Dropdown.svelte.d.ts +11 -0
  109. package/dist/components/overlays/Modal.svelte +125 -0
  110. package/dist/components/overlays/Modal.svelte.d.ts +15 -0
  111. package/dist/components/overlays/Popover.svelte +106 -0
  112. package/dist/components/overlays/Popover.svelte.d.ts +11 -0
  113. package/dist/components/overlays/ProgressBar.svelte +29 -0
  114. package/dist/components/overlays/ProgressBar.svelte.d.ts +10 -0
  115. package/dist/components/overlays/SkeletonLoader.svelte +66 -0
  116. package/dist/components/overlays/SkeletonLoader.svelte.d.ts +9 -0
  117. package/dist/components/overlays/Spinner.svelte +33 -0
  118. package/dist/components/overlays/Spinner.svelte.d.ts +7 -0
  119. package/dist/components/overlays/Toast.svelte +111 -0
  120. package/dist/components/overlays/Toast.svelte.d.ts +16 -0
  121. package/dist/components/overlays/Tooltip.svelte +94 -0
  122. package/dist/components/overlays/Tooltip.svelte.d.ts +12 -0
  123. package/dist/components/overlays/index.d.ts +11 -0
  124. package/dist/components/overlays/index.js +11 -0
  125. package/dist/components/typography/Code.svelte +10 -0
  126. package/dist/components/typography/Code.svelte.d.ts +6 -0
  127. package/dist/components/typography/Heading.svelte +15 -0
  128. package/dist/components/typography/Heading.svelte.d.ts +10 -0
  129. package/dist/components/typography/Text.svelte +21 -0
  130. package/dist/components/typography/Text.svelte.d.ts +10 -0
  131. package/dist/components/typography/index.d.ts +3 -0
  132. package/dist/components/typography/index.js +3 -0
  133. package/dist/components/utilities/Accordion.svelte +54 -0
  134. package/dist/components/utilities/Accordion.svelte.d.ts +17 -0
  135. package/dist/components/utilities/Carousel.svelte +124 -0
  136. package/dist/components/utilities/Carousel.svelte.d.ts +16 -0
  137. package/dist/components/utilities/Collapse.svelte +46 -0
  138. package/dist/components/utilities/Collapse.svelte.d.ts +10 -0
  139. package/dist/components/utilities/Hero.svelte +42 -0
  140. package/dist/components/utilities/Hero.svelte.d.ts +10 -0
  141. package/dist/components/utilities/Portal.svelte +47 -0
  142. package/dist/components/utilities/Portal.svelte.d.ts +21 -0
  143. package/dist/components/utilities/ScrollArea.svelte +33 -0
  144. package/dist/components/utilities/ScrollArea.svelte.d.ts +8 -0
  145. package/dist/components/utilities/SystemConsole.svelte +310 -0
  146. package/dist/components/utilities/SystemConsole.svelte.d.ts +20 -0
  147. package/dist/components/utilities/SystemInterface.svelte +726 -0
  148. package/dist/components/utilities/SystemInterface.svelte.d.ts +19 -0
  149. package/dist/components/utilities/index.d.ts +9 -0
  150. package/dist/components/utilities/index.js +8 -0
  151. package/dist/components/utilities/utilities.types.d.ts +46 -0
  152. package/dist/components/utilities/utilities.types.js +4 -0
  153. package/dist/index.d.ts +60 -175
  154. package/dist/index.js +24 -4560
  155. package/dist/lib/internal/id.d.ts +12 -0
  156. package/dist/lib/internal/id.js +15 -0
  157. package/dist/theme.css +2821 -0
  158. package/package.json +83 -75
  159. package/dist/index.css +0 -1
@@ -0,0 +1,443 @@
1
+ <script lang="ts">import Checkbox from '../forms/Checkbox.svelte';
2
+ let { columns, data, striped = false, hoverable = true, compact = false, stickyHeader = false, loading = false, loadingMessage = 'Loading...', emptyMessage = 'No data available', emptyState, filterFn, onSort, onRowClick, selectable = false, selectedKeys = $bindable(new Set()), rowKey = 'id', onSelectionChange, class: className = '', children, ...restProps } = $props();
3
+ // Determine if we're in dynamic mode or manual markup mode
4
+ const isDynamicMode = $derived(columns && data);
5
+ // Apply user-defined filter if provided
6
+ const filteredData = $derived.by(() => {
7
+ if (!isDynamicMode || !data)
8
+ return [];
9
+ if (!filterFn)
10
+ return data;
11
+ return data.filter(filterFn);
12
+ });
13
+ // Track current sort state
14
+ let sortColumn = $state(null);
15
+ let sortDirection = $state(null);
16
+ function handleSort(columnKey) {
17
+ if (!onSort)
18
+ return;
19
+ // Cycle through: null -> asc -> desc -> null
20
+ if (sortColumn !== columnKey) {
21
+ sortColumn = columnKey;
22
+ sortDirection = 'asc';
23
+ }
24
+ else if (sortDirection === 'asc') {
25
+ sortDirection = 'desc';
26
+ }
27
+ else if (sortDirection === 'desc') {
28
+ sortColumn = null;
29
+ sortDirection = null;
30
+ }
31
+ else {
32
+ sortDirection = 'asc';
33
+ }
34
+ onSort(columnKey, sortDirection);
35
+ }
36
+ function handleRowClick(row) {
37
+ if (onRowClick) {
38
+ onRowClick(row);
39
+ }
40
+ }
41
+ // Selection logic
42
+ function getRowKey(row, index) {
43
+ return row[rowKey] ?? index;
44
+ }
45
+ const allSelected = $derived.by(() => {
46
+ if (!selectable || filteredData.length === 0)
47
+ return false;
48
+ return filteredData.every((row, i) => selectedKeys.has(getRowKey(row, i)));
49
+ });
50
+ const someSelected = $derived.by(() => {
51
+ if (!selectable || filteredData.length === 0)
52
+ return false;
53
+ const selectedCount = filteredData.filter((row, i) => selectedKeys.has(getRowKey(row, i))).length;
54
+ return selectedCount > 0 && selectedCount < filteredData.length;
55
+ });
56
+ function toggleSelectAll() {
57
+ if (allSelected) {
58
+ // Deselect all
59
+ selectedKeys = new Set();
60
+ }
61
+ else {
62
+ // Select all filtered rows
63
+ selectedKeys = new Set(filteredData.map((row, i) => getRowKey(row, i)));
64
+ }
65
+ notifySelectionChange();
66
+ }
67
+ function toggleRowSelection(row, index) {
68
+ const key = getRowKey(row, index);
69
+ const newSet = new Set(selectedKeys);
70
+ if (newSet.has(key)) {
71
+ newSet.delete(key);
72
+ }
73
+ else {
74
+ newSet.add(key);
75
+ }
76
+ selectedKeys = newSet;
77
+ notifySelectionChange();
78
+ }
79
+ function isRowSelected(row, index) {
80
+ return selectedKeys.has(getRowKey(row, index));
81
+ }
82
+ function notifySelectionChange() {
83
+ if (onSelectionChange) {
84
+ const selectedRows = filteredData.filter((row, i) => selectedKeys.has(getRowKey(row, i)));
85
+ onSelectionChange(selectedKeys, selectedRows);
86
+ }
87
+ }
88
+ </script>
89
+
90
+ <div class="panel-raised rounded-[var(--radius-xl)] overflow-hidden {className}" {...restProps}>
91
+ <table class="mrdv-table w-full" class:striped class:hoverable class:compact class:sticky-header={stickyHeader}>
92
+ {#if isDynamicMode}
93
+ <!-- Dynamic mode: render from columns and data -->
94
+ <thead>
95
+ <tr>
96
+ {#if selectable}
97
+ <th class="select-cell">
98
+ <Checkbox
99
+ checked={allSelected}
100
+ onchange={toggleSelectAll}
101
+ class={someSelected ? 'indeterminate' : ''}
102
+ />
103
+ </th>
104
+ {/if}
105
+ {#each columns as column}
106
+ <th
107
+ style:text-align={column.align || 'left'}
108
+ class:sortable={column.sortable && onSort}
109
+ class:sorted={sortColumn === column.key}
110
+ onclick={() => column.sortable && handleSort(column.key)}
111
+ >
112
+ <div class="th-content">
113
+ {column.label}
114
+ {#if column.sortable && onSort}
115
+ <span class="sort-indicator">
116
+ {#if sortColumn === column.key}
117
+ {#if sortDirection === 'asc'}
118
+ <svg
119
+ xmlns="http://www.w3.org/2000/svg"
120
+ width="16"
121
+ height="16"
122
+ viewBox="0 0 24 24"
123
+ fill="none"
124
+ stroke="currentColor"
125
+ stroke-width="2"
126
+ stroke-linecap="round"
127
+ stroke-linejoin="round"
128
+ >
129
+ <path d="m18 15-6-6-6 6" />
130
+ </svg>
131
+ {:else if sortDirection === 'desc'}
132
+ <svg
133
+ xmlns="http://www.w3.org/2000/svg"
134
+ width="16"
135
+ height="16"
136
+ viewBox="0 0 24 24"
137
+ fill="none"
138
+ stroke="currentColor"
139
+ stroke-width="2"
140
+ stroke-linecap="round"
141
+ stroke-linejoin="round"
142
+ >
143
+ <path d="m6 9 6 6 6-6" />
144
+ </svg>
145
+ {/if}
146
+ {:else}
147
+ <svg
148
+ xmlns="http://www.w3.org/2000/svg"
149
+ width="16"
150
+ height="16"
151
+ viewBox="0 0 24 24"
152
+ fill="none"
153
+ stroke="currentColor"
154
+ stroke-width="2"
155
+ stroke-linecap="round"
156
+ stroke-linejoin="round"
157
+ opacity="0.3"
158
+ >
159
+ <path d="m7 15 5 5 5-5" />
160
+ <path d="m7 9 5-5 5 5" />
161
+ </svg>
162
+ {/if}
163
+ </span>
164
+ {/if}
165
+ </div>
166
+ </th>
167
+ {/each}
168
+ </tr>
169
+ </thead>
170
+ <tbody>
171
+ {#if loading}
172
+ <!-- Loading state -->
173
+ <tr class="state-row">
174
+ <td colspan={(columns?.length || 0) + (selectable ? 1 : 0)} class="text-center">
175
+ <div class="loading-container">
176
+ <svg
177
+ class="loading-spinner"
178
+ xmlns="http://www.w3.org/2000/svg"
179
+ width="24"
180
+ height="24"
181
+ viewBox="0 0 24 24"
182
+ fill="none"
183
+ stroke="currentColor"
184
+ stroke-width="2"
185
+ stroke-linecap="round"
186
+ stroke-linejoin="round"
187
+ >
188
+ <path d="M21 12a9 9 0 1 1-6.219-8.56" />
189
+ </svg>
190
+ <span>{loadingMessage}</span>
191
+ </div>
192
+ </td>
193
+ </tr>
194
+ {:else if filteredData.length === 0}
195
+ <!-- Empty state -->
196
+ <tr class="state-row">
197
+ <td colspan={(columns?.length || 0) + (selectable ? 1 : 0)} class="text-center">
198
+ {#if emptyState}
199
+ {@render emptyState()}
200
+ {:else}
201
+ <div class="empty-container">
202
+ <svg
203
+ xmlns="http://www.w3.org/2000/svg"
204
+ width="48"
205
+ height="48"
206
+ viewBox="0 0 24 24"
207
+ fill="none"
208
+ stroke="currentColor"
209
+ stroke-width="1.5"
210
+ stroke-linecap="round"
211
+ stroke-linejoin="round"
212
+ opacity="0.3"
213
+ >
214
+ <circle cx="11" cy="11" r="8" />
215
+ <path d="m21 21-4.3-4.3" />
216
+ </svg>
217
+ <p>{emptyMessage}</p>
218
+ </div>
219
+ {/if}
220
+ </td>
221
+ </tr>
222
+ {:else}
223
+ <!-- Data rows -->
224
+ {#each filteredData as row, index}
225
+ <tr
226
+ class:clickable={onRowClick}
227
+ class:selected={selectable && isRowSelected(row, index)}
228
+ onclick={() => handleRowClick(row)}
229
+ >
230
+ {#if selectable}
231
+ <td class="select-cell" onclick={(e) => e.stopPropagation()}>
232
+ <Checkbox
233
+ checked={isRowSelected(row, index)}
234
+ onchange={() => toggleRowSelection(row, index)}
235
+ />
236
+ </td>
237
+ {/if}
238
+ {#each columns as column}
239
+ <td style:text-align={column.align || 'left'}>
240
+ {#if restProps[`cell_${column.key}`]}
241
+ {@render restProps[`cell_${column.key}`]({ value: row[column.key], row })}
242
+ {:else if column.render}
243
+ {@html column.render(row[column.key], row)}
244
+ {:else}
245
+ {row[column.key]}
246
+ {/if}
247
+ </td>
248
+ {/each}
249
+ </tr>
250
+ {/each}
251
+ {/if}
252
+ </tbody>
253
+ {:else}
254
+ <!-- Manual markup mode: use children snippet -->
255
+ {@render children?.()}
256
+ {/if}
257
+ </table>
258
+ </div>
259
+
260
+ <style>
261
+ .mrdv-table :global(thead) {
262
+ background: var(--color-base-2);
263
+ border-bottom: 2px solid var(--color-border-strong);
264
+ }
265
+
266
+ .mrdv-table :global(thead th) {
267
+ color: var(--color-text);
268
+ font-weight: 600;
269
+ text-transform: uppercase;
270
+ letter-spacing: 0.05em;
271
+ text-align: left;
272
+ }
273
+
274
+ .mrdv-table.compact :global(th),
275
+ .mrdv-table.compact :global(td) {
276
+ padding: 0.5rem 1rem;
277
+ }
278
+
279
+ .mrdv-table:not(.compact) :global(th),
280
+ .mrdv-table:not(.compact) :global(td) {
281
+ padding: 1rem 1.5rem;
282
+ }
283
+
284
+ .mrdv-table :global(tbody) {
285
+ position: relative;
286
+ z-index: 1;
287
+ }
288
+
289
+ .mrdv-table :global(tbody tr) {
290
+ border-bottom: 1px solid var(--color-border);
291
+ transition: all var(--duration-200) var(--ease-luxe);
292
+ }
293
+
294
+ .mrdv-table.hoverable :global(tbody tr:hover) {
295
+ background: var(--color-accent-overlay-5);
296
+ transform: translateY(-1px);
297
+ box-shadow:
298
+ 0 2px 8px var(--color-shadow-overlay-20),
299
+ var(--shadow-accent-glow);
300
+ }
301
+
302
+ .mrdv-table.striped :global(tbody tr:nth-child(even)) {
303
+ background: var(--color-neutral-overlay-2);
304
+ }
305
+
306
+ .mrdv-table.striped.hoverable :global(tbody tr:nth-child(even):hover) {
307
+ background: var(--color-accent-overlay-5);
308
+ transform: translateY(-1px);
309
+ box-shadow:
310
+ 0 2px 8px var(--color-shadow-overlay-20),
311
+ var(--shadow-accent-glow);
312
+ }
313
+
314
+ .mrdv-table :global(th),
315
+ .mrdv-table :global(td) {
316
+ text-align: left;
317
+ }
318
+
319
+ /* Sortable column styles */
320
+ .mrdv-table th.sortable {
321
+ cursor: pointer;
322
+ user-select: none;
323
+ transition: all var(--duration-200) var(--ease-luxe);
324
+ }
325
+
326
+ .mrdv-table th.sortable:hover {
327
+ background: var(--color-accent-overlay-5);
328
+ color: var(--color-accent);
329
+ }
330
+
331
+ .mrdv-table th.sorted {
332
+ color: var(--color-accent);
333
+ }
334
+
335
+ .th-content {
336
+ display: flex;
337
+ align-items: center;
338
+ gap: 0.5rem;
339
+ justify-content: space-between;
340
+ }
341
+
342
+ .sort-indicator {
343
+ display: flex;
344
+ align-items: center;
345
+ flex-shrink: 0;
346
+ }
347
+
348
+ /* Clickable row styles */
349
+ .mrdv-table tbody tr.clickable {
350
+ cursor: pointer;
351
+ }
352
+
353
+ /* Selection styles */
354
+ .select-cell {
355
+ width: 3rem;
356
+ padding-left: 1rem !important;
357
+ padding-right: 0.5rem !important;
358
+ }
359
+
360
+ .mrdv-table tbody tr.selected {
361
+ background: var(--color-accent-overlay-10);
362
+ }
363
+
364
+ .mrdv-table tbody tr.selected:hover {
365
+ background: var(--color-accent-overlay-15);
366
+ }
367
+
368
+ .mrdv-table.striped tbody tr.selected:nth-child(even) {
369
+ background: var(--color-accent-overlay-10);
370
+ }
371
+
372
+ /* Indeterminate checkbox styling */
373
+ .select-cell :global(.indeterminate input[type="checkbox"]) {
374
+ background: var(--color-accent);
375
+ border-color: var(--color-accent);
376
+ }
377
+
378
+ .select-cell :global(.indeterminate input[type="checkbox"])::after {
379
+ content: '';
380
+ position: absolute;
381
+ left: 50%;
382
+ top: 50%;
383
+ transform: translate(-50%, -50%);
384
+ width: 10px;
385
+ height: 2px;
386
+ background: white;
387
+ border-radius: 1px;
388
+ }
389
+
390
+ /* Sticky header */
391
+ .mrdv-table.sticky-header thead {
392
+ position: sticky;
393
+ top: 0;
394
+ z-index: 10;
395
+ }
396
+
397
+ /* Loading state */
398
+ .loading-container {
399
+ display: flex;
400
+ align-items: center;
401
+ justify-content: center;
402
+ gap: 0.75rem;
403
+ padding: 3rem 1rem;
404
+ color: var(--color-text-secondary);
405
+ }
406
+
407
+ .loading-spinner {
408
+ animation: spin 1s linear infinite;
409
+ }
410
+
411
+ @keyframes spin {
412
+ from {
413
+ transform: rotate(0deg);
414
+ }
415
+ to {
416
+ transform: rotate(360deg);
417
+ }
418
+ }
419
+
420
+ /* Empty state */
421
+ .empty-container {
422
+ display: flex;
423
+ flex-direction: column;
424
+ align-items: center;
425
+ justify-content: center;
426
+ gap: 1rem;
427
+ padding: 3rem 1rem;
428
+ color: var(--color-text-muted);
429
+ }
430
+
431
+ .empty-container p {
432
+ margin: 0;
433
+ font-size: 0.875rem;
434
+ }
435
+
436
+ /* State row */
437
+ .state-row td {
438
+ border-bottom: none !important;
439
+ }
440
+
441
+ .text-center {
442
+ text-align: center;
443
+ }</style>
@@ -0,0 +1,30 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { Column, SortDirection, RowKey } from './Table.types';
3
+ interface Props {
4
+ columns?: Column[];
5
+ data?: Record<string, any>[];
6
+ striped?: boolean;
7
+ hoverable?: boolean;
8
+ compact?: boolean;
9
+ stickyHeader?: boolean;
10
+ loading?: boolean;
11
+ loadingMessage?: string;
12
+ emptyMessage?: string;
13
+ emptyState?: Snippet;
14
+ filterFn?: (row: Record<string, any>) => boolean;
15
+ onSort?: (columnKey: string, direction: SortDirection) => void;
16
+ onRowClick?: (row: Record<string, any>) => void;
17
+ selectable?: boolean;
18
+ selectedKeys?: Set<RowKey>;
19
+ rowKey?: string;
20
+ onSelectionChange?: (selectedKeys: Set<RowKey>, rows: Record<string, any>[]) => void;
21
+ children?: Snippet;
22
+ [key: `cell_${string}`]: Snippet<[{
23
+ value: any;
24
+ row: any;
25
+ }]> | undefined;
26
+ class?: string;
27
+ }
28
+ declare const Table: import("svelte").Component<Props, {}, "selectedKeys">;
29
+ type Table = ReturnType<typeof Table>;
30
+ export default Table;
@@ -0,0 +1,14 @@
1
+ export type SortDirection = 'asc' | 'desc' | null;
2
+ export interface Column {
3
+ key: string;
4
+ label: string;
5
+ align?: 'left' | 'center' | 'right';
6
+ sortable?: boolean;
7
+ render?: (value: any, row: any) => any;
8
+ }
9
+ export type RowKey = string | number;
10
+ export interface SelectionState {
11
+ selectedKeys: Set<RowKey>;
12
+ allSelected: boolean;
13
+ someSelected: boolean;
14
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ <script lang="ts">"use strict";
2
+ let { variant = 'default', size = 'md', dismissible = false, onDismiss, ondismiss, children, icon } = $props();
3
+ const onDismissCallback = $derived(onDismiss ?? ondismiss);
4
+ const variantClasses = {
5
+ default: 'bg-[var(--color-base-2)] text-[var(--color-text-soft)] border-[var(--color-border)]',
6
+ accent: 'bg-[var(--color-secondary-overlay-10)] text-[var(--color-accent-soft)] border-[var(--color-accent)] shadow-[0_0_12px_var(--color-secondary-overlay-20)]',
7
+ info: 'bg-[var(--color-info-overlay-10)] text-[var(--color-info)] border-[var(--color-info)] shadow-[0_0_12px_var(--color-info-overlay-20)]'
8
+ };
9
+ const sizeClasses = {
10
+ sm: 'px-2 py-0.5 text-xs gap-1',
11
+ md: 'px-3 py-1.5 text-sm gap-2',
12
+ lg: 'px-4 py-2 text-base gap-2'
13
+ };
14
+ const classes = $derived(`inline-flex items-center rounded-[var(--radius-pill)] border font-[var(--font-body)] font-medium transition-all duration-300 hover:scale-[1.02] ${sizeClasses[size]} ${variantClasses[variant]}`);
15
+ function handleDismiss() {
16
+ onDismissCallback?.();
17
+ }
18
+ </script>
19
+
20
+ <span class={classes}>
21
+ {#if icon}
22
+ <span class="inline-flex items-center justify-center">
23
+ {@render icon()}
24
+ </span>
25
+ {/if}
26
+ {@render children?.()}
27
+
28
+ {#if dismissible}
29
+ <button
30
+ class="ml-1 opacity-60 hover:opacity-100 hover:text-[var(--color-text)] transition-all duration-300"
31
+ onclick={handleDismiss}
32
+ aria-label="Remove tag"
33
+ >
34
+ <svg
35
+ width="14"
36
+ height="14"
37
+ viewBox="0 0 14 14"
38
+ fill="none"
39
+ xmlns="http://www.w3.org/2000/svg"
40
+ >
41
+ <path
42
+ d="M10.5 3.5L3.5 10.5M3.5 3.5L10.5 10.5"
43
+ stroke="currentColor"
44
+ stroke-width="1.5"
45
+ stroke-linecap="round"
46
+ stroke-linejoin="round"
47
+ />
48
+ </svg>
49
+ </button>
50
+ {/if}
51
+ </span>
@@ -0,0 +1,13 @@
1
+ interface Props {
2
+ variant?: 'default' | 'accent' | 'info';
3
+ size?: 'sm' | 'md' | 'lg';
4
+ dismissible?: boolean;
5
+ onDismiss?: () => void;
6
+ /** @deprecated Use onDismiss */
7
+ ondismiss?: () => void;
8
+ children?: import('svelte').Snippet;
9
+ icon?: import('svelte').Snippet;
10
+ }
11
+ declare const Tag: import("svelte").Component<Props, {}, "">;
12
+ type Tag = ReturnType<typeof Tag>;
13
+ export default Tag;
@@ -0,0 +1,12 @@
1
+ export { default as Table } from './Table.svelte';
2
+ export type { Column as TableColumn, SortDirection, RowKey, SelectionState } from './Table.types';
3
+ export { default as Pagination } from './Pagination.svelte';
4
+ export { default as Badge } from './Badge.svelte';
5
+ export { default as Tag } from './Tag.svelte';
6
+ export { default as List } from './List.svelte';
7
+ export { default as Avatar } from './Avatar.svelte';
8
+ export { default as CodeBlock } from './CodeBlock.svelte';
9
+ export { default as Stat } from './Stat.svelte';
10
+ export { default as CalendarGrid } from './CalendarGrid.svelte';
11
+ export type { CalendarEvent } from './CalendarGrid.types';
12
+ export { default as Sparkline } from './Sparkline.svelte';
@@ -0,0 +1,10 @@
1
+ export { default as Table } from './Table.svelte';
2
+ export { default as Pagination } from './Pagination.svelte';
3
+ export { default as Badge } from './Badge.svelte';
4
+ export { default as Tag } from './Tag.svelte';
5
+ export { default as List } from './List.svelte';
6
+ export { default as Avatar } from './Avatar.svelte';
7
+ export { default as CodeBlock } from './CodeBlock.svelte';
8
+ export { default as Stat } from './Stat.svelte';
9
+ export { default as CalendarGrid } from './CalendarGrid.svelte';
10
+ export { default as Sparkline } from './Sparkline.svelte';
@@ -0,0 +1,39 @@
1
+ <script lang="ts">import { createId } from '../../lib/internal/id.js';
2
+ let { checked = $bindable(false), disabled = false, label, id = createId('checkbox'), onchange, iconBefore, class: className = '' } = $props();
3
+ </script>
4
+
5
+ <label for={id} class="flex items-center gap-2 cursor-pointer {disabled ? 'opacity-50 cursor-not-allowed' : ''} {className}">
6
+ <input
7
+ type="checkbox"
8
+ {id}
9
+ {disabled}
10
+ bind:checked
11
+ onchange={onchange}
12
+ class="w-6 h-6 rounded-sm border-2 border-border-strong bg-transparent appearance-none transition-all duration-200 ease-luxe cursor-pointer checked:bg-accent checked:border-accent checked:accent-glow focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 focus:ring-offset-base-1 relative {disabled ? 'cursor-not-allowed' : ''}"
13
+ />
14
+ {#if iconBefore}
15
+ <span class="inline-flex items-center justify-center text-text-soft">
16
+ {@render iconBefore()}
17
+ </span>
18
+ {/if}
19
+ {#if label}
20
+ <span class="text-text text-sm select-none">
21
+ {label}
22
+ </span>
23
+ {/if}
24
+ </label>
25
+
26
+ <style>
27
+ input[type="checkbox"]:checked::after {
28
+ content: '';
29
+ position: absolute;
30
+ left: 50%;
31
+ top: 50%;
32
+ transform: translate(-50%, -50%);
33
+ width: 12px;
34
+ height: 12px;
35
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 6L5 8.5L9.5 3.5' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
36
+ background-size: contain;
37
+ background-repeat: no-repeat;
38
+ background-position: center;
39
+ }</style>
@@ -0,0 +1,12 @@
1
+ export interface Props {
2
+ checked?: boolean;
3
+ disabled?: boolean;
4
+ label?: string;
5
+ id?: string;
6
+ onchange?: (event: Event) => void;
7
+ iconBefore?: import('svelte').Snippet;
8
+ class?: string;
9
+ }
10
+ declare const Checkbox: import("svelte").Component<Props, {}, "checked">;
11
+ type Checkbox = ReturnType<typeof Checkbox>;
12
+ export default Checkbox;
@@ -0,0 +1,61 @@
1
+ <script lang="ts">import { createId } from '../../lib/internal/id.js';
2
+ import { baseInputClasses, focusClasses, disabledClasses, } from './formClasses';
3
+ let { value = $bindable(''), min, max, placeholder, disabled = false, error = false, label, id = createId('datepicker'), onchange, class: className = '', } = $props();
4
+ const errorClasses = $derived(error ? 'error-state' : '');
5
+ </script>
6
+
7
+ {#if label}
8
+ <div>
9
+ <label for={id} class="text-text-soft text-sm mb-2 block">
10
+ {label}
11
+ </label>
12
+ <input
13
+ type="date"
14
+ {id}
15
+ {placeholder}
16
+ {disabled}
17
+ {min}
18
+ {max}
19
+ bind:value
20
+ {onchange}
21
+ class="{baseInputClasses} {focusClasses} {errorClasses} {disabled
22
+ ? disabledClasses
23
+ : ''} {className}"
24
+ />
25
+ </div>
26
+ {:else}
27
+ <input
28
+ type="date"
29
+ {id}
30
+ {placeholder}
31
+ {disabled}
32
+ {min}
33
+ {max}
34
+ bind:value
35
+ {onchange}
36
+ class="{baseInputClasses} {focusClasses} {errorClasses} {disabled
37
+ ? disabledClasses
38
+ : ''} {className}"
39
+ />
40
+ {/if}
41
+
42
+ <style>
43
+ input[type='date'] {
44
+ min-height: 3rem;
45
+ cursor: pointer;
46
+ }
47
+
48
+ input[type='date']::-webkit-calendar-picker-indicator {
49
+ cursor: pointer;
50
+ filter: invert(0.7);
51
+ transition: filter 120ms var(--ease-sharp);
52
+ }
53
+
54
+ input[type='date']:hover::-webkit-calendar-picker-indicator {
55
+ filter: invert(1);
56
+ }
57
+
58
+ input[type='date']:disabled::-webkit-calendar-picker-indicator {
59
+ cursor: not-allowed;
60
+ opacity: 0.4;
61
+ }</style>