@mrintel/villain-ui 0.3.0 → 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 (128) 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 +60 -46
  15. package/dist/components/cards/Card.svelte.d.ts +6 -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 +282 -57
  57. package/dist/components/forms/Input.svelte.d.ts +9 -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/Switch.svelte +44 -56
  65. package/dist/components/forms/Switch.svelte.d.ts +3 -1
  66. package/dist/components/forms/Textarea.svelte +52 -57
  67. package/dist/components/forms/Textarea.svelte.d.ts +3 -1
  68. package/dist/components/forms/TimePicker.svelte +63 -0
  69. package/dist/components/forms/TimePicker.svelte.d.ts +16 -0
  70. package/dist/components/forms/formClasses.d.ts +3 -0
  71. package/dist/components/forms/formClasses.js +3 -0
  72. package/dist/components/forms/index.d.ts +3 -0
  73. package/dist/components/forms/index.js +3 -0
  74. package/dist/components/navigation/Breadcrumbs.svelte +56 -59
  75. package/dist/components/navigation/Breadcrumbs.svelte.d.ts +1 -0
  76. package/dist/components/navigation/ContextMenu.svelte +133 -83
  77. package/dist/components/navigation/ContextMenu.svelte.d.ts +8 -1
  78. package/dist/components/navigation/DropdownMenu.svelte +139 -80
  79. package/dist/components/navigation/DropdownMenu.svelte.d.ts +8 -1
  80. package/dist/components/navigation/Menu.svelte +72 -48
  81. package/dist/components/navigation/Navbar.svelte +111 -32
  82. package/dist/components/navigation/Navbar.svelte.d.ts +6 -0
  83. package/dist/components/navigation/Sidebar.svelte +236 -35
  84. package/dist/components/navigation/Sidebar.svelte.d.ts +2 -0
  85. package/dist/components/navigation/Tabs.svelte +86 -54
  86. package/dist/components/navigation/Tabs.svelte.d.ts +5 -1
  87. package/dist/components/overlays/Alert.svelte +81 -99
  88. package/dist/components/overlays/Alert.svelte.d.ts +5 -1
  89. package/dist/components/overlays/CommandPalette.svelte +182 -217
  90. package/dist/components/overlays/Drawer.svelte +158 -167
  91. package/dist/components/overlays/Drawer.svelte.d.ts +3 -1
  92. package/dist/components/overlays/Dropdown.svelte +62 -30
  93. package/dist/components/overlays/Dropdown.svelte.d.ts +2 -0
  94. package/dist/components/overlays/Modal.svelte +125 -130
  95. package/dist/components/overlays/Modal.svelte.d.ts +3 -1
  96. package/dist/components/overlays/Popover.svelte +106 -131
  97. package/dist/components/overlays/ProgressBar.svelte +29 -45
  98. package/dist/components/overlays/SkeletonLoader.svelte +66 -82
  99. package/dist/components/overlays/Spinner.svelte +33 -43
  100. package/dist/components/overlays/Toast.svelte +111 -140
  101. package/dist/components/overlays/Toast.svelte.d.ts +3 -0
  102. package/dist/components/overlays/Tooltip.svelte +94 -115
  103. package/dist/components/overlays/Tooltip.svelte.d.ts +3 -1
  104. package/dist/components/typography/Code.svelte +10 -14
  105. package/dist/components/typography/Heading.svelte +15 -22
  106. package/dist/components/typography/Heading.svelte.d.ts +1 -0
  107. package/dist/components/typography/Text.svelte +21 -24
  108. package/dist/components/typography/Text.svelte.d.ts +2 -1
  109. package/dist/components/utilities/Accordion.svelte +54 -67
  110. package/dist/components/utilities/Accordion.svelte.d.ts +4 -1
  111. package/dist/components/utilities/Carousel.svelte +124 -152
  112. package/dist/components/utilities/Collapse.svelte +46 -60
  113. package/dist/components/utilities/Hero.svelte +42 -0
  114. package/dist/components/utilities/Hero.svelte.d.ts +10 -0
  115. package/dist/components/utilities/Portal.svelte +47 -72
  116. package/dist/components/utilities/ScrollArea.svelte +33 -41
  117. package/dist/components/utilities/SystemConsole.svelte +310 -0
  118. package/dist/components/utilities/SystemConsole.svelte.d.ts +20 -0
  119. package/dist/components/utilities/SystemInterface.svelte +726 -0
  120. package/dist/components/utilities/SystemInterface.svelte.d.ts +19 -0
  121. package/dist/components/utilities/index.d.ts +4 -0
  122. package/dist/components/utilities/index.js +3 -0
  123. package/dist/components/utilities/utilities.types.d.ts +46 -0
  124. package/dist/components/utilities/utilities.types.js +4 -0
  125. package/dist/index.d.ts +49 -4
  126. package/dist/index.js +4 -4
  127. package/dist/theme.css +2821 -218
  128. package/package.json +83 -76
