@aspect-ops/exon-ui 0.2.0 → 0.2.2

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 (74) hide show
  1. package/README.md +200 -0
  2. package/dist/components/Accordion/Accordion.svelte +2 -2
  3. package/dist/components/Accordion/AccordionItem.svelte +2 -2
  4. package/dist/components/AspectRatio/AspectRatio.svelte +1 -0
  5. package/dist/components/Card/FlipCard.svelte +155 -0
  6. package/dist/components/Card/FlipCard.svelte.d.ts +13 -0
  7. package/dist/components/Card/index.d.ts +1 -0
  8. package/dist/components/Card/index.js +1 -0
  9. package/dist/components/Chatbot/ChatMessage.svelte +143 -0
  10. package/dist/components/Chatbot/ChatMessage.svelte.d.ts +8 -0
  11. package/dist/components/Chatbot/Chatbot.svelte +640 -0
  12. package/dist/components/Chatbot/Chatbot.svelte.d.ts +22 -0
  13. package/dist/components/Chatbot/index.d.ts +3 -0
  14. package/dist/components/Chatbot/index.js +2 -0
  15. package/dist/components/Chatbot/types.d.ts +48 -0
  16. package/dist/components/Chatbot/types.js +2 -0
  17. package/dist/components/ContactForm/ContactForm.svelte +564 -0
  18. package/dist/components/ContactForm/ContactForm.svelte.d.ts +44 -0
  19. package/dist/components/ContactForm/index.d.ts +1 -0
  20. package/dist/components/ContactForm/index.js +1 -0
  21. package/dist/components/Container/Container.svelte +1 -0
  22. package/dist/components/DataTable/DataTable.svelte +460 -0
  23. package/dist/components/DataTable/DataTable.svelte.d.ts +49 -0
  24. package/dist/components/DataTable/index.d.ts +2 -0
  25. package/dist/components/DataTable/index.js +1 -0
  26. package/dist/components/DoughnutChart/DoughnutChart.svelte +390 -0
  27. package/dist/components/DoughnutChart/DoughnutChart.svelte.d.ts +25 -0
  28. package/dist/components/DoughnutChart/index.d.ts +1 -0
  29. package/dist/components/DoughnutChart/index.js +1 -0
  30. package/dist/components/FAB/FAB.svelte +5 -1
  31. package/dist/components/FAB/FABGroup.svelte +10 -2
  32. package/dist/components/FileUpload/FileUpload.svelte +12 -12
  33. package/dist/components/Icon/Icon.svelte +15 -18
  34. package/dist/components/Icon/Icon.svelte.d.ts +2 -1
  35. package/dist/components/Menu/MenuContent.svelte +1 -0
  36. package/dist/components/Menu/MenuSubContent.svelte +1 -0
  37. package/dist/components/Mermaid/Mermaid.svelte +320 -0
  38. package/dist/components/Mermaid/Mermaid.svelte.d.ts +38 -0
  39. package/dist/components/Mermaid/index.d.ts +1 -0
  40. package/dist/components/Mermaid/index.js +1 -0
  41. package/dist/components/Mermaid/mermaid.d.ts +21 -0
  42. package/dist/components/PageHeader/PageHeader.svelte +140 -0
  43. package/dist/components/PageHeader/PageHeader.svelte.d.ts +30 -0
  44. package/dist/components/PageHeader/index.d.ts +1 -0
  45. package/dist/components/PageHeader/index.js +1 -0
  46. package/dist/components/Popover/PopoverTrigger.svelte +1 -3
  47. package/dist/components/StatCircle/StatCircle.svelte +172 -0
  48. package/dist/components/StatCircle/StatCircle.svelte.d.ts +19 -0
  49. package/dist/components/StatCircle/index.d.ts +1 -0
  50. package/dist/components/StatCircle/index.js +1 -0
  51. package/dist/components/StatsCard/StatsCard.svelte +301 -0
  52. package/dist/components/StatsCard/StatsCard.svelte.d.ts +32 -0
  53. package/dist/components/StatsCard/index.d.ts +2 -0
  54. package/dist/components/StatsCard/index.js +1 -0
  55. package/dist/components/StatusBadge/StatusBadge.svelte +221 -0
  56. package/dist/components/StatusBadge/StatusBadge.svelte.d.ts +22 -0
  57. package/dist/components/StatusBadge/index.d.ts +2 -0
  58. package/dist/components/StatusBadge/index.js +1 -0
  59. package/dist/components/StatusBanner/StatusBanner.svelte +325 -0
  60. package/dist/components/StatusBanner/StatusBanner.svelte.d.ts +13 -0
  61. package/dist/components/StatusBanner/index.d.ts +1 -0
  62. package/dist/components/StatusBanner/index.js +1 -0
  63. package/dist/components/ViewCounter/ViewCounter.svelte +157 -0
  64. package/dist/components/ViewCounter/ViewCounter.svelte.d.ts +17 -0
  65. package/dist/components/ViewCounter/index.d.ts +1 -0
  66. package/dist/components/ViewCounter/index.js +1 -0
  67. package/dist/index.d.ts +17 -2
  68. package/dist/index.js +16 -1
  69. package/dist/styles/tokens.css +2 -1
  70. package/dist/types/data-display.d.ts +72 -0
  71. package/dist/types/feedback.d.ts +10 -0
  72. package/dist/types/index.d.ts +3 -3
  73. package/dist/types/input.d.ts +20 -0
  74. package/package.json +4 -2
