@happyvertical/smrt-ui 0.38.26 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/AGENTS.md +23 -7
  2. package/README.md +132 -0
  3. package/dist/components/data/CollectionList.svelte +106 -0
  4. package/dist/components/data/CollectionList.svelte.d.ts +49 -0
  5. package/dist/components/data/CollectionList.svelte.d.ts.map +1 -0
  6. package/dist/components/data/CollectionToolbar.svelte +72 -0
  7. package/dist/components/data/CollectionToolbar.svelte.d.ts +20 -0
  8. package/dist/components/data/CollectionToolbar.svelte.d.ts.map +1 -0
  9. package/dist/components/data/DataTable.svelte +107 -17
  10. package/dist/components/data/DataTable.svelte.d.ts +2 -2
  11. package/dist/components/data/DataTable.svelte.d.ts.map +1 -1
  12. package/dist/components/data/__tests__/DataTable.test.js +61 -1
  13. package/dist/components/data/index.d.ts +2 -0
  14. package/dist/components/data/index.d.ts.map +1 -1
  15. package/dist/components/data/index.js +2 -0
  16. package/dist/components/data/types.d.ts +33 -0
  17. package/dist/components/data/types.d.ts.map +1 -1
  18. package/dist/components/feedback/Alert.svelte +53 -0
  19. package/dist/components/feedback/Alert.svelte.d.ts +14 -0
  20. package/dist/components/feedback/Alert.svelte.d.ts.map +1 -0
  21. package/dist/components/feedback/Drawer.svelte +34 -0
  22. package/dist/components/feedback/Drawer.svelte.d.ts +18 -0
  23. package/dist/components/feedback/Drawer.svelte.d.ts.map +1 -0
  24. package/dist/components/feedback/Meter.svelte +33 -0
  25. package/dist/components/feedback/Meter.svelte.d.ts +16 -0
  26. package/dist/components/feedback/Meter.svelte.d.ts.map +1 -0
  27. package/dist/components/feedback/Modal.svelte +9 -5
  28. package/dist/components/feedback/Modal.svelte.d.ts +2 -2
  29. package/dist/components/feedback/Modal.svelte.d.ts.map +1 -1
  30. package/dist/components/feedback/Progress.svelte +61 -0
  31. package/dist/components/feedback/Progress.svelte.d.ts +14 -0
  32. package/dist/components/feedback/Progress.svelte.d.ts.map +1 -0
  33. package/dist/components/feedback/Spinner.svelte +17 -0
  34. package/dist/components/feedback/Spinner.svelte.d.ts +9 -0
  35. package/dist/components/feedback/Spinner.svelte.d.ts.map +1 -0
  36. package/dist/components/feedback/ToastViewport.svelte +48 -0
  37. package/dist/components/feedback/ToastViewport.svelte.d.ts +10 -0
  38. package/dist/components/feedback/ToastViewport.svelte.d.ts.map +1 -0
  39. package/dist/components/feedback/__tests__/toast.test.js +49 -0
  40. package/dist/components/feedback/index.d.ts +8 -0
  41. package/dist/components/feedback/index.d.ts.map +1 -1
  42. package/dist/components/feedback/index.js +10 -3
  43. package/dist/components/feedback/toast.d.ts +28 -0
  44. package/dist/components/feedback/toast.d.ts.map +1 -0
  45. package/dist/components/feedback/toast.js +58 -0
  46. package/dist/components/forms/Checkbox.svelte +149 -0
  47. package/dist/components/forms/Checkbox.svelte.d.ts +13 -0
  48. package/dist/components/forms/Checkbox.svelte.d.ts.map +1 -0
  49. package/dist/components/forms/Combobox.svelte +172 -0
  50. package/dist/components/forms/Combobox.svelte.d.ts +18 -0
  51. package/dist/components/forms/Combobox.svelte.d.ts.map +1 -0
  52. package/dist/components/forms/DatePicker.svelte +25 -0
  53. package/dist/components/forms/DatePicker.svelte.d.ts +12 -0
  54. package/dist/components/forms/DatePicker.svelte.d.ts.map +1 -0
  55. package/dist/components/forms/ErrorSummary.svelte +32 -0
  56. package/dist/components/forms/ErrorSummary.svelte.d.ts +11 -0
  57. package/dist/components/forms/ErrorSummary.svelte.d.ts.map +1 -0
  58. package/dist/components/forms/Fieldset.svelte +32 -0
  59. package/dist/components/forms/Fieldset.svelte.d.ts +13 -0
  60. package/dist/components/forms/Fieldset.svelte.d.ts.map +1 -0
  61. package/dist/components/forms/FilePicker.svelte +116 -0
  62. package/dist/components/forms/FilePicker.svelte.d.ts +19 -0
  63. package/dist/components/forms/FilePicker.svelte.d.ts.map +1 -0
  64. package/dist/components/forms/Form.svelte +55 -2
  65. package/dist/components/forms/Form.svelte.d.ts +11 -1
  66. package/dist/components/forms/Form.svelte.d.ts.map +1 -1
  67. package/dist/components/forms/FormGroup.svelte +19 -2
  68. package/dist/components/forms/FormGroup.svelte.d.ts +3 -0
  69. package/dist/components/forms/FormGroup.svelte.d.ts.map +1 -1
  70. package/dist/components/forms/Input.svelte +127 -0
  71. package/dist/components/forms/Input.svelte.d.ts +9 -1
  72. package/dist/components/forms/Input.svelte.d.ts.map +1 -1
  73. package/dist/components/forms/InputGroup.svelte +17 -0
  74. package/dist/components/forms/InputGroup.svelte.d.ts +11 -0
  75. package/dist/components/forms/InputGroup.svelte.d.ts.map +1 -0
  76. package/dist/components/forms/Listbox.svelte +97 -0
  77. package/dist/components/forms/Listbox.svelte.d.ts +15 -0
  78. package/dist/components/forms/Listbox.svelte.d.ts.map +1 -0
  79. package/dist/components/forms/MultiSelect.svelte +159 -0
  80. package/dist/components/forms/MultiSelect.svelte.d.ts +16 -0
  81. package/dist/components/forms/MultiSelect.svelte.d.ts.map +1 -0
  82. package/dist/components/forms/Radio.svelte +34 -0
  83. package/dist/components/forms/Radio.svelte.d.ts +10 -0
  84. package/dist/components/forms/Radio.svelte.d.ts.map +1 -0
  85. package/dist/components/forms/RadioGroup.svelte +130 -0
  86. package/dist/components/forms/RadioGroup.svelte.d.ts +19 -0
  87. package/dist/components/forms/RadioGroup.svelte.d.ts.map +1 -0
  88. package/dist/components/forms/RangeSlider.svelte +137 -0
  89. package/dist/components/forms/RangeSlider.svelte.d.ts +21 -0
  90. package/dist/components/forms/RangeSlider.svelte.d.ts.map +1 -0
  91. package/dist/components/forms/SegmentedControl.svelte +87 -0
  92. package/dist/components/forms/SegmentedControl.svelte.d.ts +17 -0
  93. package/dist/components/forms/SegmentedControl.svelte.d.ts.map +1 -0
  94. package/dist/components/forms/Select.svelte +84 -3
  95. package/dist/components/forms/Select.svelte.d.ts +6 -1
  96. package/dist/components/forms/Select.svelte.d.ts.map +1 -1
  97. package/dist/components/forms/Slider.svelte +131 -0
  98. package/dist/components/forms/Slider.svelte.d.ts +18 -0
  99. package/dist/components/forms/Slider.svelte.d.ts.map +1 -0
  100. package/dist/components/forms/Switch.svelte +128 -0
  101. package/dist/components/forms/Switch.svelte.d.ts +14 -0
  102. package/dist/components/forms/Switch.svelte.d.ts.map +1 -0
  103. package/dist/components/forms/TagsInput.svelte +106 -0
  104. package/dist/components/forms/TagsInput.svelte.d.ts +17 -0
  105. package/dist/components/forms/TagsInput.svelte.d.ts.map +1 -0
  106. package/dist/components/forms/Textarea.svelte +84 -3
  107. package/dist/components/forms/Textarea.svelte.d.ts +6 -1
  108. package/dist/components/forms/Textarea.svelte.d.ts.map +1 -1
  109. package/dist/components/forms/TimePicker.svelte +25 -0
  110. package/dist/components/forms/TimePicker.svelte.d.ts +12 -0
  111. package/dist/components/forms/TimePicker.svelte.d.ts.map +1 -0
  112. package/dist/components/forms/ToggleButton.svelte +79 -0
  113. package/dist/components/forms/ToggleButton.svelte.d.ts +13 -0
  114. package/dist/components/forms/ToggleButton.svelte.d.ts.map +1 -0
  115. package/dist/components/forms/__tests__/composite-controls.fixture.svelte +29 -0
  116. package/dist/components/forms/__tests__/composite-controls.fixture.svelte.d.ts +8 -0
  117. package/dist/components/forms/__tests__/composite-controls.fixture.svelte.d.ts.map +1 -0
  118. package/dist/components/forms/__tests__/composite-controls.test.js +33 -0
  119. package/dist/components/forms/__tests__/control-interaction.test.js +95 -0
  120. package/dist/components/forms/__tests__/core-controls.fixture.svelte +39 -0
  121. package/dist/components/forms/__tests__/core-controls.fixture.svelte.d.ts +8 -0
  122. package/dist/components/forms/__tests__/core-controls.fixture.svelte.d.ts.map +1 -0
  123. package/dist/components/forms/__tests__/core-controls.test.js +90 -0
  124. package/dist/components/forms/control-dom.d.ts +6 -0
  125. package/dist/components/forms/control-dom.d.ts.map +1 -0
  126. package/dist/components/forms/control-dom.js +38 -0
  127. package/dist/components/forms/control-interaction-context.d.ts +9 -0
  128. package/dist/components/forms/control-interaction-context.d.ts.map +1 -0
  129. package/dist/components/forms/control-interaction-context.js +15 -0
  130. package/dist/components/forms/control-interaction.d.ts +147 -0
  131. package/dist/components/forms/control-interaction.d.ts.map +1 -0
  132. package/dist/components/forms/control-interaction.js +265 -0
  133. package/dist/components/forms/form-group-context.d.ts +7 -0
  134. package/dist/components/forms/form-group-context.d.ts.map +1 -1
  135. package/dist/components/forms/index.d.ts +22 -1
  136. package/dist/components/forms/index.d.ts.map +1 -1
  137. package/dist/components/forms/index.js +21 -1
  138. package/dist/components/forms/radio-group-context.d.ts +12 -0
  139. package/dist/components/forms/radio-group-context.d.ts.map +1 -0
  140. package/dist/components/forms/radio-group-context.js +11 -0
  141. package/dist/components/forms/types.d.ts +14 -0
  142. package/dist/components/forms/types.d.ts.map +1 -0
  143. package/dist/components/forms/types.js +1 -0
  144. package/dist/components/forms/use-control-registration.svelte.d.ts +8 -0
  145. package/dist/components/forms/use-control-registration.svelte.d.ts.map +1 -0
  146. package/dist/components/forms/use-control-registration.svelte.js +15 -0
  147. package/dist/components/ui/Accordion.svelte +44 -0
  148. package/dist/components/ui/Accordion.svelte.d.ts +12 -0
  149. package/dist/components/ui/Accordion.svelte.d.ts.map +1 -0
  150. package/dist/components/ui/AccordionItem.svelte +42 -0
  151. package/dist/components/ui/AccordionItem.svelte.d.ts +11 -0
  152. package/dist/components/ui/AccordionItem.svelte.d.ts.map +1 -0
  153. package/dist/components/ui/Disclosure.svelte +50 -0
  154. package/dist/components/ui/Disclosure.svelte.d.ts +13 -0
  155. package/dist/components/ui/Disclosure.svelte.d.ts.map +1 -0
  156. package/dist/components/ui/Dropdown.svelte +5 -7
  157. package/dist/components/ui/Dropdown.svelte.d.ts +9 -0
  158. package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -1
  159. package/dist/components/ui/Popover.svelte +102 -0
  160. package/dist/components/ui/Popover.svelte.d.ts +16 -0
  161. package/dist/components/ui/Popover.svelte.d.ts.map +1 -0
  162. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte +13 -0
  163. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte.d.ts +19 -0
  164. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte.d.ts.map +1 -0
  165. package/dist/components/ui/__tests__/interaction-primitives.test.js +31 -0
  166. package/dist/components/ui/accordion-context.d.ts +7 -0
  167. package/dist/components/ui/accordion-context.d.ts.map +1 -0
  168. package/dist/components/ui/accordion-context.js +11 -0
  169. package/dist/components/ui/index.d.ts +5 -1
  170. package/dist/components/ui/index.d.ts.map +1 -1
  171. package/dist/components/ui/index.js +5 -1
  172. package/dist/index.d.ts +1 -1
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/playground.d.ts +2 -0
  175. package/dist/playground.d.ts.map +1 -0
  176. package/dist/playground.js +1 -0
  177. package/dist/svelte/__tests__/playground.test.js +18 -0
  178. package/dist/svelte/playground/BaseControlsPreview.svelte +233 -0
  179. package/dist/svelte/playground/BaseControlsPreview.svelte.d.ts +4 -0
  180. package/dist/svelte/playground/BaseControlsPreview.svelte.d.ts.map +1 -0
  181. package/dist/svelte/playground/CollectionsPreview.svelte +59 -0
  182. package/dist/svelte/playground/CollectionsPreview.svelte.d.ts +4 -0
  183. package/dist/svelte/playground/CollectionsPreview.svelte.d.ts.map +1 -0
  184. package/dist/svelte/playground/DataTablePreview.svelte +247 -0
  185. package/dist/svelte/playground/DataTablePreview.svelte.d.ts +4 -0
  186. package/dist/svelte/playground/DataTablePreview.svelte.d.ts.map +1 -0
  187. package/dist/svelte/playground/FeedbackPreview.svelte +51 -0
  188. package/dist/svelte/playground/FeedbackPreview.svelte.d.ts +4 -0
  189. package/dist/svelte/playground/FeedbackPreview.svelte.d.ts.map +1 -0
  190. package/dist/svelte/playground/InteractiveControlsPreview.svelte +109 -0
  191. package/dist/svelte/playground/InteractiveControlsPreview.svelte.d.ts +4 -0
  192. package/dist/svelte/playground/InteractiveControlsPreview.svelte.d.ts.map +1 -0
  193. package/dist/svelte/playground.d.ts +20 -0
  194. package/dist/svelte/playground.d.ts.map +1 -0
  195. package/dist/svelte/playground.js +65 -0
  196. package/dist/theme/index.d.ts +6 -4
  197. package/dist/theme/index.d.ts.map +1 -1
  198. package/dist/theme/index.js +6 -7
  199. package/dist/themes/context.svelte.js +1 -1
  200. package/dist/themes/index.d.ts +1 -1
  201. package/dist/themes/index.js +1 -1
  202. package/dist/themes/smrt/index.js +1 -1
  203. package/dist/types-generic.d.ts +7 -1
  204. package/dist/types-generic.d.ts.map +1 -1
  205. package/package.json +23 -12
