@happyvertical/smrt-ui 0.55.16 → 0.55.17

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 (138) hide show
  1. package/AGENTS.md +14 -0
  2. package/README.md +68 -0
  3. package/dist/components/calendar/Calendar.svelte +59 -56
  4. package/dist/components/calendar/CalendarView.svelte +79 -76
  5. package/dist/components/calendar/DayView.svelte +39 -36
  6. package/dist/components/chat/MessageBubble.svelte +26 -23
  7. package/dist/components/chat/ReactionPicker.svelte +10 -7
  8. package/dist/components/chat/TypingIndicator.svelte +12 -9
  9. package/dist/components/data/CollectionList.svelte +10 -7
  10. package/dist/components/data/CollectionToolbar.svelte +5 -2
  11. package/dist/components/data/DataTable.svelte +51 -48
  12. package/dist/components/data/ListSortSelect.svelte +8 -5
  13. package/dist/components/data/SortableHeader.svelte +9 -6
  14. package/dist/components/display/ConfidenceBadge.svelte +11 -8
  15. package/dist/components/display/CurrencyDisplay.svelte +7 -4
  16. package/dist/components/display/DateDisplay.svelte +6 -3
  17. package/dist/components/display/Icon.svelte +4 -1
  18. package/dist/components/display/StatusBadge.svelte +9 -6
  19. package/dist/components/feedback/Alert.svelte +9 -6
  20. package/dist/components/feedback/ConfirmDialog.svelte +13 -10
  21. package/dist/components/feedback/LoadingOverlay.svelte +35 -32
  22. package/dist/components/feedback/Meter.svelte +4 -1
  23. package/dist/components/feedback/Modal.svelte +20 -17
  24. package/dist/components/feedback/PhoneSheet.svelte +4 -1
  25. package/dist/components/feedback/Progress.svelte +8 -5
  26. package/dist/components/feedback/ProgressBar.svelte +13 -10
  27. package/dist/components/feedback/Spinner.svelte +4 -1
  28. package/dist/components/feedback/ToastViewport.svelte +17 -14
  29. package/dist/components/feedback/WorkingStrip.svelte +6 -3
  30. package/dist/components/forms/CameraCapture.svelte +6 -3
  31. package/dist/components/forms/Checkbox.svelte +10 -7
  32. package/dist/components/forms/Combobox.svelte +4 -1
  33. package/dist/components/forms/DatePicker.svelte +7 -2
  34. package/dist/components/forms/DictationButton.svelte +17 -14
  35. package/dist/components/forms/DictationStatus.svelte +12 -9
  36. package/dist/components/forms/ErrorSummary.svelte +4 -1
  37. package/dist/components/forms/FieldLabel.svelte +9 -6
  38. package/dist/components/forms/Fieldset.svelte +4 -1
  39. package/dist/components/forms/FilePicker.svelte +4 -1
  40. package/dist/components/forms/Form.svelte +1 -1
  41. package/dist/components/forms/FormActionBar.svelte +4 -1
  42. package/dist/components/forms/FormGroup.svelte +6 -3
  43. package/dist/components/forms/Input.svelte +14 -11
  44. package/dist/components/forms/InputGroup.svelte +5 -2
  45. package/dist/components/forms/Listbox.svelte +4 -1
  46. package/dist/components/forms/MultiSelect.svelte +4 -1
  47. package/dist/components/forms/Radio.svelte +8 -5
  48. package/dist/components/forms/RadioGroup.svelte +5 -2
  49. package/dist/components/forms/RangeSlider.svelte +4 -1
  50. package/dist/components/forms/RelationInput.svelte +7 -4
  51. package/dist/components/forms/SearchInput.svelte +5 -2
  52. package/dist/components/forms/SegmentedControl.svelte +5 -2
  53. package/dist/components/forms/Select.svelte +12 -9
  54. package/dist/components/forms/SignaturePad.svelte +6 -3
  55. package/dist/components/forms/Slider.svelte +4 -1
  56. package/dist/components/forms/StagedControlReview.svelte +15 -12
  57. package/dist/components/forms/Switch.svelte +7 -4
  58. package/dist/components/forms/TagsInput.svelte +4 -1
  59. package/dist/components/forms/Textarea.svelte +13 -10
  60. package/dist/components/forms/TimePicker.svelte +7 -2
  61. package/dist/components/forms/Toggle.svelte +13 -10
  62. package/dist/components/forms/ToggleButton.svelte +4 -1
  63. package/dist/components/layout/ActionGroup.svelte +4 -1
  64. package/dist/components/layout/Container.svelte +4 -1
  65. package/dist/components/layout/EmptyState.svelte +11 -8
  66. package/dist/components/layout/Footer.svelte +4 -1
  67. package/dist/components/layout/Grid.svelte +13 -10
  68. package/dist/components/layout/Header.svelte +4 -1
  69. package/dist/components/layout/Masthead.svelte +4 -1
  70. package/dist/components/layout/PageHeader.svelte +10 -7
  71. package/dist/components/layout/PageLayout.svelte +3 -0
  72. package/dist/components/layout/SummaryCard.svelte +9 -6
  73. package/dist/components/memberships/MembershipCard.svelte +5 -2
  74. package/dist/components/memberships/MembershipList.svelte +5 -2
  75. package/dist/components/nav/FilterChips.svelte +13 -10
  76. package/dist/components/nav/Tabs.svelte +28 -24
  77. package/dist/components/permissions/PermissionPicker.svelte +4 -1
  78. package/dist/components/roles/RoleBadge.svelte +8 -5
  79. package/dist/components/roles/RoleSelector.svelte +21 -18
  80. package/dist/components/theme/ThemeProvider.svelte +7 -4
  81. package/dist/components/ui/Accordion.svelte +4 -1
  82. package/dist/components/ui/AccordionItem.svelte +4 -1
  83. package/dist/components/ui/Avatar.svelte +10 -7
  84. package/dist/components/ui/Badge.svelte +4 -1
  85. package/dist/components/ui/Button.svelte +11 -8
  86. package/dist/components/ui/Card.svelte +7 -4
  87. package/dist/components/ui/Chip.svelte +12 -9
  88. package/dist/components/ui/Disclosure.svelte +4 -1
  89. package/dist/components/ui/Dropdown.svelte +17 -14
  90. package/dist/components/ui/IconToggle.svelte +10 -7
  91. package/dist/components/ui/IconToggle.svelte.d.ts +1 -1
  92. package/dist/components/ui/IconToggle.svelte.d.ts.map +1 -1
  93. package/dist/components/ui/IconToggleGroup.svelte +8 -5
  94. package/dist/components/ui/Pagination.svelte +11 -8
  95. package/dist/components/ui/Popover.svelte +5 -2
  96. package/dist/components/ui/Skeleton.svelte +10 -7
  97. package/dist/components/ui/Tooltip.svelte +12 -9
  98. package/dist/components/ui/Tree.svelte +10 -7
  99. package/dist/styles/layers.css +8 -0
  100. package/dist/styles/layers.d.ts +9 -0
  101. package/dist/styles/layers.d.ts.map +1 -0
  102. package/dist/styles/layers.js +8 -0
  103. package/dist/styles/tokens.css +27 -69
  104. package/dist/styles/unstyled.css +65 -0
  105. package/dist/svelte/playground/BaseControlsPreview.svelte +3 -0
  106. package/dist/svelte/playground/CalendarPreview.svelte +5 -2
  107. package/dist/svelte/playground/CapturePreview.svelte +3 -0
  108. package/dist/svelte/playground/CodeSelectorsPreview.svelte +3 -0
  109. package/dist/svelte/playground/CollectionsPreview.svelte +3 -0
  110. package/dist/svelte/playground/DataTablePreview.svelte +3 -0
  111. package/dist/svelte/playground/FeedbackPreview.svelte +3 -0
  112. package/dist/svelte/playground/InteractiveControlsPreview.svelte +3 -0
  113. package/dist/svelte/playground/StylelessPreview.svelte +110 -0
  114. package/dist/svelte/playground/StylelessPreview.svelte.d.ts +4 -0
  115. package/dist/svelte/playground/StylelessPreview.svelte.d.ts.map +1 -0
  116. package/dist/svelte/playground.d.ts.map +1 -1
  117. package/dist/svelte/playground.js +10 -0
  118. package/dist/test-support/setup.js +9 -0
  119. package/dist/theme/ThemeProvider.svelte +3 -0
  120. package/dist/themes/CUSTOM_THEME_GUIDE.md +25 -0
  121. package/dist/themes/README.md +25 -0
  122. package/dist/themes/ThemeProvider.svelte +11 -2
  123. package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
  124. package/dist/themes/components/ColorSchemeToggle.svelte +17 -14
  125. package/dist/themes/components/ThemeSwitcher.svelte +14 -11
  126. package/dist/themes/create-theme.d.ts.map +1 -1
  127. package/dist/themes/create-theme.js +8 -5
  128. package/dist/themes/css-generator.d.ts.map +1 -1
  129. package/dist/themes/css-generator.js +5 -4
  130. package/dist/themes/required-tokens.generated.json +172 -0
  131. package/dist/themes/styles/base.css +4 -1
  132. package/dist/themes/styles/glass.css +4 -1
  133. package/dist/themes/styles/happyvertical.css +7 -3
  134. package/dist/themes/styles/smrt.css +4 -1
  135. package/dist/themes/styles/studio.css +4 -1
  136. package/dist/utils/theme/typography.d.ts +21 -21
  137. package/dist/utils/theme/typography.js +21 -21
  138. package/package.json +8 -2