@@ -0,0 +1,460 @@
1
+ <script lang="ts">
2
+ /**
3
+ * DataTable - A sortable, customizable data table component
4
+ * Supports custom cell rendering, sorting, loading states, and responsive overflow
5
+ */
6
+
7
+ type SortOrder = 'asc' | 'desc';
8
+ type ColumnAlign = 'left' | 'center' | 'right';
9
+
10
+ interface ColumnDef {
11
+ /** Unique key matching the data property */
12
+ key: string;
13
+ /** Header text to display */
14
+ header: string;
15
+ /** Whether this column is sortable */
16
+ sortable?: boolean;
17
+ /** Fixed width (e.g., '100px', '10rem') */
18
+ width?: string;
19
+ /** Text alignment */
20
+ align?: ColumnAlign;
21
+ /** Custom cell renderer - receives (value, row) */
22
+ cell?: import('svelte').Snippet<[value: unknown, row: unknown]>;
23
+ }
24
+
25
+ interface Props {
26
+ /** Array of data objects to display */
27
+ data: unknown[];
28
+ /** Column definitions */
29
+ columns: ColumnDef[];
30
+ /** Currently sorted column key */
31
+ sortBy?: string;
32
+ /** Current sort direction */
33
+ sortOrder?: SortOrder;
34
+ /** Callback when sort changes */
35
+ onsort?: (column: string, order: SortOrder) => void;
36
+ /** Show loading skeleton */
37
+ loading?: boolean;
38
+ /** Number of skeleton rows to show when loading */
39
+ loadingRows?: number;
40
+ /** Custom empty state content */
41
+ empty?: import('svelte').Snippet;
42
+ /** Enable row hover effect */
43
+ rowHover?: boolean;
44
+ /** Enable striped rows */
45
+ striped?: boolean;
46
+ /** Make header sticky on scroll */
47
+ stickyHeader?: boolean;
48
+ /** Additional CSS classes */
49
+ class?: string;
50
+ }
51
+
52
+ let {
53
+ data = [],
54
+ columns,
55
+ sortBy = $bindable(),
56
+ sortOrder = $bindable(),
57
+ onsort,
58
+ loading = false,
59
+ loadingRows = 5,
60
+ empty,
61
+ rowHover = true,
62
+ striped = false,
63
+ stickyHeader = false,
64
+ class: className = ''
65
+ }: Props = $props();
66
+
67
+ function handleSort(column: ColumnDef) {
68
+ if (!column.sortable) return;
69
+
70
+ let newOrder: SortOrder = 'asc';
71
+ if (sortBy === column.key) {
72
+ newOrder = sortOrder === 'asc' ? 'desc' : 'asc';
73
+ }
74
+
75
+ sortBy = column.key;
76
+ sortOrder = newOrder;
77
+ onsort?.(column.key, newOrder);
78
+ }
79
+
80
+ function getCellValue(row: unknown, key: string): unknown {
81
+ if (typeof row === 'object' && row !== null) {
82
+ return (row as Record<string, unknown>)[key];
83
+ }
84
+ return undefined;
85
+ }
86
+
87
+ const isEmpty = $derived(!loading && data.length === 0);
88
+ const skeletonRows = $derived(Array.from({ length: loadingRows }, (_, i) => i));
89
+ </script>
90
+
91
+ <div class="data-table-container {className}" class:data-table-container--sticky={stickyHeader}>
92
+ <table
93
+ class="data-table"
94
+ class:data-table--striped={striped}
95
+ class:data-table--row-hover={rowHover}
96
+ >
97
+ <thead class="data-table__head">
98
+ <tr>
99
+ {#each columns as column}
100
+ <th
101
+ class="data-table__header data-table__header--{column.align || 'left'}"
102
+ class:data-table__header--sortable={column.sortable}
103
+ style={column.width ? `width: ${column.width}` : undefined}
104
+ onclick={() => handleSort(column)}
105
+ role={column.sortable ? 'button' : undefined}
106
+ tabindex={column.sortable ? 0 : undefined}
107
+ onkeydown={(e) => {
108
+ if (column.sortable && (e.key === 'Enter' || e.key === ' ')) {
109
+ e.preventDefault();
110
+ handleSort(column);
111
+ }
112
+ }}
113
+ aria-sort={sortBy === column.key
114
+ ? sortOrder === 'asc'
115
+ ? 'ascending'
116
+ : 'descending'
117
+ : undefined}
118
+ >
119
+ <div class="data-table__header-content">
120
+ <span>{column.header}</span>
121
+ {#if column.sortable}
122
+ <span
123
+ class="data-table__sort-icon"
124
+ class:data-table__sort-icon--active={sortBy === column.key}
125
+ >
126
+ {#if sortBy === column.key}
127
+ <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
128
+ {#if sortOrder === 'asc'}
129
+ <path
130
+ fill-rule="evenodd"
131
+ d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
132
+ clip-rule="evenodd"
133
+ />
134
+ {:else}
135
+ <path
136
+ fill-rule="evenodd"
137
+ d="M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z"
138
+ clip-rule="evenodd"
139
+ />
140
+ {/if}
141
+ </svg>
142
+ {:else}
143
+ <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
144
+ <path
145
+ d="M5 8.5a.5.5 0 01.5-.5h9a.5.5 0 010 1h-9A.5.5 0 015 8.5zm0 3a.5.5 0 01.5-.5h9a.5.5 0 010 1h-9a.5.5 0 01-.5-.5z"
146
+ />
147
+ </svg>
148
+ {/if}
149
+ </span>
150
+ {/if}
151
+ </div>
152
+ </th>
153
+ {/each}
154
+ </tr>
155
+ </thead>
156
+ <tbody class="data-table__body">
157
+ {#if loading}
158
+ {#each skeletonRows as _row}
159
+ <tr class="data-table__row data-table__row--skeleton">
160
+ {#each columns as column}
161
+ <td
162
+ class="data-table__cell data-table__cell--{column.align || 'left'}"
163
+ style={column.width ? `width: ${column.width}` : undefined}
164
+ >
165
+ <div class="data-table__skeleton"></div>
166
+ </td>
167
+ {/each}
168
+ </tr>
169
+ {/each}
170
+ {:else if isEmpty}
171
+ <tr class="data-table__row data-table__row--empty">
172
+ <td colspan={columns.length} class="data-table__cell data-table__cell--empty">
173
+ {#if empty}
174
+ {@render empty()}
175
+ {:else}
176
+ <div class="data-table__empty-default">
177
+ <span>No data available</span>
178
+ </div>
179
+ {/if}
180
+ </td>
181
+ </tr>
182
+ {:else}
183
+ {#each data as row, index}
184
+ <tr class="data-table__row" data-row-index={index}>
185
+ {#each columns as column}
186
+ <td
187
+ class="data-table__cell data-table__cell--{column.align || 'left'}"
188
+ style={column.width ? `width: ${column.width}` : undefined}
189
+ >
190
+ {#if column.cell}
191
+ {@render column.cell(getCellValue(row, column.key), row)}
192
+ {:else}
193
+ {getCellValue(row, column.key) ?? '-'}
194
+ {/if}
195
+ </td>
196
+ {/each}
197
+ </tr>
198
+ {/each}
199
+ {/if}
200
+ </tbody>
201
+ </table>
202
+ </div>
203
+
204
+ <style>
205
+ /* Container with horizontal overflow */
206
+ .data-table-container {
207
+ width: 100%;
208
+ overflow-x: auto;
209
+ -webkit-overflow-scrolling: touch;
210
+ border-radius: var(--radius-lg, 0.5rem);
211
+ background: var(--color-bg-card, #ffffff);
212
+ box-shadow: var(--shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05));
213
+ }
214
+
215
+ .data-table-container--sticky {
216
+ max-height: 70vh;
217
+ overflow-y: auto;
218
+ }
219
+
220
+ /* Table base */
221
+ .data-table {
222
+ width: 100%;
223
+ border-collapse: collapse;
224
+ font-family: inherit;
225
+ font-size: var(--text-sm, 0.875rem);
226
+ }
227
+
228
+ /* Header */
229
+ .data-table__head {
230
+ background: var(--color-bg-muted, #f9fafb);
231
+ }
232
+
233
+ .data-table-container--sticky .data-table__head {
234
+ position: sticky;
235
+ top: 0;
236
+ z-index: 1;
237
+ }
238
+
239
+ .data-table__header {
240
+ padding: var(--space-md, 0.75rem) var(--space-lg, 1rem);
241
+ font-size: var(--text-xs, 0.75rem);
242
+ font-weight: 600;
243
+ color: var(--color-text-muted, #6b7280);
244
+ text-transform: uppercase;
245
+ letter-spacing: 0.05em;
246
+ white-space: nowrap;
247
+ border-bottom: 1px solid var(--color-border, #e5e7eb);
248
+ user-select: none;
249
+ }
250
+
251
+ .data-table__header--left {
252
+ text-align: left;
253
+ }
254
+
255
+ .data-table__header--center {
256
+ text-align: center;
257
+ }
258
+
259
+ .data-table__header--right {
260
+ text-align: right;
261
+ }
262
+
263
+ .data-table__header--sortable {
264
+ cursor: pointer;
265
+ transition: background-color 0.15s ease;
266
+ }
267
+
268
+ .data-table__header--sortable:hover {
269
+ background: var(--color-bg-hover, #f3f4f6);
270
+ }
271
+
272
+ .data-table__header--sortable:focus-visible {
273
+ outline: 2px solid var(--color-primary, #3b82f6);
274
+ outline-offset: -2px;
275
+ }
276
+
277
+ .data-table__header-content {
278
+ display: inline-flex;
279
+ align-items: center;
280
+ gap: var(--space-xs, 0.25rem);
281
+ }
282
+
283
+ /* Sort icon */
284
+ .data-table__sort-icon {
285
+ display: inline-flex;
286
+ width: 1rem;
287
+ height: 1rem;
288
+ color: var(--color-text-muted, #9ca3af);
289
+ transition: color 0.15s ease;
290
+ }
291
+
292
+ .data-table__sort-icon svg {
293
+ width: 100%;
294
+ height: 100%;
295
+ }
296
+
297
+ .data-table__sort-icon--active {
298
+ color: var(--color-primary, #3b82f6);
299
+ }
300
+
301
+ /* Body */
302
+ .data-table__body {
303
+ background: var(--color-bg-card, #ffffff);
304
+ }
305
+
306
+ /* Row */
307
+ .data-table__row {
308
+ border-bottom: 1px solid var(--color-border, #e5e7eb);
309
+ }
310
+
311
+ .data-table__row:last-child {
312
+ border-bottom: none;
313
+ }
314
+
315
+ /* Row hover */
316
+ .data-table--row-hover
317
+ .data-table__row:not(.data-table__row--skeleton):not(.data-table__row--empty):hover {
318
+ background: var(--color-bg-hover, #f9fafb);
319
+ }
320
+
321
+ /* Striped rows */
322
+ .data-table--striped .data-table__row:nth-child(even) {
323
+ background: var(--color-bg-muted, #f9fafb);
324
+ }
325
+
326
+ /* Cell */
327
+ .data-table__cell {
328
+ padding: var(--space-md, 0.75rem) var(--space-lg, 1rem);
329
+ color: var(--color-text, #1f2937);
330
+ vertical-align: middle;
331
+ }
332
+
333
+ .data-table__cell--left {
334
+ text-align: left;
335
+ }
336
+
337
+ .data-table__cell--center {
338
+ text-align: center;
339
+ }
340
+
341
+ .data-table__cell--right {
342
+ text-align: right;
343
+ }
344
+
345
+ .data-table__cell--empty {
346
+ padding: var(--space-2xl, 3rem) var(--space-lg, 1rem);
347
+ text-align: center;
348
+ }
349
+
350
+ /* Empty state */
351
+ .data-table__empty-default {
352
+ display: flex;
353
+ flex-direction: column;
354
+ align-items: center;
355
+ gap: var(--space-sm, 0.5rem);
356
+ color: var(--color-text-muted, #6b7280);
357
+ }
358
+
359
+ /* Skeleton loading */
360
+ .data-table__skeleton {
361
+ height: 1rem;
362
+ width: 75%;
363
+ background: linear-gradient(
364
+ 90deg,
365
+ var(--color-bg-muted, #e5e7eb) 25%,
366
+ var(--color-bg-skeleton-shine, #f3f4f6) 50%,
367
+ var(--color-bg-muted, #e5e7eb) 75%
368
+ );
369
+ background-size: 200% 100%;
370
+ animation: skeleton-shimmer 1.5s ease-in-out infinite;
371
+ border-radius: var(--radius-sm, 0.25rem);
372
+ }
373
+
374
+ .data-table__cell--center .data-table__skeleton {
375
+ margin: 0 auto;
376
+ }
377
+
378
+ .data-table__cell--right .data-table__skeleton {
379
+ margin-left: auto;
380
+ }
381
+
382
+ @keyframes skeleton-shimmer {
383
+ 0% {
384
+ background-position: 200% 0;
385
+ }
386
+ 100% {
387
+ background-position: -200% 0;
388
+ }
389
+ }
390
+
391
+ /* Dark mode support */
392
+ :global([data-theme='dark']) .data-table-container {
393
+ background: var(--color-bg-card-dark, #1f2937);
394
+ box-shadow: var(--shadow-sm-dark, 0 1px 2px 0 rgb(0 0 0 / 0.2));
395
+ }
396
+
397
+ :global([data-theme='dark']) .data-table__head {
398
+ background: var(--color-bg-muted-dark, #374151);
399
+ }
400
+
401
+ :global([data-theme='dark']) .data-table__header {
402
+ color: var(--color-text-muted-dark, #9ca3af);
403
+ border-bottom-color: var(--color-border-dark, #4b5563);
404
+ }
405
+
406
+ :global([data-theme='dark']) .data-table__header--sortable:hover {
407
+ background: var(--color-bg-hover-dark, #4b5563);
408
+ }
409
+
410
+ :global([data-theme='dark']) .data-table__body {
411
+ background: var(--color-bg-card-dark, #1f2937);
412
+ }
413
+
414
+ :global([data-theme='dark']) .data-table__row {
415
+ border-bottom-color: var(--color-border-dark, #374151);
416
+ }
417
+
418
+ :global([data-theme='dark'])
419
+ .data-table--row-hover
420
+ .data-table__row:not(.data-table__row--skeleton):not(.data-table__row--empty):hover {
421
+ background: var(--color-bg-hover-dark, #374151);
422
+ }
423
+
424
+ :global([data-theme='dark']) .data-table--striped .data-table__row:nth-child(even) {
425
+ background: var(--color-bg-muted-dark, #374151);
426
+ }
427
+
428
+ :global([data-theme='dark']) .data-table__cell {
429
+ color: var(--color-text-dark, #f9fafb);
430
+ }
431
+
432
+ :global([data-theme='dark']) .data-table__empty-default {
433
+ color: var(--color-text-muted-dark, #9ca3af);
434
+ }
435
+
436
+ :global([data-theme='dark']) .data-table__skeleton {
437
+ background: linear-gradient(
438
+ 90deg,
439
+ var(--color-bg-muted-dark, #374151) 25%,
440
+ var(--color-bg-skeleton-shine-dark, #4b5563) 50%,
441
+ var(--color-bg-muted-dark, #374151) 75%
442
+ );
443
+ background-size: 200% 100%;
444
+ }
445
+
446
+ /* Mobile touch targets */
447
+ @media (pointer: coarse) {
448
+ .data-table__header {
449
+ padding: var(--space-md, 0.75rem) var(--space-md, 0.75rem);
450
+ }
451
+
452
+ .data-table__cell {
453
+ padding: var(--space-md, 0.75rem) var(--space-md, 0.75rem);
454
+ }
455
+
456
+ .data-table__header--sortable {
457
+ min-height: 2.75rem;
458
+ }
459
+ }
460
+ </style>
@@ -0,0 +1,49 @@
1
+ /**
2
+ * DataTable - A sortable, customizable data table component
3
+ * Supports custom cell rendering, sorting, loading states, and responsive overflow
4
+ */
5
+ type SortOrder = 'asc' | 'desc';
6
+ type ColumnAlign = 'left' | 'center' | 'right';
7
+ interface ColumnDef {
8
+ /** Unique key matching the data property */
9
+ key: string;
10
+ /** Header text to display */
11
+ header: string;
12
+ /** Whether this column is sortable */
13
+ sortable?: boolean;
14
+ /** Fixed width (e.g., '100px', '10rem') */
15
+ width?: string;
16
+ /** Text alignment */
17
+ align?: ColumnAlign;
18
+ /** Custom cell renderer - receives (value, row) */
19
+ cell?: import('svelte').Snippet<[value: unknown, row: unknown]>;
20
+ }
21
+ interface Props {
22
+ /** Array of data objects to display */
23
+ data: unknown[];
24
+ /** Column definitions */
25
+ columns: ColumnDef[];
26
+ /** Currently sorted column key */
27
+ sortBy?: string;
28
+ /** Current sort direction */
29
+ sortOrder?: SortOrder;
30
+ /** Callback when sort changes */
31
+ onsort?: (column: string, order: SortOrder) => void;
32
+ /** Show loading skeleton */
33
+ loading?: boolean;
34
+ /** Number of skeleton rows to show when loading */
35
+ loadingRows?: number;
36
+ /** Custom empty state content */
37
+ empty?: import('svelte').Snippet;
38
+ /** Enable row hover effect */
39
+ rowHover?: boolean;
40
+ /** Enable striped rows */
41
+ striped?: boolean;
42
+ /** Make header sticky on scroll */
43
+ stickyHeader?: boolean;
44
+ /** Additional CSS classes */
45
+ class?: string;
46
+ }
47
+ declare const DataTable: import("svelte").Component<Props, {}, "sortBy" | "sortOrder">;
48
+ type DataTable = ReturnType<typeof DataTable>;
49
+ export default DataTable;
@@ -0,0 +1,2 @@
1
+ export { default as DataTable } from './DataTable.svelte';
2
+ export type { DataTableProps, DataTableColumn, DataTableSortOrder } from '../../types/index.js';
@@ -0,0 +1 @@
1
+ export { default as DataTable } from './DataTable.svelte';