@@ -1,76 +1,443 @@
1
- <script lang="ts">
2
- interface Props {
3
- striped?: boolean;
4
- hoverable?: boolean;
5
- compact?: boolean;
6
- children?: import('svelte').Snippet;
7
- }
8
-
9
- let { striped = false, hoverable = true, compact = false, children }: Props = $props();
10
- </script>
11
-
12
- <div class="glass-panel rounded-[var(--radius-xl)] overflow-hidden">
13
- <table class="mrdv-table w-full" class:striped class:hoverable class:compact>
14
- {@render children?.()}
15
- </table>
16
- </div>
17
-
18
- <style>
19
- .mrdv-table :global(thead) {
20
- background: var(--color-base-2);
21
- border-bottom: 2px solid var(--color-border-strong);
22
- }
23
-
24
- .mrdv-table :global(thead th) {
25
- color: var(--color-text);
26
- font-weight: 600;
27
- text-transform: uppercase;
28
- letter-spacing: 0.05em;
29
- text-align: left;
30
- }
31
-
32
- .mrdv-table.compact :global(th),
33
- .mrdv-table.compact :global(td) {
34
- padding: 0.5rem 1rem;
35
- }
36
-
37
- .mrdv-table:not(.compact) :global(th),
38
- .mrdv-table:not(.compact) :global(td) {
39
- padding: 1rem 1.5rem;
40
- }
41
-
42
- .mrdv-table :global(tbody) {
43
- position: relative;
44
- z-index: 1;
45
- }
46
-
47
- .mrdv-table :global(tbody tr) {
48
- border-bottom: 1px solid var(--color-border);
49
- transition: all var(--ease-luxe);
50
- }
51
-
52
- .mrdv-table.hoverable :global(tbody tr:hover) {
53
- background: rgba(127, 61, 255, 0.05);
54
- transform: translateY(-1px);
55
- box-shadow:
56
- 0 2px 8px rgba(0, 0, 0, 0.2),
57
- var(--shadow-accent-glow);
58
- }
59
-
60
- .mrdv-table.striped :global(tbody tr:nth-child(even)) {
61
- background: rgba(255, 255, 255, 0.02);
62
- }
63
-
64
- .mrdv-table.striped.hoverable :global(tbody tr:nth-child(even):hover) {
65
- background: rgba(127, 61, 255, 0.05);
66
- transform: translateY(-1px);
67
- box-shadow:
68
- 0 2px 8px rgba(0, 0, 0, 0.2),
69
- var(--shadow-accent-glow);
70
- }
71
-
72
- .mrdv-table :global(th),
73
- .mrdv-table :global(td) {
74
- text-align: left;
75
- }
76
- </style>
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>
@@ -1,9 +1,30 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { Column, SortDirection, RowKey } from './Table.types';
1
3
  interface Props {
4
+ columns?: Column[];
5
+ data?: Record<string, any>[];
2
6
  striped?: boolean;
3
7
  hoverable?: boolean;
4
8
  compact?: boolean;
5
- children?: import('svelte').Snippet;
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;
6
27
  }
7
- declare const Table: import("svelte").Component<Props, {}, "">;
28
+ declare const Table: import("svelte").Component<Props, {}, "selectedKeys">;
8
29
  type Table = ReturnType<typeof Table>;
9
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 {};
@@ -1,53 +1,51 @@
1
- <script lang="ts">
2
- interface Props {
3
- variant?: 'default' | 'accent';
4
- dismissible?: boolean;
5
- ondismiss?: () => void;
6
- children?: import('svelte').Snippet;
7
- }
8
-
9
- let { variant = 'default', dismissible = false, ondismiss, children }: Props = $props();
10
-
11
- const variantClasses = {
12
- default:
13
- 'bg-[var(--color-base-2)] text-[var(--color-text-soft)] border-[var(--color-border)]',
14
- accent:
15
- 'bg-[rgba(127,61,255,0.1)] text-[var(--color-accent-soft)] border-[var(--color-accent)] shadow-[0_0_12px_rgba(127,61,255,0.2)]'
16
- };
17
-
18
- const classes = $derived(
19
- `inline-flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-pill)] border font-[var(--font-body)] font-medium text-sm transition-all duration-300 hover:scale-[1.02] ${variantClasses[variant]}`
20
- );
21
-
22
- function handleDismiss() {
23
- ondismiss?.();
24
- }
25
- </script>
26
-
27
- <span class={classes}>
28
- {@render children?.()}
29
-
30
- {#if dismissible}
31
- <button
32
- class="ml-1 opacity-60 hover:opacity-100 hover:text-[var(--color-text)] transition-all duration-300"
33
- onclick={handleDismiss}
34
- aria-label="Remove tag"
35
- >
36
- <svg
37
- width="14"
38
- height="14"
39
- viewBox="0 0 14 14"
40
- fill="none"
41
- xmlns="http://www.w3.org/2000/svg"
42
- >
43
- <path
44
- d="M10.5 3.5L3.5 10.5M3.5 3.5L10.5 10.5"
45
- stroke="currentColor"
46
- stroke-width="1.5"
47
- stroke-linecap="round"
48
- stroke-linejoin="round"
49
- />
50
- </svg>
51
- </button>
52
- {/if}
53
- </span>
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>
@@ -1,8 +1,12 @@
1
1
  interface Props {
2
- variant?: 'default' | 'accent';
2
+ variant?: 'default' | 'accent' | 'info';
3
+ size?: 'sm' | 'md' | 'lg';
3
4
  dismissible?: boolean;
5
+ onDismiss?: () => void;
6
+ /** @deprecated Use onDismiss */
4
7
  ondismiss?: () => void;
5
8
  children?: import('svelte').Snippet;
9
+ icon?: import('svelte').Snippet;
6
10
  }
7
11
  declare const Tag: import("svelte").Component<Props, {}, "">;
8
12
  type Tag = ReturnType<typeof Tag>;