@@ -13,8 +13,8 @@
13
13
  Use `as="div"` with `role="columnheader"` semantics for grid layouts that
14
14
  are not a `<table>`.
15
15
 
16
- Style hooks (set on the header or an ancestor): `--sortable-header-padding`
17
- (the control's padding) and `--sortable-header-font-weight` (default 600;
16
+ Style hooks (set on the header or an ancestor): `--smrt-sortable-header-padding`
17
+ (the control's padding) and `--smrt-sortable-header-font-weight` (default 600;
18
18
  `inherit` takes the surrounding head row's weight).
19
19
  -->
20
20
  <script lang="ts">
@@ -92,7 +92,7 @@ const actionLabel = $derived(listSortActionLabel(sort, columnId, label, spec));
92
92
  scope={as === 'th' ? 'col' : undefined}
93
93
  role={as === 'div' ? 'columnheader' : undefined}
94
94
  aria-sort={aria}
95
- data-sort-column={columnId}
95
+ data-sort-column={columnId} data-smrt-component="SortableHeader"
96
96
  >
97
97
  {#if href}
98
98
  <a
@@ -119,6 +119,8 @@ const actionLabel = $derived(listSortActionLabel(sort, columnId, label, spec));
119
119
  </svelte:element>
120
120
 
121
121
  <style>
122
+ @layer smrt.reset, smrt.structure, smrt.theme;
123
+ @layer smrt.theme {
122
124
  .sortable-header {
123
125
  padding: 0;
124
126
  font-weight: inherit;
@@ -136,12 +138,12 @@ const actionLabel = $derived(listSortActionLabel(sort, columnId, label, spec));
136
138
  gap: 0.25rem;
137
139
  min-height: 2.75rem;
138
140
  width: 100%;
139
- padding: var(--sortable-header-padding, 0.5rem 0.75rem);
141
+ padding: var(--smrt-sortable-header-padding, 0.5rem 0.75rem);
140
142
  border: 0;
141
143
  background: transparent;
142
144
  color: inherit;
143
145
  font: inherit;
144
- font-weight: var(--sortable-header-font-weight, 600);
146
+ font-weight: var(--smrt-sortable-header-font-weight, 600);
145
147
  text-align: inherit;
146
148
  text-decoration: none;
147
149
  cursor: pointer;
@@ -156,7 +158,7 @@ const actionLabel = $derived(listSortActionLabel(sort, columnId, label, spec));
156
158
  text-decoration: underline;
157
159
  }
158
160
  .sortable-header__control:focus-visible {
159
- outline: 2px solid var(--color-focus, var(--color-primary, currentColor));
161
+ outline: 2px solid var(--smrt-color-primary, var(--smrt-color-primary, currentColor));
160
162
  outline-offset: -2px;
161
163
  }
162
164
  .sortable-header__icon {
@@ -166,4 +168,5 @@ const actionLabel = $derived(listSortActionLabel(sort, columnId, label, spec));
166
168
  .sortable-header__icon.is-active {
167
169
  opacity: 1;
168
170
  }
171
+ }
169
172
  </style>
@@ -84,15 +84,15 @@ const valueText = $derived(
84
84
  class="confidence-badge {className}"
85
85
  class:sm={size === 'sm'}
86
86
  class:lg={size === 'lg'}
87
- style:--badge-bg={colors.bg}
88
- style:--badge-text={colors.text}
89
- style:--bar-color={colors.bar}
87
+ style:--smrt-badge-bg={colors.bg}
88
+ style:--smrt-badge-text={colors.text}
89
+ style:--smrt-confidence-badge-bar-color={colors.bar}
90
90
  role="meter"
91
91
  aria-valuenow={clampedConfidence}
92
92
  aria-valuemin={0}
93
93
  aria-valuemax={100}
94
94
  aria-valuetext={valueText}
95
- aria-label={ariaLabel ?? defaultLabel}
95
+ aria-label={ariaLabel ?? defaultLabel} data-smrt-component="ConfidenceBadge"
96
96
  >
97
97
  <span class="confidence-bar" style:width="{clampedConfidence}%"></span>
98
98
  {#if showPercent}
@@ -101,6 +101,8 @@ const valueText = $derived(
101
101
  </span>
102
102
 
103
103
  <style>
104
+ @layer smrt.reset, smrt.structure, smrt.theme;
105
+ @layer smrt.theme {
104
106
  .confidence-badge {
105
107
  display: inline-flex;
106
108
  align-items: center;
@@ -108,9 +110,9 @@ const valueText = $derived(
108
110
  padding: 0.25rem 0.5rem;
109
111
  font-size: var(--smrt-typography-label-medium-size, 0.75rem);
110
112
  font-weight: var(--smrt-typography-weight-medium, 500);
111
- border-radius: var(--smrt-radius-sm, 4px);
112
- background-color: var(--badge-bg);
113
- color: var(--badge-text);
113
+ border-radius: var(--smrt-radius-sm);
114
+ background-color: var(--smrt-badge-bg);
115
+ color: var(--smrt-badge-text);
114
116
  position: relative;
115
117
  overflow: hidden;
116
118
  min-width: 60px;
@@ -133,7 +135,7 @@ const valueText = $derived(
133
135
  left: 0;
134
136
  top: 0;
135
137
  bottom: 0;
136
- background-color: var(--bar-color);
138
+ background-color: var(--smrt-confidence-badge-bar-color);
137
139
  opacity: 0.3;
138
140
  transition: width var(--smrt-duration-short4, 300ms) var(--smrt-easing-standard, ease);
139
141
  }
@@ -143,4 +145,5 @@ const valueText = $derived(
143
145
  z-index: 1;
144
146
  font-variant-numeric: tabular-nums;
145
147
  }
148
+ }
146
149
  </style>
@@ -203,12 +203,14 @@ const colorClass = $derived.by(() => {
203
203
  class:lg={size === 'lg'}
204
204
  class:negative={colorClass === 'negative'}
205
205
  class:positive={colorClass === 'positive'}
206
- class:invalid={formatted.invalidCode !== null}
206
+ class:invalid={formatted.invalidCode !== null} data-smrt-component="CurrencyDisplay"
207
207
  >
208
208
  {formatted.text}
209
209
  </span>
210
210
 
211
211
  <style>
212
+ @layer smrt.reset, smrt.structure, smrt.theme;
213
+ @layer smrt.theme {
212
214
  .currency-display {
213
215
  font-variant-numeric: tabular-nums;
214
216
  white-space: nowrap;
@@ -224,14 +226,15 @@ const colorClass = $derived.by(() => {
224
226
  }
225
227
 
226
228
  .currency-display.negative {
227
- color: var(--smrt-color-error, #dc2626);
229
+ color: var(--smrt-color-error);
228
230
  }
229
231
 
230
232
  .currency-display.positive {
231
- color: var(--smrt-color-tertiary, #16a34a);
233
+ color: var(--smrt-color-tertiary);
232
234
  }
233
235
 
234
236
  .currency-display.invalid {
235
- color: var(--smrt-color-error, #dc2626);
237
+ color: var(--smrt-color-error);
236
238
  }
239
+ }
237
240
  </style>
@@ -163,22 +163,25 @@ const isoString = $derived(
163
163
  </script>
164
164
 
165
165
  {#if parsedDate}
166
- <time class="date-display {className}" datetime={isoString}>
166
+ <time class="date-display {className}" datetime={isoString} data-smrt-component="DateDisplay">
167
167
  {formatted}
168
168
  </time>
169
169
  {:else}
170
- <span class="date-display date-fallback {className}">
170
+ <span class="date-display date-fallback {className}" data-smrt-component="DateDisplay">
171
171
  {fallback}
172
172
  </span>
173
173
  {/if}
174
174
 
175
175
  <style>
176
+ @layer smrt.reset, smrt.structure, smrt.theme;
177
+ @layer smrt.theme {
176
178
  .date-display {
177
179
  white-space: nowrap;
178
180
  }
179
181
 
180
182
  .date-fallback {
181
- color: var(--smrt-color-on-surface-variant, #9ca3af);
183
+ color: var(--smrt-color-on-surface-variant);
182
184
  font-style: italic;
183
185
  }
186
+ }
184
187
  </style>
@@ -50,15 +50,18 @@ const pxSize = $derived(typeof size === 'number' ? `${size}px` : size);
50
50
  fill={color}
51
51
  aria-hidden={!isInformative}
52
52
  aria-label={ariaLabel}
53
- role={isInformative ? 'img' : undefined}
53
+ role={isInformative ? 'img' : undefined} data-smrt-component="Icon"
54
54
  >
55
55
  <path d={finalPath} />
56
56
  </svg>
57
57
 
58
58
  <style>
59
+ @layer smrt.reset, smrt.structure, smrt.theme;
60
+ @layer smrt.theme {
59
61
  svg {
60
62
  display: inline-block;
61
63
  flex-shrink: 0;
62
64
  vertical-align: middle;
63
65
  }
66
+ }
64
67
  </style>
@@ -251,24 +251,26 @@ const displayLabel = $derived(label ?? status.replace(/_/g, ' '));
251
251
  class:sm={size === 'sm'}
252
252
  class:lg={size === 'lg'}
253
253
  class:outline={variant === 'outline'}
254
- style:--badge-bg={colors.bg}
255
- style:--badge-text={colors.text}
254
+ style:--smrt-badge-bg={colors.bg}
255
+ style:--smrt-badge-text={colors.text} data-smrt-component="StatusBadge"
256
256
  >
257
257
  {displayLabel}
258
258
  </span>
259
259
 
260
260
  <style>
261
+ @layer smrt.reset, smrt.structure, smrt.theme;
262
+ @layer smrt.theme {
261
263
  .status-badge {
262
264
  display: inline-flex;
263
265
  align-items: center;
264
266
  padding: 0.25rem 0.75rem;
265
267
  font-size: var(--smrt-typography-label-medium-size, 0.75rem);
266
268
  font-weight: var(--smrt-typography-label-medium-weight, 500);
267
- border-radius: var(--smrt-radius-full, 9999px);
269
+ border-radius: var(--smrt-radius-full);
268
270
  white-space: nowrap;
269
271
  text-transform: capitalize;
270
- background-color: var(--badge-bg);
271
- color: var(--badge-text);
272
+ background-color: var(--smrt-badge-bg);
273
+ color: var(--smrt-badge-text);
272
274
  line-height: 1.25;
273
275
  }
274
276
 
@@ -284,6 +286,7 @@ const displayLabel = $derived(label ?? status.replace(/_/g, ' '));
284
286
 
285
287
  .status-badge.outline {
286
288
  background-color: transparent;
287
- border: 1px solid var(--badge-text);
289
+ border: 1px solid var(--smrt-badge-text);
288
290
  }
291
+ }
289
292
  </style>
@@ -32,7 +32,7 @@ const role = $derived(
32
32
  );
33
33
  </script>
34
34
 
35
- <div class="alert alert--{variant} {className}" {role}>
35
+ <div class="alert alert--{variant} {className}" {role} data-smrt-component="Alert">
36
36
  <span class="marker" aria-hidden="true"></span>
37
37
  <div class="content">
38
38
  {#if title}<strong>{title}</strong>{/if}
@@ -45,11 +45,13 @@ const role = $derived(
45
45
  </div>
46
46
 
47
47
  <style>
48
- .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); }
49
- .alert--success { --alert-color: var(--smrt-color-success, #2e7d32); }
50
- .alert--warning { --alert-color: var(--smrt-color-warning, #a45b00); }
51
- .alert--error { --alert-color: var(--smrt-color-error); }
52
- .marker { width: .65rem; height: .65rem; margin-top: .4rem; border-radius: 50%; background: var(--alert-color); }
48
+ @layer smrt.reset, smrt.structure, smrt.theme;
49
+ @layer smrt.theme {
50
+ .alert { --smrt-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(--smrt-alert-color) 35%, var(--smrt-color-outline-variant)); border-radius: var(--smrt-radius-medium); background: color-mix(in srgb, var(--smrt-alert-color) 8%, var(--smrt-color-surface)); color: var(--smrt-color-on-surface); }
51
+ .alert--success { --smrt-alert-color: var(--smrt-color-success); }
52
+ .alert--warning { --smrt-alert-color: var(--smrt-color-warning); }
53
+ .alert--error { --smrt-alert-color: var(--smrt-color-error); }
54
+ .marker { width: .65rem; height: .65rem; margin-top: .4rem; border-radius: 50%; background: var(--smrt-alert-color); }
53
55
  .content { min-width: 0; }
54
56
  strong { display: block; font: var(--smrt-typography-title-small-font); }
55
57
  .message { color: var(--smrt-color-on-surface-variant); }
@@ -57,4 +59,5 @@ const role = $derived(
57
59
  .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; }
58
60
  .dismiss:hover { background: color-mix(in srgb, currentColor 10%, transparent); }
59
61
  .dismiss:focus-visible { outline: 2px solid var(--smrt-color-primary); }
62
+ }
60
63
  </style>
@@ -134,7 +134,7 @@ function handleKeydown(e: KeyboardEvent) {
134
134
  tabindex="-1"
135
135
  onclick={handleBackdropClick}
136
136
  onkeydown={handleKeydown}
137
- oncancel={handleCancel}
137
+ oncancel={handleCancel} data-smrt-component="ConfirmDialog"
138
138
  >
139
139
  <div class="dialog-content">
140
140
  <h2 id={`${instanceId}-title`} class="dialog-title">{title}</h2>
@@ -176,6 +176,8 @@ function handleKeydown(e: KeyboardEvent) {
176
176
  {/if}
177
177
 
178
178
  <style>
179
+ @layer smrt.reset, smrt.structure, smrt.theme;
180
+ @layer smrt.theme {
179
181
  .dialog-backdrop {
180
182
  position: fixed;
181
183
  inset: 0;
@@ -201,7 +203,7 @@ function handleKeydown(e: KeyboardEvent) {
201
203
  .dialog-content {
202
204
  background-color: var(--smrt-color-surface-container-high);
203
205
  border-radius: var(--smrt-radius-3xl, 32px);
204
- padding: var(--smrt-spacing-6, 24px);
206
+ padding: var(--smrt-spacing-6);
205
207
  max-width: 400px;
206
208
  width: 100%;
207
209
  box-shadow: var(--smrt-elevation-3);
@@ -224,32 +226,32 @@ function handleKeydown(e: KeyboardEvent) {
224
226
  .dialog-title {
225
227
  font: var(--smrt-typography-headline-small-font);
226
228
  color: var(--smrt-color-on-surface);
227
- margin: 0 0 var(--smrt-spacing-4, 16px);
229
+ margin: 0 0 var(--smrt-spacing-4);
228
230
  }
229
231
 
230
232
  .dialog-message {
231
233
  font: var(--smrt-typography-body-medium-font);
232
234
  color: var(--smrt-color-on-surface-variant);
233
- margin: 0 0 var(--smrt-spacing-6, 24px);
235
+ margin: 0 0 var(--smrt-spacing-6);
234
236
  line-height: 1.5;
235
237
  }
236
238
 
237
239
  .dialog-actions {
238
240
  display: flex;
239
241
  justify-content: flex-end;
240
- gap: var(--smrt-spacing-2, 8px);
242
+ gap: var(--smrt-spacing-2);
241
243
  }
242
244
 
243
245
  .btn {
244
246
  display: inline-flex;
245
247
  align-items: center;
246
248
  justify-content: center;
247
- gap: var(--smrt-spacing-2, 8px);
249
+ gap: var(--smrt-spacing-2);
248
250
  height: 40px;
249
- padding: 0 var(--smrt-spacing-6, 24px);
251
+ padding: 0 var(--smrt-spacing-6);
250
252
  font: var(--smrt-typography-label-large-font);
251
253
  font-weight: var(--smrt-typography-weight-medium, 500);
252
- border-radius: var(--smrt-radius-2xl, 24px);
254
+ border-radius: var(--smrt-radius-2xl);
253
255
  cursor: pointer;
254
256
  transition: all var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, ease);
255
257
  border: none;
@@ -265,7 +267,7 @@ function handleKeydown(e: KeyboardEvent) {
265
267
  .btn-text {
266
268
  background: transparent;
267
269
  color: var(--smrt-color-primary);
268
- padding: 0 var(--smrt-spacing-3, 12px);
270
+ padding: 0 var(--smrt-spacing-3);
269
271
  }
270
272
 
271
273
  .btn-text:hover:not(:disabled) {
@@ -292,7 +294,7 @@ function handleKeydown(e: KeyboardEvent) {
292
294
  height: 18px;
293
295
  border: 2px solid transparent;
294
296
  border-top-color: currentColor;
295
- border-radius: var(--smrt-radius-full, 9999px);
297
+ border-radius: var(--smrt-radius-full);
296
298
  animation: spin 0.8s linear infinite;
297
299
  }
298
300
 
@@ -310,4 +312,5 @@ function handleKeydown(e: KeyboardEvent) {
310
312
  animation: none;
311
313
  }
312
314
  }
315
+ }
313
316
  </style>
@@ -70,7 +70,7 @@ function handleKeydown(e: KeyboardEvent) {
70
70
  aria-modal="true"
71
71
  aria-labelledby="loading-title"
72
72
  aria-describedby={items.length > 0 ? 'loading-items' : undefined}
73
- aria-busy={!error}
73
+ aria-busy={!error} data-smrt-component="LoadingOverlay"
74
74
  >
75
75
  <div class="overlay-backdrop"></div>
76
76
 
@@ -132,6 +132,8 @@ function handleKeydown(e: KeyboardEvent) {
132
132
  {/if}
133
133
 
134
134
  <style>
135
+ @layer smrt.reset, smrt.structure, smrt.theme;
136
+ @layer smrt.theme {
135
137
  .loading-overlay {
136
138
  position: fixed;
137
139
  inset: 0;
@@ -151,8 +153,8 @@ function handleKeydown(e: KeyboardEvent) {
151
153
  .overlay-content {
152
154
  position: relative;
153
155
  background: var(--smrt-color-surface-container-high, white);
154
- border-radius: var(--smrt-radius-xl, 16px);
155
- padding: var(--smrt-spacing-8, 32px) var(--smrt-spacing-10, 40px);
156
+ border-radius: var(--smrt-radius-xl);
157
+ padding: var(--smrt-spacing-8) var(--smrt-spacing-10);
156
158
  max-width: 400px;
157
159
  width: 90%;
158
160
  text-align: center;
@@ -162,7 +164,7 @@ function handleKeydown(e: KeyboardEvent) {
162
164
  .loading-icon {
163
165
  width: 48px;
164
166
  height: 48px;
165
- margin: 0 auto var(--smrt-spacing-4, 16px);
167
+ margin: 0 auto var(--smrt-spacing-4);
166
168
  }
167
169
 
168
170
  .icon {
@@ -171,12 +173,12 @@ function handleKeydown(e: KeyboardEvent) {
171
173
  }
172
174
 
173
175
  .icon.spinner {
174
- color: var(--smrt-color-primary, #3b82f6);
176
+ color: var(--smrt-color-primary);
175
177
  animation: spin 1s linear infinite;
176
178
  }
177
179
 
178
180
  .icon.error {
179
- color: var(--smrt-color-error, #ef4444);
181
+ color: var(--smrt-color-error);
180
182
  }
181
183
 
182
184
  @keyframes spin {
@@ -191,22 +193,22 @@ function handleKeydown(e: KeyboardEvent) {
191
193
  .title {
192
194
  font-size: var(--smrt-typography-title-large-size, 1.25rem);
193
195
  font-weight: var(--smrt-typography-weight-semibold, 600);
194
- color: var(--smrt-color-on-surface, #1f2937);
195
- margin: 0 0 var(--smrt-spacing-4, 16px);
196
+ color: var(--smrt-color-on-surface);
197
+ margin: 0 0 var(--smrt-spacing-4);
196
198
  }
197
199
 
198
200
  .progress-container {
199
201
  display: flex;
200
202
  align-items: center;
201
- gap: var(--smrt-spacing-3, 12px);
202
- margin: var(--smrt-spacing-4, 16px) 0;
203
+ gap: var(--smrt-spacing-3);
204
+ margin: var(--smrt-spacing-4) 0;
203
205
  }
204
206
 
205
207
  .progress-bar {
206
208
  flex: 1;
207
209
  height: 8px;
208
- background: var(--smrt-color-surface-container-highest, #e5e7eb);
209
- border-radius: var(--smrt-radius-sm, 4px);
210
+ background: var(--smrt-color-surface-container-highest);
211
+ border-radius: var(--smrt-radius-sm);
210
212
  overflow: hidden;
211
213
  }
212
214
 
@@ -217,57 +219,57 @@ function handleKeydown(e: KeyboardEvent) {
217
219
  var(--smrt-color-primary),
218
220
  color-mix(in srgb, var(--smrt-color-primary) 70%, white)
219
221
  );
220
- border-radius: var(--smrt-radius-sm, 4px);
222
+ border-radius: var(--smrt-radius-sm);
221
223
  transition: width var(--smrt-duration-short4, 300ms) var(--smrt-easing-standard, ease);
222
224
  }
223
225
 
224
226
  .progress-text {
225
227
  font-size: var(--smrt-typography-label-large-size, 0.875rem);
226
228
  font-weight: var(--smrt-typography-weight-semibold, 600);
227
- color: var(--smrt-color-primary, #3b82f6);
229
+ color: var(--smrt-color-primary);
228
230
  min-width: 40px;
229
231
  }
230
232
 
231
233
  .items-container {
232
234
  display: flex;
233
235
  flex-wrap: wrap;
234
- gap: var(--smrt-spacing-2, 8px);
236
+ gap: var(--smrt-spacing-2);
235
237
  justify-content: center;
236
- margin-top: var(--smrt-spacing-4, 16px);
238
+ margin-top: var(--smrt-spacing-4);
237
239
  }
238
240
 
239
241
  .item-badge {
240
242
  font-size: var(--smrt-typography-label-medium-size, 0.75rem);
241
- padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-3, 12px);
242
- border-radius: var(--smrt-radius-full, 9999px);
243
- background: var(--smrt-color-primary-container, #dcfce7);
244
- color: var(--smrt-color-on-primary-container, #166534);
243
+ padding: var(--smrt-spacing-1) var(--smrt-spacing-3);
244
+ border-radius: var(--smrt-radius-full);
245
+ background: var(--smrt-color-primary-container);
246
+ color: var(--smrt-color-on-primary-container);
245
247
  }
246
248
 
247
249
  .error-message {
248
250
  font-size: var(--smrt-typography-body-medium-size, 0.875rem);
249
- color: var(--smrt-color-error, #ef4444);
250
- margin: var(--smrt-spacing-4, 16px) 0 0;
251
- padding: var(--smrt-spacing-3, 12px);
252
- background: var(--smrt-color-error-container, #fef2f2);
253
- border-radius: var(--smrt-radius-md, 8px);
251
+ color: var(--smrt-color-error);
252
+ margin: var(--smrt-spacing-4) 0 0;
253
+ padding: var(--smrt-spacing-3);
254
+ background: var(--smrt-color-error-container);
255
+ border-radius: var(--smrt-radius-md);
254
256
  }
255
257
 
256
258
  .dismiss-btn {
257
- margin-top: var(--smrt-spacing-5, 20px);
258
- padding: var(--smrt-spacing-3, 12px) var(--smrt-spacing-5, 20px);
259
+ margin-top: var(--smrt-spacing-5);
260
+ padding: var(--smrt-spacing-3) var(--smrt-spacing-5);
259
261
  font-size: var(--smrt-typography-label-large-size, 0.875rem);
260
- color: var(--smrt-color-on-surface-variant, #6b7280);
262
+ color: var(--smrt-color-on-surface-variant);
261
263
  background: transparent;
262
- border: 1px solid var(--smrt-color-outline, #9ca3af);
263
- border-radius: var(--smrt-radius-md, 8px);
264
+ border: 1px solid var(--smrt-color-outline);
265
+ border-radius: var(--smrt-radius-md);
264
266
  cursor: pointer;
265
267
  transition: all var(--smrt-duration-short2, 150ms) var(--smrt-easing-standard, ease);
266
268
  }
267
269
 
268
270
  .dismiss-btn:hover {
269
- background: var(--smrt-color-surface-container-highest, #f3f4f6);
270
- border-color: var(--smrt-color-outline, #9ca3af);
271
+ background: var(--smrt-color-surface-container-highest);
272
+ border-color: var(--smrt-color-outline);
271
273
  }
272
274
 
273
275
  .dismiss-btn:focus-visible {
@@ -283,4 +285,5 @@ function handleKeydown(e: KeyboardEvent) {
283
285
  transition: none;
284
286
  }
285
287
  }
288
+ }
286
289
  </style>
@@ -34,10 +34,13 @@ let {
34
34
  class: className = '',
35
35
  }: Props = $props();
36
36
  </script>
37
- <div class="meter {className}"><div class="meter__header"><span>{label}</span>{#if showValue}<span>{formatValue(value)}</span>{/if}</div>
37
+ <div class="meter {className}" data-smrt-component="Meter"><div class="meter__header"><span>{label}</span>{#if showValue}<span>{formatValue(value)}</span>{/if}</div>
38
38
  <meter {value} {min} {max} {low} {high} {optimum}>{formatValue(value)}</meter></div>
39
39
  <style>
40
+ @layer smrt.reset, smrt.structure, smrt.theme;
41
+ @layer smrt.theme {
40
42
  .meter { display: grid; gap: var(--smrt-spacing-2); color: var(--smrt-color-on-surface); }
41
43
  .meter__header { display: flex; justify-content: space-between; font: var(--smrt-typography-label-large-font); }
42
44
  meter { width: 100%; height: .75rem; accent-color: var(--smrt-color-primary); }
45
+ }
43
46
  </style>
@@ -125,24 +125,24 @@ const placementClass = $derived(`modal--${placement}`);
125
125
  onkeydown={handleKeydown}
126
126
  oncancel={handleCancel}
127
127
  aria-label={ariaLabel ?? title}
128
- aria-describedby={ariaDescribedBy}
128
+ aria-describedby={ariaDescribedBy} data-smrt-component="Modal"
129
129
  >
130
130
  <div class="modal__container">
131
131
  {#if header}
132
- <header class="modal__header modal__header--custom">
132
+ <header class="modal__header modal__header--custom" data-smrt-part="header">
133
133
  {@render header()}
134
134
  </header>
135
135
  {:else if title || showClose}
136
- <header class="modal__header">
136
+ <header class="modal__header" data-smrt-part="header">
137
137
  {#if title}
138
- <h2 class="modal__title">{title}</h2>
138
+ <h2 class="modal__title" data-smrt-part="title">{title}</h2>
139
139
  {:else}
140
140
  <span></span>
141
141
  {/if}
142
142
  {#if showClose}
143
143
  <button
144
144
  type="button"
145
- class="modal__close"
145
+ class="modal__close" data-smrt-part="close"
146
146
  onclick={handleClose}
147
147
  aria-label={t(M['ui.modal.close'])}
148
148
  >
@@ -166,14 +166,14 @@ const placementClass = $derived(`modal--${placement}`);
166
166
  </header>
167
167
  {/if}
168
168
 
169
- <div class="modal__body">
169
+ <div class="modal__body" data-smrt-part="body">
170
170
  {#if children}
171
171
  {@render children()}
172
172
  {/if}
173
173
  </div>
174
174
 
175
175
  {#if footer}
176
- <footer class="modal__footer">
176
+ <footer class="modal__footer" data-smrt-part="footer">
177
177
  {@render footer()}
178
178
  </footer>
179
179
  {/if}
@@ -181,6 +181,8 @@ const placementClass = $derived(`modal--${placement}`);
181
181
  </dialog>
182
182
 
183
183
  <style>
184
+ @layer smrt.reset, smrt.structure, smrt.theme;
185
+ @layer smrt.theme {
184
186
  .modal {
185
187
  position: fixed;
186
188
  inset: 0;
@@ -212,7 +214,7 @@ const placementClass = $derived(`modal--${placement}`);
212
214
  flex-direction: column;
213
215
  max-height: calc(100vh - var(--smrt-spacing-8, 2rem));
214
216
  max-width: calc(100vw - var(--smrt-spacing-8, 2rem));
215
- background: var(--smrt-color-surface, #ffffff);
217
+ background: var(--smrt-color-surface);
216
218
  border-radius: var(--smrt-radius-large, 0.75rem);
217
219
  box-shadow: var(--smrt-elevation-3, 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05));
218
220
  overflow: hidden;
@@ -310,7 +312,7 @@ const placementClass = $derived(`modal--${placement}`);
310
312
  justify-content: space-between;
311
313
  gap: var(--smrt-spacing-3, 0.75rem);
312
314
  padding: var(--smrt-spacing-4, 1rem) var(--smrt-spacing-5, 1.25rem);
313
- border-bottom: 1px solid var(--smrt-color-outline-variant, #c4c6cf);
315
+ border-bottom: 1px solid var(--smrt-color-outline-variant);
314
316
  flex-shrink: 0;
315
317
  }
316
318
 
@@ -323,7 +325,7 @@ const placementClass = $derived(`modal--${placement}`);
323
325
  margin: 0;
324
326
  font-size: var(--smrt-typography-headline-small-size, 1.125rem);
325
327
  font-weight: var(--smrt-typography-weight-semibold, 600);
326
- color: var(--smrt-color-on-surface, #1b1b1f);
328
+ color: var(--smrt-color-on-surface);
327
329
  line-height: var(--smrt-typography-headline-small-line-height, 1.4);
328
330
  }
329
331
 
@@ -336,20 +338,20 @@ const placementClass = $derived(`modal--${placement}`);
336
338
  padding: 0;
337
339
  border: none;
338
340
  background: transparent;
339
- border-radius: var(--smrt-radius-full, 9999px);
340
- color: var(--smrt-color-on-surface-variant, #43474e);
341
+ border-radius: var(--smrt-radius-full);
342
+ color: var(--smrt-color-on-surface-variant);
341
343
  cursor: pointer;
342
344
  transition: all var(--smrt-duration-short3, 150ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
343
345
  flex-shrink: 0;
344
346
  }
345
347
 
346
348
  .modal__close:hover {
347
- background: var(--smrt-color-surface-container-highest, #e0e2ec);
348
- color: var(--smrt-color-on-surface, #1b1b1f);
349
+ background: var(--smrt-color-surface-container-highest);
350
+ color: var(--smrt-color-on-surface);
349
351
  }
350
352
 
351
353
  .modal__close:focus-visible {
352
- outline: 2px solid var(--smrt-color-primary, #005ac1);
354
+ outline: 2px solid var(--smrt-color-primary);
353
355
  outline-offset: 2px;
354
356
  }
355
357
 
@@ -358,7 +360,7 @@ const placementClass = $derived(`modal--${placement}`);
358
360
  flex: 1;
359
361
  padding: var(--smrt-spacing-5, 1.25rem);
360
362
  overflow-y: auto;
361
- color: var(--smrt-color-on-surface, #1b1b1f);
363
+ color: var(--smrt-color-on-surface);
362
364
  }
363
365
 
364
366
  /* Footer */
@@ -368,7 +370,7 @@ const placementClass = $derived(`modal--${placement}`);
368
370
  justify-content: flex-end;
369
371
  gap: var(--smrt-spacing-3, 0.75rem);
370
372
  padding: var(--smrt-spacing-4, 1rem) var(--smrt-spacing-5, 1.25rem);
371
- border-top: 1px solid var(--smrt-color-outline-variant, #c4c6cf);
373
+ border-top: 1px solid var(--smrt-color-outline-variant);
372
374
  flex-shrink: 0;
373
375
  }
374
376
 
@@ -394,4 +396,5 @@ const placementClass = $derived(`modal--${placement}`);
394
396
  max-height: 100%;
395
397
  }
396
398
  }
399
+ }
397
400
  </style>