@@ -15,6 +15,7 @@ import type { Snippet } from 'svelte';
15
15
  import { M } from '../../i18n/strings.js';
16
16
  import Trans from '../../i18n/Trans.svelte';
17
17
  import { useI18n } from '../../i18n/use-i18n.js';
18
+ import Pagination from '../ui/Pagination.svelte';
18
19
  import type {
19
20
  DataTableColumn,
20
21
  DataTableProps,
@@ -43,6 +44,20 @@ let {
43
44
  sortable = false,
44
45
  sort = $bindable({ columnId: null, direction: null }),
45
46
  onSortChange,
47
+ manualSorting = false,
48
+ filterFn,
49
+ page = $bindable(1),
50
+ pageSize,
51
+ manualPagination = false,
52
+ totalRows,
53
+ onPageChange,
54
+ expanded = $bindable(new Set<string | number>()),
55
+ onExpandedChange,
56
+ canExpand,
57
+ expandedContent,
58
+ toolbar,
59
+ footer,
60
+ visibleColumnIds,
46
61
  loading = false,
47
62
  empty,
48
63
  rowClass,
@@ -62,6 +77,10 @@ function getRowKey(row: T, index: number): string | number {
62
77
  return row[rowKey] as string | number;
63
78
  }
64
79
 
80
+ function getDisplayRowKey(row: T, index: number): string | number {
81
+ return getRowKey(row, displayIndexOffset + index);
82
+ }
83
+
65
84
  // Handle sort click
66
85
  function handleSort(column: DataTableColumn<T>) {
67
86
  if (!sortable || !column.sortable) return;
@@ -104,13 +123,32 @@ function handleRowSelect(key: string | number, event: Event) {
104
123
  // Handle select all
105
124
  function handleSelectAll() {
106
125
  if (allSelected) {
107
- selected = new Set();
126
+ const visibleKeys = new Set(
127
+ displayData.map((row, i) => getDisplayRowKey(row, i)),
128
+ );
129
+ selected = new Set([...selected].filter((key) => !visibleKeys.has(key)));
108
130
  } else {
109
- selected = new Set(sortedData.map((row, i) => getRowKey(row, i)));
131
+ selected = new Set([
132
+ ...selected,
133
+ ...displayData.map((row, i) => getDisplayRowKey(row, i)),
134
+ ]);
110
135
  }
111
136
  onSelectionChange?.(selected);
112
137
  }
113
138
 
139
+ function handleExpanded(key: string | number, event: Event) {
140
+ event.stopPropagation();
141
+ const next = new Set(expanded);
142
+ next.has(key) ? next.delete(key) : next.add(key);
143
+ expanded = next;
144
+ onExpandedChange?.(next);
145
+ }
146
+
147
+ function handlePageChange(next: number) {
148
+ page = Math.min(Math.max(1, next), totalPages);
149
+ onPageChange?.(page);
150
+ }
151
+
114
152
  // Handle row click
115
153
  function handleRowClick(row: T, index: number) {
116
154
  onRowClick?.(row, index);
@@ -127,19 +165,25 @@ function setIndeterminate(node: HTMLInputElement, value: boolean) {
127
165
  }
128
166
 
129
167
  // Get visible columns
130
- const visibleColumns = $derived(columns.filter((col) => !col.hidden));
168
+ const visibleColumns = $derived(
169
+ columns.filter(
170
+ (col) => !col.hidden && (!visibleColumnIds || visibleColumnIds.has(col.id)),
171
+ ),
172
+ );
173
+
174
+ const filteredData = $derived(filterFn ? data.filter(filterFn) : data);
131
175
 
132
176
  // Sort data
133
177
  const sortedData = $derived.by(() => {
134
- if (!sort.columnId || !sort.direction) return data;
178
+ if (manualSorting || !sort.columnId || !sort.direction) return filteredData;
135
179
 
136
180
  const column = columns.find((c) => c.id === sort.columnId);
137
- if (!column) return data;
181
+ if (!column) return filteredData;
138
182
 
139
183
  const accessor = column.accessor ?? column.id;
140
184
  const direction = sort.direction;
141
185
 
142
- return [...data].sort((a, b) => {
186
+ return [...filteredData].sort((a, b) => {
143
187
  if (column.sortFn) {
144
188
  return column.sortFn(a, b, direction);
145
189
  }
@@ -147,12 +191,33 @@ const sortedData = $derived.by(() => {
147
191
  });
148
192
  });
149
193
 
194
+ const totalRowCount = $derived(totalRows ?? sortedData.length);
195
+ const totalPages = $derived(
196
+ pageSize ? Math.max(1, Math.ceil(totalRowCount / pageSize)) : 1,
197
+ );
198
+ const displayData = $derived.by(() => {
199
+ if (!pageSize || manualPagination) return sortedData;
200
+ const start = (page - 1) * pageSize;
201
+ return sortedData.slice(start, start + pageSize);
202
+ });
203
+ const displayIndexOffset = $derived(pageSize ? (page - 1) * pageSize : 0);
204
+
205
+ $effect(() => {
206
+ if (page > totalPages) handlePageChange(totalPages);
207
+ });
208
+
150
209
  // Selection state
151
210
  const allSelected = $derived(
152
- data.length > 0 && data.every((row, i) => selected.has(getRowKey(row, i))),
211
+ displayData.length > 0 &&
212
+ displayData.every((row, i) => selected.has(getDisplayRowKey(row, i))),
153
213
  );
154
214
  const someSelected = $derived(
155
- data.some((row, i) => selected.has(getRowKey(row, i))) && !allSelected,
215
+ displayData.some((row, i) => selected.has(getDisplayRowKey(row, i))) &&
216
+ !allSelected,
217
+ );
218
+
219
+ const columnCount = $derived(
220
+ visibleColumns.length + (selectable ? 1 : 0) + (expandedContent ? 1 : 0),
156
221
  );
157
222
 
158
223
  // Get cell value
@@ -169,10 +234,8 @@ const sizeClasses = {
169
234
  };
170
235
  </script>
171
236
 
172
- <div
173
- class="data-table-container"
174
- class:data-table-container--sticky={stickyHeader}
175
- >
237
+ {#if toolbar}<div class="data-table-toolbar">{@render toolbar()}</div>{/if}
238
+ <div class="data-table-container" class:data-table-container--sticky={stickyHeader}>
176
239
  <table
177
240
  class="data-table {sizeClasses[size]}"
178
241
  class:data-table--striped={striped}
@@ -186,6 +249,7 @@ const sizeClasses = {
186
249
 
187
250
  <thead class="data-table__head">
188
251
  <tr class="data-table__row data-table__row--header">
252
+ {#if expandedContent}<th class="data-table__cell data-table__cell--expand" scope="col"><span class="sr-only">Expand</span></th>{/if}
189
253
  {#if selectable}
190
254
  <th class="data-table__cell data-table__cell--checkbox" scope="col">
191
255
  <input
@@ -245,7 +309,7 @@ const sizeClasses = {
245
309
  <tr class="data-table__row data-table__row--loading">
246
310
  <td
247
311
  class="data-table__cell data-table__cell--loading"
248
- colspan={visibleColumns.length + (selectable ? 1 : 0)}
312
+ colspan={columnCount}
249
313
  >
250
314
  <div class="data-table__loading-indicator">
251
315
  <span class="data-table__spinner"></span>
@@ -253,11 +317,11 @@ const sizeClasses = {
253
317
  </div>
254
318
  </td>
255
319
  </tr>
256
- {:else if sortedData.length === 0}
320
+ {:else if displayData.length === 0}
257
321
  <tr class="data-table__row data-table__row--empty">
258
322
  <td
259
323
  class="data-table__cell data-table__cell--empty"
260
- colspan={visibleColumns.length + (selectable ? 1 : 0)}
324
+ colspan={columnCount}
261
325
  >
262
326
  {#if empty}
263
327
  {@render empty()}
@@ -269,9 +333,11 @@ const sizeClasses = {
269
333
  </td>
270
334
  </tr>
271
335
  {:else}
272
- {#each sortedData as row, index (getRowKey(row, index))}
273
- {@const key = getRowKey(row, index)}
336
+ {#each displayData as row, index (getDisplayRowKey(row, index))}
337
+ {@const key = getDisplayRowKey(row, index)}
274
338
  {@const isSelected = selected.has(key)}
339
+ {@const isExpanded = expanded.has(key)}
340
+ {@const rowCanExpand = canExpand?.(row, index) ?? true}
275
341
  <tr
276
342
  class="data-table__row {rowClass?.(row, index) ?? ''}"
277
343
  class:data-table__row--selected={isSelected}
@@ -285,6 +351,11 @@ const sizeClasses = {
285
351
  }
286
352
  }}
287
353
  >
354
+ {#if expandedContent}
355
+ <td class="data-table__cell data-table__cell--expand">
356
+ {#if rowCanExpand}<button type="button" class="data-table__expand-button" aria-label={isExpanded ? 'Collapse row' : 'Expand row'} aria-expanded={isExpanded} onclick={(event) => handleExpanded(key, event)}>{isExpanded ? '−' : '+'}</button>{/if}
357
+ </td>
358
+ {/if}
288
359
  {#if selectable}
289
360
  <td class="data-table__cell data-table__cell--checkbox">
290
361
  <input
@@ -313,11 +384,20 @@ const sizeClasses = {
313
384
  </td>
314
385
  {/each}
315
386
  </tr>
387
+ {#if expandedContent && isExpanded}
388
+ <tr class="data-table__row data-table__row--expanded">
389
+ <td class="data-table__cell data-table__cell--expanded" colspan={columnCount}>{@render expandedContent({ row, index })}</td>
390
+ </tr>
391
+ {/if}
316
392
  {/each}
317
393
  {/if}
318
394
  </tbody>
395
+ {#if footer}
396
+ <tfoot><tr><td class="data-table__cell data-table__footer" colspan={columnCount}>{@render footer({ rows: displayData })}</td></tr></tfoot>
397
+ {/if}
319
398
  </table>
320
399
  </div>
400
+ {#if pageSize && totalPages > 1}<Pagination currentPage={page} {totalPages} onPageChange={handlePageChange} aria-label="Table pages" />{/if}
321
401
 
322
402
  <style>
323
403
  .data-table-container {
@@ -325,6 +405,10 @@ const sizeClasses = {
325
405
  overflow-x: auto;
326
406
  }
327
407
 
408
+ .data-table-toolbar { margin-bottom: var(--smrt-spacing-2); }
409
+
410
+ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
411
+
328
412
  .data-table-container--sticky {
329
413
  max-height: 100%;
330
414
  overflow-y: auto;
@@ -444,6 +528,12 @@ const sizeClasses = {
444
528
  text-align: center;
445
529
  }
446
530
 
531
+ .data-table__cell--expand { width: 2.75rem; text-align: center; }
532
+ .data-table__expand-button { width: 1.75rem; height: 1.75rem; border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-full); background: transparent; color: var(--smrt-color-on-surface); cursor: pointer; }
533
+ .data-table__expand-button:focus-visible { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; }
534
+ .data-table__cell--expanded { padding: var(--smrt-spacing-4); background: var(--smrt-color-surface-container-low); }
535
+ .data-table__footer { border-top: 2px solid var(--smrt-color-outline-variant); font-weight: var(--smrt-typography-weight-medium); }
536
+
447
537
  .data-table__checkbox {
448
538
  width: 18px;
449
539
  height: 18px;
@@ -25,7 +25,7 @@ interface ExtendedProps<T> extends DataTableProps<T> {
25
25
  declare function $$render<T>(): {
26
26
  props: ExtendedProps<T>;
27
27
  exports: {};
28
- bindings: "sort" | "selected";
28
+ bindings: "sort" | "page" | "selected" | "expanded";
29
29
  slots: {};
30
30
  events: {};
31
31
  };
@@ -33,7 +33,7 @@ declare class __sveltets_Render<T> {
33
33
  props(): ReturnType<typeof $$render<T>>['props'];
34
34
  events(): ReturnType<typeof $$render<T>>['events'];
35
35
  slots(): ReturnType<typeof $$render<T>>['slots'];
36
- bindings(): "sort" | "selected";
36
+ bindings(): "sort" | "page" | "selected" | "expanded";
37
37
  exports(): {};
38
38
  }
39
39
  interface $$IsomorphicComponent {
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/data/DataTable.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAGf,MAAM,YAAY,CAAC;AAIpB,UAAU,aAAa,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAClD,+DAA+D;IAC/D,IAAI,CAAC,EAAE,OAAO,CACZ;QAAC;YAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;YAAC,GAAG,EAAE,CAAC,CAAC;YAAC,KAAK,EAAE,OAAO,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE;KAAC,CACxE,CAAC;CACH;AAAC,iBAAS,QAAQ,CAAC,CAAC;WA0PQ,aAAa,CAAC,CAAC,CAAC;;;;;EAA4F;AACzI,cAAM,iBAAiB,CAAC,CAAC;IACrB,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAChD,MAAM,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAClD,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAChD,QAAQ;IACR,OAAO;CACV;AAED,UAAU,qBAAqB;IAC3B,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;KAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5X,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3H,YAAY,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;CACjE;AACD,QAAA,MAAM,SAAS,EAAE,qBAAmC,CAAC;AACnC,KAAK,SAAS,CAAC,CAAC,IAAI,YAAY,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"DataTable.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/data/DataTable.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAGf,MAAM,YAAY,CAAC;AAIpB,UAAU,aAAa,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAClD,+DAA+D;IAC/D,IAAI,CAAC,EAAE,OAAO,CACZ;QAAC;YAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;YAAC,GAAG,EAAE,CAAC,CAAC;YAAC,KAAK,EAAE,OAAO,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE;KAAC,CACxE,CAAC;CACH;AAAC,iBAAS,QAAQ,CAAC,CAAC;WA6UQ,aAAa,CAAC,CAAC,CAAC;;;;;EAAgH;AAC7J,cAAM,iBAAiB,CAAC,CAAC;IACrB,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAChD,MAAM,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAClD,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAChD,QAAQ;IACR,OAAO;CACV;AAED,UAAU,qBAAqB;IAC3B,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;KAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5X,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3H,YAAY,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;CACjE;AACD,QAAA,MAAM,SAAS,EAAE,qBAAmC,CAAC;AACnC,KAAK,SAAS,CAAC,CAAC,IAAI,YAAY,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,eAAe,SAAS,CAAC"}
@@ -7,7 +7,8 @@
7
7
  */
8
8
  import { render, screen } from '@testing-library/svelte';
9
9
  import userEvent from '@testing-library/user-event';
10
- import { describe, expect, it } from 'vitest';
10
+ import { createRawSnippet } from 'svelte';
11
+ import { describe, expect, it, vi } from 'vitest';
11
12
  import { expectNoA11yViolations } from '../../../test-support/a11y';
12
13
  import DataTable from '../DataTable.svelte';
13
14
  const columns = [
@@ -39,6 +40,65 @@ describe('DataTable', () => {
39
40
  await userEvent.click(screen.getByRole('button', { name: 'Name' }));
40
41
  expect(nameHeader).toHaveAttribute('aria-sort', 'ascending');
41
42
  });
43
+ it('filters and paginates client-side rows', async () => {
44
+ render(DataTable, {
45
+ props: {
46
+ data: [...data, { name: 'Grace', age: 85 }],
47
+ columns,
48
+ filterFn: (person) => person.age > 40,
49
+ pageSize: 1,
50
+ },
51
+ });
52
+ expect(screen.getByRole('cell', { name: 'Linus' })).toBeInTheDocument();
53
+ expect(screen.queryByRole('cell', { name: 'Grace' })).not.toBeInTheDocument();
54
+ await userEvent.click(screen.getByRole('button', { name: 'Next page' }));
55
+ expect(screen.getByRole('cell', { name: 'Grace' })).toBeInTheDocument();
56
+ });
57
+ it('keeps fallback selection keys unique across pages', async () => {
58
+ const onSelectionChange = vi.fn();
59
+ render(DataTable, {
60
+ props: {
61
+ data,
62
+ columns,
63
+ pageSize: 1,
64
+ selectable: true,
65
+ onSelectionChange,
66
+ },
67
+ });
68
+ await userEvent.click(screen.getByRole('checkbox', { name: 'Select all rows' }));
69
+ await userEvent.click(screen.getByRole('button', { name: 'Next page' }));
70
+ await userEvent.click(screen.getByRole('checkbox', { name: 'Select all rows' }));
71
+ expect(onSelectionChange).toHaveBeenLastCalledWith(new Set([0, 1]));
72
+ });
73
+ it('does not carry fallback expansion keys onto the next page', async () => {
74
+ render(DataTable, {
75
+ props: {
76
+ data,
77
+ columns,
78
+ pageSize: 1,
79
+ expandedContent: createRawSnippet(() => ({
80
+ render: () => '<p>Row detail</p>',
81
+ })),
82
+ },
83
+ });
84
+ await userEvent.click(screen.getByRole('button', { name: 'Expand row' }));
85
+ await userEvent.click(screen.getByRole('button', { name: 'Next page' }));
86
+ expect(screen.queryByText('Row detail')).not.toBeInTheDocument();
87
+ expect(screen.getByRole('button', { name: 'Expand row' })).toBeInTheDocument();
88
+ });
89
+ it('reveals expandable row content', async () => {
90
+ render(DataTable, {
91
+ props: {
92
+ data,
93
+ columns,
94
+ expandedContent: createRawSnippet(() => ({
95
+ render: () => '<p>Row detail</p>',
96
+ })),
97
+ },
98
+ });
99
+ await userEvent.click(screen.getAllByRole('button', { name: 'Expand row' })[0]);
100
+ expect(screen.getByText('Row detail')).toBeInTheDocument();
101
+ });
42
102
  it('is axe-clean', async () => {
43
103
  const { container } = render(DataTable, {
44
104
  props: { data, columns, caption: 'People' },
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Data display components
3
3
  */
4
+ export { default as CollectionList, default as ContentList, } from './CollectionList.svelte';
5
+ export { default as CollectionToolbar } from './CollectionToolbar.svelte';
4
6
  export { default as DataTable } from './DataTable.svelte';
5
7
  export * from './types.js';
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/data/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/data/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,OAAO,IAAI,cAAc,EACzB,OAAO,IAAI,WAAW,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,cAAc,YAAY,CAAC"}
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * Data display components
3
3
  */
4
+ export { default as CollectionList, default as ContentList, } from './CollectionList.svelte';
5
+ export { default as CollectionToolbar } from './CollectionToolbar.svelte';
4
6
  export { default as DataTable } from './DataTable.svelte';
5
7
  export * from './types.js';
@@ -74,6 +74,39 @@ export interface DataTableProps<T> {
74
74
  sort?: SortState;
75
75
  /** Sort change callback */
76
76
  onSortChange?: (sort: SortState) => void;
77
+ /** Parent owns sorting and supplies already-sorted rows. */
78
+ manualSorting?: boolean;
79
+ /** Optional client-side row filter. */
80
+ filterFn?: (row: T, index: number) => boolean;
81
+ /** Current 1-based page. Pagination is enabled when pageSize is set. */
82
+ page?: number;
83
+ /** Rows per page. */
84
+ pageSize?: number;
85
+ /** Parent owns pagination and supplies only the current page. */
86
+ manualPagination?: boolean;
87
+ /** Total server row count when manualPagination is enabled. */
88
+ totalRows?: number;
89
+ /** Page change callback. */
90
+ onPageChange?: (page: number) => void;
91
+ /** Controlled set of expanded row keys. */
92
+ expanded?: Set<string | number>;
93
+ /** Expansion change callback. */
94
+ onExpandedChange?: (expanded: Set<string | number>) => void;
95
+ /** Predicate controlling which rows can expand. */
96
+ canExpand?: (row: T, index: number) => boolean;
97
+ /** Expanded row content. */
98
+ expandedContent?: Snippet<[{
99
+ row: T;
100
+ index: number;
101
+ }]>;
102
+ /** Optional content above the table. */
103
+ toolbar?: Snippet;
104
+ /** Optional full-width table footer content. */
105
+ footer?: Snippet<[{
106
+ rows: T[];
107
+ }]>;
108
+ /** Controlled visible column ids. Column.hidden is still respected. */
109
+ visibleColumnIds?: Set<string>;
77
110
  /** Loading state */
78
111
  loading?: boolean;
79
112
  /** Empty state content */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/data/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/data/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ export interface Props {
5
+ variant?: 'info' | 'success' | 'warning' | 'error';
6
+ title?: string;
7
+ children?: Snippet;
8
+ action?: Snippet;
9
+ dismissible?: boolean;
10
+ ondismiss?: () => void;
11
+ class?: string;
12
+ }
13
+
14
+ let {
15
+ variant = 'info',
16
+ title,
17
+ children,
18
+ action,
19
+ dismissible = false,
20
+ ondismiss,
21
+ class: className = '',
22
+ }: Props = $props();
23
+ const role = $derived(
24
+ variant === 'error' || variant === 'warning' ? 'alert' : 'status',
25
+ );
26
+ </script>
27
+
28
+ <div class="alert alert--{variant} {className}" {role}>
29
+ <span class="marker" aria-hidden="true"></span>
30
+ <div class="content">
31
+ {#if title}<strong>{title}</strong>{/if}
32
+ {#if children}<div class="message">{@render children()}</div>{/if}
33
+ </div>
34
+ {#if action}<div class="action">{@render action()}</div>{/if}
35
+ {#if dismissible}
36
+ <button type="button" class="dismiss" aria-label="Dismiss" onclick={ondismiss}>×</button>
37
+ {/if}
38
+ </div>
39
+
40
+ <style>
41
+ .alert { --alert-color: var(--smrt-color-primary); display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: start; gap: var(--smrt-spacing-3); padding: var(--smrt-spacing-3) var(--smrt-spacing-4); border: 1px solid color-mix(in srgb, var(--alert-color) 35%, var(--smrt-color-outline-variant)); border-radius: var(--smrt-radius-medium); background: color-mix(in srgb, var(--alert-color) 8%, var(--smrt-color-surface)); color: var(--smrt-color-on-surface); }
42
+ .alert--success { --alert-color: var(--smrt-color-success, #2e7d32); }
43
+ .alert--warning { --alert-color: var(--smrt-color-warning, #a45b00); }
44
+ .alert--error { --alert-color: var(--smrt-color-error); }
45
+ .marker { width: .65rem; height: .65rem; margin-top: .4rem; border-radius: 50%; background: var(--alert-color); }
46
+ .content { min-width: 0; }
47
+ strong { display: block; font: var(--smrt-typography-title-small-font); }
48
+ .message { color: var(--smrt-color-on-surface-variant); }
49
+ .action { align-self: center; }
50
+ .dismiss { width: 2rem; height: 2rem; margin: -.35rem; border: 0; border-radius: var(--smrt-radius-full); background: transparent; color: inherit; font-size: 1.25rem; cursor: pointer; }
51
+ .dismiss:hover { background: color-mix(in srgb, currentColor 10%, transparent); }
52
+ .dismiss:focus-visible { outline: 2px solid var(--smrt-color-primary); }
53
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { Snippet } from 'svelte';
2
+ export interface Props {
3
+ variant?: 'info' | 'success' | 'warning' | 'error';
4
+ title?: string;
5
+ children?: Snippet;
6
+ action?: Snippet;
7
+ dismissible?: boolean;
8
+ ondismiss?: () => void;
9
+ class?: string;
10
+ }
11
+ declare const Alert: import("svelte").Component<Props, {}, "">;
12
+ type Alert = ReturnType<typeof Alert>;
13
+ export default Alert;
14
+ //# sourceMappingURL=Alert.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Alert.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmCD,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import Modal from './Modal.svelte';
4
+
5
+ export interface Props {
6
+ open?: boolean;
7
+ title?: string;
8
+ side?: 'start' | 'end';
9
+ size?: 'sm' | 'md' | 'lg' | 'xl';
10
+ showClose?: boolean;
11
+ closeOnBackdrop?: boolean;
12
+ children?: Snippet;
13
+ header?: Snippet;
14
+ footer?: Snippet;
15
+ onclose?: () => void;
16
+ ariaLabel?: string;
17
+ }
18
+
19
+ let {
20
+ open = $bindable(false),
21
+ title,
22
+ side = 'end',
23
+ size = 'md',
24
+ showClose = true,
25
+ closeOnBackdrop = true,
26
+ children,
27
+ header,
28
+ footer,
29
+ onclose,
30
+ ariaLabel,
31
+ }: Props = $props();
32
+ </script>
33
+
34
+ <Modal bind:open {title} {size} placement={side} {showClose} {closeOnBackdrop} onClose={onclose} {header} {footer} {children} {ariaLabel} />
@@ -0,0 +1,18 @@
1
+ import type { Snippet } from 'svelte';
2
+ export interface Props {
3
+ open?: boolean;
4
+ title?: string;
5
+ side?: 'start' | 'end';
6
+ size?: 'sm' | 'md' | 'lg' | 'xl';
7
+ showClose?: boolean;
8
+ closeOnBackdrop?: boolean;
9
+ children?: Snippet;
10
+ header?: Snippet;
11
+ footer?: Snippet;
12
+ onclose?: () => void;
13
+ ariaLabel?: string;
14
+ }
15
+ declare const Drawer: import("svelte").Component<Props, {}, "open">;
16
+ type Drawer = ReturnType<typeof Drawer>;
17
+ export default Drawer;
18
+ //# sourceMappingURL=Drawer.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Drawer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAItC,MAAM,WAAW,KAAK;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IACvB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyBD,QAAA,MAAM,MAAM,+CAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ export interface Props {
3
+ value: number;
4
+ min?: number;
5
+ max?: number;
6
+ low?: number;
7
+ high?: number;
8
+ optimum?: number;
9
+ label: string;
10
+ showValue?: boolean;
11
+ formatValue?: (value: number) => string;
12
+ class?: string;
13
+ }
14
+ let {
15
+ value,
16
+ min = 0,
17
+ max = 100,
18
+ low,
19
+ high,
20
+ optimum,
21
+ label,
22
+ showValue = true,
23
+ formatValue = (next) => String(next),
24
+ class: className = '',
25
+ }: Props = $props();
26
+ </script>
27
+ <div class="meter {className}"><div class="meter__header"><span>{label}</span>{#if showValue}<span>{formatValue(value)}</span>{/if}</div>
28
+ <meter {value} {min} {max} {low} {high} {optimum}>{formatValue(value)}</meter></div>
29
+ <style>
30
+ .meter { display: grid; gap: var(--smrt-spacing-2); color: var(--smrt-color-on-surface); }
31
+ .meter__header { display: flex; justify-content: space-between; font: var(--smrt-typography-label-large-font); }
32
+ meter { width: 100%; height: .75rem; accent-color: var(--smrt-color-primary); }
33
+ </style>
@@ -0,0 +1,16 @@
1
+ export interface Props {
2
+ value: number;
3
+ min?: number;
4
+ max?: number;
5
+ low?: number;
6
+ high?: number;
7
+ optimum?: number;
8
+ label: string;
9
+ showValue?: boolean;
10
+ formatValue?: (value: number) => string;
11
+ class?: string;
12
+ }
13
+ declare const Meter: import("svelte").Component<Props, {}, "">;
14
+ type Meter = ReturnType<typeof Meter>;
15
+ export default Meter;
16
+ //# sourceMappingURL=Meter.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Meter.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Meter.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsBD,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}