@happyvertical/smrt-ui 0.55.16 → 0.55.18

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 (166) hide show
  1. package/AGENTS.md +14 -0
  2. package/README.md +75 -0
  3. package/dist/components/calendar/Calendar.svelte +59 -56
  4. package/dist/components/calendar/CalendarView.svelte +80 -77
  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 +12 -9
  8. package/dist/components/chat/TypingIndicator.svelte +12 -9
  9. package/dist/components/data/CollectionList.svelte +11 -8
  10. package/dist/components/data/CollectionToolbar.svelte +5 -2
  11. package/dist/components/data/DataTable.svelte +74 -59
  12. package/dist/components/data/ListSortSelect.svelte +8 -5
  13. package/dist/components/data/SortableHeader.svelte +10 -7
  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 +12 -8
  20. package/dist/components/feedback/ConfirmDialog.svelte +13 -10
  21. package/dist/components/feedback/LoadingOverlay.svelte +37 -34
  22. package/dist/components/feedback/Meter.svelte +4 -1
  23. package/dist/components/feedback/Modal.svelte +26 -21
  24. package/dist/components/feedback/PhoneSheet.svelte +6 -3
  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 +18 -15
  29. package/dist/components/feedback/WorkingStrip.svelte +6 -3
  30. package/dist/components/forms/CameraCapture.svelte +8 -5
  31. package/dist/components/forms/Checkbox.svelte +11 -8
  32. package/dist/components/forms/Combobox.svelte +5 -2
  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 +5 -2
  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 +22 -15
  44. package/dist/components/forms/InputGroup.svelte +6 -3
  45. package/dist/components/forms/Listbox.svelte +5 -2
  46. package/dist/components/forms/MultiSelect.svelte +4 -1
  47. package/dist/components/forms/Radio.svelte +9 -6
  48. package/dist/components/forms/RadioGroup.svelte +5 -2
  49. package/dist/components/forms/RangeSlider.svelte +5 -2
  50. package/dist/components/forms/RelationInput.svelte +7 -4
  51. package/dist/components/forms/SearchInput.svelte +7 -4
  52. package/dist/components/forms/SegmentedControl.svelte +6 -3
  53. package/dist/components/forms/Select.svelte +20 -13
  54. package/dist/components/forms/SignaturePad.svelte +8 -5
  55. package/dist/components/forms/Slider.svelte +5 -2
  56. package/dist/components/forms/StagedControlReview.svelte +15 -12
  57. package/dist/components/forms/Switch.svelte +8 -5
  58. package/dist/components/forms/TagsInput.svelte +5 -2
  59. package/dist/components/forms/Textarea.svelte +20 -13
  60. package/dist/components/forms/TimePicker.svelte +7 -2
  61. package/dist/components/forms/Toggle.svelte +14 -11
  62. package/dist/components/forms/ToggleButton.svelte +5 -2
  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 +12 -9
  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 +75 -41
  77. package/dist/components/permissions/PermissionPicker.svelte +5 -2
  78. package/dist/components/roles/RoleBadge.svelte +8 -5
  79. package/dist/components/roles/RoleSelector.svelte +22 -19
  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 +5 -2
  83. package/dist/components/ui/Avatar.svelte +10 -7
  84. package/dist/components/ui/Badge.svelte +6 -2
  85. package/dist/components/ui/Button.svelte +49 -37
  86. package/dist/components/ui/Card.svelte +18 -14
  87. package/dist/components/ui/Chip.svelte +41 -14
  88. package/dist/components/ui/Disclosure.svelte +5 -2
  89. package/dist/components/ui/Dropdown.svelte +33 -25
  90. package/dist/components/ui/IconToggle.svelte +12 -9
  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 +9 -6
  96. package/dist/components/ui/Skeleton.svelte +10 -7
  97. package/dist/components/ui/Tooltip.svelte +13 -9
  98. package/dist/components/ui/Tree.svelte +12 -9
  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 +40 -0
  121. package/dist/themes/README.md +151 -0
  122. package/dist/themes/ThemeProvider.svelte +181 -12
  123. package/dist/themes/ThemeProvider.svelte.d.ts +7 -2
  124. package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
  125. package/dist/themes/components/ColorSchemeToggle.svelte +17 -14
  126. package/dist/themes/components/ThemeSwitcher.svelte +14 -11
  127. package/dist/themes/create-theme.d.ts +22 -1
  128. package/dist/themes/create-theme.d.ts.map +1 -1
  129. package/dist/themes/create-theme.js +100 -9
  130. package/dist/themes/css-generator.d.ts.map +1 -1
  131. package/dist/themes/css-generator.js +20 -20
  132. package/dist/themes/derive.d.ts +31 -0
  133. package/dist/themes/derive.d.ts.map +1 -0
  134. package/dist/themes/derive.js +183 -0
  135. package/dist/themes/glass/index.d.ts.map +1 -1
  136. package/dist/themes/glass/index.js +127 -14
  137. package/dist/themes/happyvertical/index.d.ts.map +1 -1
  138. package/dist/themes/happyvertical/index.js +101 -20
  139. package/dist/themes/index.d.ts +2 -2
  140. package/dist/themes/index.d.ts.map +1 -1
  141. package/dist/themes/index.js +1 -1
  142. package/dist/themes/material/index.d.ts.map +1 -1
  143. package/dist/themes/material/index.js +129 -28
  144. package/dist/themes/required-tokens.generated.json +201 -0
  145. package/dist/themes/shared.d.ts +35 -0
  146. package/dist/themes/shared.d.ts.map +1 -1
  147. package/dist/themes/shared.js +32 -0
  148. package/dist/themes/smrt/index.d.ts +3 -0
  149. package/dist/themes/smrt/index.d.ts.map +1 -1
  150. package/dist/themes/smrt/index.js +108 -26
  151. package/dist/themes/studio/index.d.ts.map +1 -1
  152. package/dist/themes/studio/index.js +116 -40
  153. package/dist/themes/styles/base.css +229 -1
  154. package/dist/themes/styles/glass.css +107 -20
  155. package/dist/themes/styles/happyvertical.css +111 -15
  156. package/dist/themes/styles/material.css +127 -35
  157. package/dist/themes/styles/smrt.css +126 -31
  158. package/dist/themes/styles/studio.css +132 -37
  159. package/dist/themes/theme-script.d.ts +3 -1
  160. package/dist/themes/theme-script.d.ts.map +1 -1
  161. package/dist/themes/theme-script.js +7 -2
  162. package/dist/themes/types.d.ts +118 -6
  163. package/dist/themes/types.d.ts.map +1 -1
  164. package/dist/utils/theme/typography.d.ts +21 -21
  165. package/dist/utils/theme/typography.js +21 -21
  166. package/package.json +8 -2
@@ -97,7 +97,7 @@ const timeText = $derived(
97
97
  class="bubble bubble--{effectiveVariant}"
98
98
  class:bubble--own={effectiveOwn}
99
99
  role={hasHeader ? 'group' : undefined}
100
- aria-label={hasHeader ? groupLabel : undefined}
100
+ aria-label={hasHeader ? groupLabel : undefined} data-smrt-component="MessageBubble"
101
101
  >
102
102
  {#if hasHeader}
103
103
  <div class="bubble__header">
@@ -126,13 +126,15 @@ const timeText = $derived(
126
126
  </div>
127
127
 
128
128
  <style>
129
+ @layer smrt.reset, smrt.structure, smrt.theme;
130
+ @layer smrt.theme {
129
131
  .bubble {
130
132
  display: flex;
131
133
  flex-direction: column;
132
- gap: var(--smrt-spacing-1, 4px);
134
+ gap: var(--smrt-spacing-1);
133
135
  max-width: 75%;
134
- padding: var(--smrt-spacing-3, 12px) var(--smrt-spacing-4, 16px);
135
- border-radius: var(--smrt-radius-large, 12px);
136
+ padding: var(--smrt-spacing-3) var(--smrt-spacing-4);
137
+ border-radius: var(--smrt-radius-large);
136
138
  font-size: var(--smrt-typography-body-medium-size, 0.875rem);
137
139
  line-height: 1.4;
138
140
  word-break: break-word;
@@ -140,39 +142,39 @@ const timeText = $derived(
140
142
 
141
143
  /* default — a peer message; `own` is the current viewer's message. */
142
144
  .bubble--default {
143
- background: var(--smrt-color-surface-container, #f3f4f6);
144
- color: var(--smrt-color-on-surface, #1b1b1f);
145
- border-bottom-left-radius: var(--smrt-radius-small, 4px);
145
+ background: var(--smrt-color-surface-container);
146
+ color: var(--smrt-color-on-surface);
147
+ border-bottom-left-radius: var(--smrt-radius-small);
146
148
  }
147
149
  .bubble--default.bubble--own {
148
- background: var(--smrt-color-primary, #005ac1);
149
- color: var(--smrt-color-on-primary, #ffffff);
150
- border-bottom-right-radius: var(--smrt-radius-small, 4px);
151
- border-bottom-left-radius: var(--smrt-radius-large, 12px);
150
+ background: var(--smrt-color-primary);
151
+ color: var(--smrt-color-on-primary);
152
+ border-bottom-right-radius: var(--smrt-radius-small);
153
+ border-bottom-left-radius: var(--smrt-radius-large);
152
154
  }
153
155
 
154
156
  /* agent — assistant message, accented on the leading edge. */
155
157
  .bubble--agent {
156
- background: var(--smrt-color-tertiary-container, #ffd8e4);
157
- color: var(--smrt-color-on-tertiary-container, #31111d);
158
- border-bottom-left-radius: var(--smrt-radius-small, 4px);
159
- border-left: 3px solid var(--smrt-color-tertiary, #7d5260);
158
+ background: var(--smrt-color-tertiary-container);
159
+ color: var(--smrt-color-on-tertiary-container);
160
+ border-bottom-left-radius: var(--smrt-radius-small);
161
+ border-left: 3px solid var(--smrt-color-tertiary);
160
162
  }
161
163
  .bubble--agent.bubble--own {
162
164
  border-left: none;
163
- border-right: 3px solid var(--smrt-color-tertiary, #7d5260);
164
- border-bottom-right-radius: var(--smrt-radius-small, 4px);
165
- border-bottom-left-radius: var(--smrt-radius-large, 12px);
165
+ border-right: 3px solid var(--smrt-color-tertiary);
166
+ border-bottom-right-radius: var(--smrt-radius-small);
167
+ border-bottom-left-radius: var(--smrt-radius-large);
166
168
  }
167
169
 
168
170
  /* system — centered notice. */
169
171
  .bubble--system {
170
172
  max-width: 100%;
171
173
  background: transparent;
172
- color: var(--smrt-color-on-surface-variant, #43474e);
174
+ color: var(--smrt-color-on-surface-variant);
173
175
  text-align: center;
174
176
  font-size: var(--smrt-typography-body-small-size, 0.75rem);
175
- padding: var(--smrt-spacing-2, 6px) var(--smrt-spacing-4, 16px);
177
+ padding: var(--smrt-spacing-2) var(--smrt-spacing-4);
176
178
  border-radius: 0;
177
179
  align-self: center;
178
180
  }
@@ -186,7 +188,7 @@ const timeText = $derived(
186
188
  .bubble__header {
187
189
  display: flex;
188
190
  align-items: baseline;
189
- gap: var(--smrt-spacing-2, 8px);
191
+ gap: var(--smrt-spacing-2);
190
192
  }
191
193
  .bubble__author {
192
194
  font-weight: var(--smrt-typography-weight-semibold, 600);
@@ -194,7 +196,7 @@ const timeText = $derived(
194
196
  }
195
197
  .bubble__time {
196
198
  font-size: var(--smrt-typography-label-small-size, 0.6875rem);
197
- color: var(--smrt-color-on-surface-variant, #49454f);
199
+ color: var(--smrt-color-on-surface-variant);
198
200
  opacity: 0.8;
199
201
  }
200
202
 
@@ -211,6 +213,7 @@ const timeText = $derived(
211
213
  .bubble__actions {
212
214
  display: flex;
213
215
  flex-wrap: wrap;
214
- gap: var(--smrt-spacing-1, 4px);
216
+ gap: var(--smrt-spacing-1);
215
217
  }
218
+ }
216
219
  </style>
@@ -61,7 +61,7 @@ function nameFor(emoji: string): string {
61
61
  </script>
62
62
 
63
63
  {#if isOpen}
64
- <div class="reactions" role="group" aria-label={groupLabel}>
64
+ <div class="reactions" role="group" aria-label={groupLabel} data-smrt-component="ReactionPicker">
65
65
  {#each emojis as emoji (emoji)}
66
66
  <button
67
67
  type="button"
@@ -76,14 +76,16 @@ function nameFor(emoji: string): string {
76
76
  {/if}
77
77
 
78
78
  <style>
79
+ @layer smrt.reset, smrt.structure, smrt.theme;
80
+ @layer smrt.theme {
79
81
  .reactions {
80
82
  display: inline-flex;
81
83
  flex-wrap: wrap;
82
- gap: var(--smrt-spacing-1, 4px);
83
- padding: var(--smrt-spacing-1, 4px);
84
+ gap: var(--smrt-spacing-1);
85
+ padding: var(--smrt-spacing-1);
84
86
  max-width: 16rem;
85
- border-radius: var(--smrt-radius-large, 12px);
86
- background: var(--smrt-color-surface-container, #f3edf7);
87
+ border-radius: var(--smrt-radius-large);
88
+ background: var(--smrt-color-surface-container);
87
89
  }
88
90
 
89
91
  .reactions__btn {
@@ -94,7 +96,7 @@ function nameFor(emoji: string): string {
94
96
  width: 2rem;
95
97
  height: 2rem;
96
98
  border: none;
97
- border-radius: var(--smrt-radius-full, 9999px);
99
+ border-radius: var(--smrt-radius-full);
98
100
  background: none;
99
101
  font-size: var(--smrt-typography-title-medium-size, 1.1rem);
100
102
  line-height: 1;
@@ -102,12 +104,12 @@ function nameFor(emoji: string): string {
102
104
  transition: transform 0.1s ease, background 0.1s ease;
103
105
  }
104
106
  .reactions__btn:hover {
105
- background: var(--smrt-color-surface-container-highest, #e6e0e9);
107
+ background: var(--smrt-color-surface-container-highest);
106
108
  transform: scale(1.15);
107
109
  }
108
110
  .reactions__btn:focus-visible {
109
- outline: 2px solid var(--smrt-color-primary);
110
- outline-offset: 1px;
111
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
112
+ outline-offset: var(--smrt-focus-ring-offset);
111
113
  }
112
114
 
113
115
  @media (prefers-reduced-motion: reduce) {
@@ -118,4 +120,5 @@ function nameFor(emoji: string): string {
118
120
  transform: none;
119
121
  }
120
122
  }
123
+ }
121
124
  </style>
@@ -39,7 +39,7 @@ const text = $derived.by(() => {
39
39
  </script>
40
40
 
41
41
  {#if show}
42
- <div class="typing" role="status" aria-live="polite">
42
+ <div class="typing" role="status" aria-live="polite" data-smrt-component="TypingIndicator">
43
43
  <span class="typing__text">{text}</span>
44
44
  <span class="typing__dots" aria-hidden="true">
45
45
  <span class="typing__dot"></span>
@@ -50,32 +50,34 @@ const text = $derived.by(() => {
50
50
  {/if}
51
51
 
52
52
  <style>
53
+ @layer smrt.reset, smrt.structure, smrt.theme;
54
+ @layer smrt.theme {
53
55
  .typing {
54
56
  display: inline-flex;
55
57
  align-items: center;
56
- gap: var(--smrt-spacing-2, 8px);
57
- padding: var(--smrt-spacing-2, 8px) var(--smrt-spacing-3, 12px);
58
- border-radius: var(--smrt-radius-large, 12px);
59
- background: var(--smrt-color-surface-container, #f3edf7);
58
+ gap: var(--smrt-spacing-2);
59
+ padding: var(--smrt-spacing-2) var(--smrt-spacing-3);
60
+ border-radius: var(--smrt-radius-large);
61
+ background: var(--smrt-color-surface-container);
60
62
  width: fit-content;
61
63
  }
62
64
 
63
65
  .typing__text {
64
66
  font-size: var(--smrt-typography-body-small-size, 0.75rem);
65
- color: var(--smrt-color-on-surface-variant, #49454f);
67
+ color: var(--smrt-color-on-surface-variant);
66
68
  white-space: nowrap;
67
69
  }
68
70
 
69
71
  .typing__dots {
70
72
  display: inline-flex;
71
- gap: var(--smrt-spacing-1, 4px);
73
+ gap: var(--smrt-spacing-1);
72
74
  }
73
75
 
74
76
  .typing__dot {
75
77
  width: 0.5rem;
76
78
  height: 0.5rem;
77
- border-radius: var(--smrt-radius-full, 9999px);
78
- background: var(--smrt-color-on-surface-variant, #49454f);
79
+ border-radius: var(--smrt-radius-full);
80
+ background: var(--smrt-color-on-surface-variant);
79
81
  opacity: 0.5;
80
82
  animation: smrt-typing-bounce 1.2s ease-in-out infinite;
81
83
  }
@@ -104,4 +106,5 @@ const text = $derived.by(() => {
104
106
  animation: none;
105
107
  }
106
108
  }
109
+ }
107
110
  </style>
@@ -81,11 +81,11 @@ function toggle(key: string | number) {
81
81
  </script>
82
82
 
83
83
  {#if loading}
84
- <div class="loading" role="status"><span class="spinner" aria-hidden="true"></span>Loading…</div>
84
+ <div class="loading" role="status" data-smrt-component="CollectionList"><span class="spinner" aria-hidden="true"></span>Loading…</div>
85
85
  {:else if items.length === 0}
86
- <div class="empty">{#if empty}{@render empty()}{:else}No items available{/if}</div>
86
+ <div class="empty" data-smrt-component="CollectionList">{#if empty}{@render empty()}{:else}No items available{/if}</div>
87
87
  {:else}
88
- <ul class="collection collection--{layout} {className}">
88
+ <ul class="collection collection--{layout} {className}" data-smrt-component="CollectionList">
89
89
  {#each items as entry, index (keyOf(entry, index))}
90
90
  {@const key = keyOf(entry, index)}
91
91
  {@const isSelected = selected.has(key)}
@@ -108,6 +108,8 @@ function toggle(key: string | number) {
108
108
  {/if}
109
109
 
110
110
  <style>
111
+ @layer smrt.reset, smrt.structure, smrt.theme;
112
+ @layer smrt.theme {
111
113
  .collection { display: grid; gap: var(--smrt-spacing-2); margin: 0; padding: 0; list-style: none; }
112
114
  .collection--grid { grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr)); }
113
115
  li { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--smrt-spacing-3); min-width: 0; padding: var(--smrt-spacing-3); border: var(--smrt-card-border, 1px solid var(--smrt-color-outline-variant)); border-radius: var(--smrt-radius-medium); background: var(--smrt-card-background, var(--smrt-color-surface)); color: var(--smrt-color-on-surface); }
@@ -117,22 +119,23 @@ function toggle(key: string | number) {
117
119
  input { width: 1.125rem; height: 1.125rem; accent-color: var(--smrt-color-primary); }
118
120
  .main { display: grid; min-width: 0; gap: var(--smrt-spacing-1); padding: 0; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; }
119
121
  button.main { width: 100%; cursor: pointer; }
120
- button.main:focus-visible { outline: 2px solid var(--smrt-color-primary); outline-offset: 3px; }
122
+ button.main:focus-visible { outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color); outline-offset: var(--smrt-focus-ring-offset); }
121
123
  .main strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: var(--smrt-typography-title-small-font); }
122
124
  .main span { color: var(--smrt-color-on-surface-variant); }
123
125
  .actions { position: relative; z-index: 1; display: flex; gap: var(--smrt-spacing-1); }
124
- .collection--divided { --collection-divider: color-mix(in srgb, var(--smrt-color-outline-variant) 55%, transparent); gap: 0; }
126
+ .collection--divided { --smrt-collection-list-divider: color-mix(in srgb, var(--smrt-color-outline-variant) 55%, transparent); gap: 0; }
125
127
  .collection--divided li { padding-inline: 0; border: none; border-radius: 0; background: transparent; }
126
- .collection--divided li + li { border-block-start: 1px solid var(--collection-divider); }
127
- .collection--divided li.selected { border-color: var(--collection-divider); background: transparent; }
128
+ .collection--divided li + li { border-block-start: 1px solid var(--smrt-collection-list-divider); }
129
+ .collection--divided li.selected { border-color: var(--smrt-collection-list-divider); background: transparent; }
128
130
  .collection--gallery { grid-template-columns: repeat(auto-fill, minmax(min(11rem, 100%), 1fr)); }
129
131
  .collection--gallery li { display: block; padding: 0; }
130
132
  .collection--gallery .main { gap: 0; }
131
- .collection--gallery .select, .collection--gallery .actions { position: absolute; top: var(--smrt-spacing-1); z-index: 2; min-width: 2.75rem; min-height: 2.75rem; align-items: center; justify-content: center; border-radius: var(--smrt-radius-full, 999px); background: color-mix(in srgb, var(--smrt-color-surface) 82%, transparent); }
133
+ .collection--gallery .select, .collection--gallery .actions { position: absolute; top: var(--smrt-spacing-1); z-index: 2; min-width: 2.75rem; min-height: 2.75rem; align-items: center; justify-content: center; border-radius: var(--smrt-radius-full); background: color-mix(in srgb, var(--smrt-color-surface) 82%, transparent); }
132
134
  .collection--gallery .select { left: var(--smrt-spacing-1); }
133
135
  .collection--gallery .actions { right: var(--smrt-spacing-1); }
134
136
  .loading, .empty { display: flex; min-height: 8rem; align-items: center; justify-content: center; gap: var(--smrt-spacing-2); color: var(--smrt-color-on-surface-variant); }
135
137
  .spinner { width: 1rem; height: 1rem; border: 2px solid var(--smrt-color-outline-variant); border-top-color: var(--smrt-color-primary); border-radius: 50%; animation: spin .8s linear infinite; }
136
138
  @keyframes spin { to { transform: rotate(360deg); } }
137
139
  @media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 1.6s; } }
140
+ }
138
141
  </style>
@@ -259,7 +259,7 @@ onDestroy(() => surfaceRegistration?.cleanup());
259
259
  class="toolbar {className}"
260
260
  class:toolbar--highlighted={surfaceHighlighted}
261
261
  role="search"
262
- tabindex="-1"
262
+ tabindex="-1" data-smrt-component="CollectionToolbar"
263
263
  >
264
264
  <div class="search">
265
265
  <Input type="search" name="collection-search" aria-label={searchLabel} placeholder={searchPlaceholder} value={controllerState?.search ?? search} oninput={(event) => changeSearch(event.currentTarget.value)} />
@@ -275,11 +275,14 @@ onDestroy(() => surfaceRegistration?.cleanup());
275
275
  </div>
276
276
 
277
277
  <style>
278
+ @layer smrt.reset, smrt.structure, smrt.theme;
279
+ @layer smrt.theme {
278
280
  .toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--smrt-spacing-2); padding: var(--smrt-spacing-2) 0; color: var(--smrt-color-on-surface); }
279
- .toolbar--highlighted { outline: 2px solid var(--smrt-color-primary, #2563eb); outline-offset: 3px; }
281
+ .toolbar--highlighted { outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color); outline-offset: var(--smrt-focus-ring-offset); }
280
282
  .search { flex: 1 1 14rem; max-width: 24rem; }
281
283
  .filters, .actions, .bulk { display: flex; align-items: center; gap: var(--smrt-spacing-2); }
282
284
  .bulk { padding: var(--smrt-spacing-1) var(--smrt-spacing-2); border-radius: var(--smrt-radius-small); background: var(--smrt-color-secondary-container); color: var(--smrt-color-on-secondary-container); }
283
285
  .count { color: var(--smrt-color-on-surface-variant); font: var(--smrt-typography-label-medium-font); }
284
286
  .spacer { flex: 1; }
287
+ }
285
288
  </style>
@@ -1444,7 +1444,7 @@ $effect(() => {
1444
1444
  });
1445
1445
  </script>
1446
1446
 
1447
- {#if toolbar}<div class="data-table-toolbar">{@render toolbar()}</div>{/if}
1447
+ {#if toolbar}<div class="data-table-toolbar" data-smrt-component="DataTable">{@render toolbar()}</div>{/if}
1448
1448
  <!-- svelte-ignore a11y_no_noninteractive_tabindex: the region provides horizontal or virtual keyboard scrolling. -->
1449
1449
  <div
1450
1450
  bind:this={tableContainer}
@@ -1473,7 +1473,7 @@ $effect(() => {
1473
1473
  onkeydown={(event) => {
1474
1474
  handleVirtualizationKeydown(event);
1475
1475
  if (!event.defaultPrevented) handleOverflowKeydown(event);
1476
- }}
1476
+ }} data-smrt-component="DataTable"
1477
1477
  >
1478
1478
  <table role={cardsRole('table')}
1479
1479
  class="data-table {sizeClasses[size]}"
@@ -1486,7 +1486,7 @@ $effect(() => {
1486
1486
  aria-rowcount={virtualizationWindow.enabled
1487
1487
  ? virtualRowCount + headerRowCount + structuralRowCount
1488
1488
  : undefined}
1489
- style={`--data-table-caption-height: ${virtualCaptionHeight}px`}
1489
+ style={`--smrt-data-table-caption-height: ${virtualCaptionHeight}px`}
1490
1490
  >
1491
1491
  {#if caption}
1492
1492
  <caption bind:this={tableCaption} class="data-table__caption">{caption}</caption>
@@ -1913,7 +1913,7 @@ $effect(() => {
1913
1913
  {/if}
1914
1914
  </div>
1915
1915
  {#if hasHorizontalOverflow}
1916
- <div class="data-table__overflow-cue" aria-hidden="true">
1916
+ <div class="data-table__overflow-cue" aria-hidden="true" data-smrt-component="DataTable">
1917
1917
  {#if canScrollLeft}<span>← {t(M['ui.data_table.more_columns'])}</span>{/if}
1918
1918
  {#if canScrollRight}<span>{t(M['ui.data_table.more_columns'])} →</span>{/if}
1919
1919
  </div>
@@ -1921,6 +1921,8 @@ $effect(() => {
1921
1921
  {#if tableState.pageSize && totalPages && totalPages > 1}<Pagination currentPage={tableState.page} {totalPages} onPageChange={handlePageChange} aria-label={t(M['ui.data_table.pagination'])} />{/if}
1922
1922
 
1923
1923
  <style>
1924
+ @layer smrt.reset, smrt.structure, smrt.theme;
1925
+ @layer smrt.theme {
1924
1926
  .data-table-container {
1925
1927
  position: relative;
1926
1928
  width: 100%;
@@ -1928,22 +1930,22 @@ $effect(() => {
1928
1930
  }
1929
1931
 
1930
1932
  .data-table-container--overflowing:focus-visible {
1931
- outline: 2px solid var(--smrt-color-primary, #3b82f6);
1932
- outline-offset: 2px;
1933
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
1934
+ outline-offset: var(--smrt-focus-ring-offset);
1933
1935
  }
1934
1936
 
1935
1937
  .data-table-container--highlighted {
1936
- outline: 2px solid var(--smrt-color-primary, #2563eb);
1937
- outline-offset: 3px;
1938
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
1939
+ outline-offset: var(--smrt-focus-ring-offset);
1938
1940
  }
1939
1941
 
1940
1942
  .data-table__overflow-cue {
1941
1943
  display: flex;
1942
1944
  justify-content: space-between;
1943
1945
  padding: var(--smrt-spacing-2, 0.5rem) var(--smrt-spacing-3, 0.75rem);
1944
- border-top: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
1945
- background: var(--smrt-color-surface-container-low, #f9fafb);
1946
- color: var(--smrt-color-on-surface-variant, #6b7280);
1946
+ border-top: var(--smrt-hairline);
1947
+ background: var(--smrt-color-surface-container-low);
1948
+ color: var(--smrt-color-on-surface-variant);
1947
1949
  font-size: var(--smrt-typography-label-small-size, 0.75rem);
1948
1950
  font-weight: var(--smrt-typography-weight-medium, 500);
1949
1951
  pointer-events: none;
@@ -1971,7 +1973,7 @@ $effect(() => {
1971
1973
 
1972
1974
  .data-table-container--sticky.data-table-container--virtualized .data-table__head {
1973
1975
  position: sticky;
1974
- top: var(--data-table-caption-height, 0px);
1976
+ top: var(--smrt-data-table-caption-height, 0px);
1975
1977
  z-index: 1;
1976
1978
  }
1977
1979
 
@@ -1981,21 +1983,21 @@ $effect(() => {
1981
1983
  border-spacing: 0;
1982
1984
  font-family: var(--smrt-font-family, inherit);
1983
1985
  font-size: var(--smrt-typography-body-medium-size, 0.875rem);
1984
- color: var(--smrt-color-on-surface, #111827);
1985
- background: var(--smrt-color-surface, #ffffff);
1986
+ color: var(--smrt-color-on-surface);
1987
+ background: var(--smrt-surface-panel);
1986
1988
  }
1987
1989
 
1988
1990
  .data-table__caption {
1989
1991
  padding: var(--smrt-spacing-3, 0.75rem);
1990
1992
  font-weight: var(--smrt-typography-weight-medium, 500);
1991
1993
  text-align: left;
1992
- color: var(--smrt-color-on-surface-variant, #6b7280);
1994
+ color: var(--smrt-color-on-surface-variant);
1993
1995
  caption-side: top;
1994
1996
  }
1995
1997
 
1996
1998
  /* Header */
1997
1999
  .data-table__head {
1998
- background: var(--smrt-color-surface-container, #f3f4f6);
2000
+ background: var(--smrt-surface-sunken);
1999
2001
  }
2000
2002
 
2001
2003
  .data-table-container--sticky .data-table__head {
@@ -2005,7 +2007,7 @@ $effect(() => {
2005
2007
  }
2006
2008
 
2007
2009
  .data-table__row--header {
2008
- border-bottom: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
2010
+ border-bottom: var(--smrt-hairline);
2009
2011
  }
2010
2012
 
2011
2013
  .data-table__cell--header {
@@ -2014,7 +2016,7 @@ $effect(() => {
2014
2016
  font-weight: var(--smrt-typography-weight-semibold, 600);
2015
2017
  text-align: left;
2016
2018
  white-space: nowrap;
2017
- color: var(--smrt-color-on-surface, #111827);
2019
+ color: var(--smrt-color-on-surface);
2018
2020
  }
2019
2021
 
2020
2022
  .data-table__cell--sortable {
@@ -2042,7 +2044,7 @@ $effect(() => {
2042
2044
  }
2043
2045
 
2044
2046
  .data-table__cell--header-group {
2045
- color: var(--smrt-color-on-surface-variant, #6b7280);
2047
+ color: var(--smrt-color-on-surface-variant);
2046
2048
  font: var(--smrt-typography-label-medium-font);
2047
2049
  letter-spacing: 0.02em;
2048
2050
  }
@@ -2065,17 +2067,17 @@ $effect(() => {
2065
2067
  right: 0.3rem;
2066
2068
  width: 1px;
2067
2069
  height: 60%;
2068
- background: var(--smrt-color-outline, #9ca3af);
2070
+ background: var(--smrt-color-outline);
2069
2071
  content: '';
2070
2072
  }
2071
2073
 
2072
2074
  .data-table__resize-handle:focus-visible {
2073
- outline: 2px solid var(--smrt-color-primary, #3b82f6);
2074
- outline-offset: -2px;
2075
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
2076
+ outline-offset: calc(var(--smrt-focus-ring-width) * -1);
2075
2077
  }
2076
2078
 
2077
2079
  .data-table__sort-button:hover {
2078
- color: var(--smrt-color-primary, #3b82f6);
2080
+ color: var(--smrt-color-primary);
2079
2081
  }
2080
2082
 
2081
2083
  .data-table__sort-icon {
@@ -2085,16 +2087,16 @@ $effect(() => {
2085
2087
 
2086
2088
  .data-table__cell--sorted .data-table__sort-icon {
2087
2089
  opacity: 1;
2088
- color: var(--smrt-color-primary, #3b82f6);
2090
+ color: var(--smrt-color-primary);
2089
2091
  }
2090
2092
 
2091
2093
  /* Body */
2092
2094
  .data-table__body {
2093
- background: var(--smrt-color-surface, #ffffff);
2095
+ background: var(--smrt-surface-panel);
2094
2096
  }
2095
2097
 
2096
2098
  .data-table__row {
2097
- border-bottom: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
2099
+ border-bottom: var(--smrt-hairline);
2098
2100
  transition: background-color var(--smrt-duration-fast, 150ms) var(--smrt-easing-standard, ease);
2099
2101
  }
2100
2102
 
@@ -2103,17 +2105,25 @@ $effect(() => {
2103
2105
  border: 0;
2104
2106
  }
2105
2107
 
2106
- .data-table--hoverable .data-table__row:hover:not(.data-table__row--loading):not(.data-table__row--empty) {
2107
- background: var(--smrt-color-surface-container-low, #f9fafb);
2108
+ .data-table--hoverable .data-table__row:hover:not(.data-table__row--loading):not(.data-table__row--empty):not(.data-table__row--selected) {
2109
+ background: color-mix(
2110
+ in srgb,
2111
+ var(--smrt-color-on-surface) calc(var(--smrt-state-hover) * 100%),
2112
+ var(--smrt-surface-panel)
2113
+ );
2108
2114
  }
2109
2115
 
2110
2116
  .data-table__row--selected {
2111
- background: var(--smrt-color-primary-container, #dbeafe) !important;
2117
+ background: color-mix(
2118
+ in srgb,
2119
+ var(--smrt-color-primary) calc(var(--smrt-state-selected) * 100%),
2120
+ var(--smrt-surface-panel)
2121
+ );
2112
2122
  }
2113
2123
 
2114
- .data-table--striped:not(.data-table--virtualized) .data-table__row:nth-child(even),
2115
- .data-table__row--striped {
2116
- background: var(--smrt-color-surface-container-lowest, #fafafa);
2124
+ .data-table--striped:not(.data-table--virtualized) .data-table__row:nth-child(even):not(.data-table__row--selected),
2125
+ .data-table__row--striped:not(.data-table__row--selected) {
2126
+ background: var(--smrt-surface-sunken);
2117
2127
  }
2118
2128
 
2119
2129
  .data-table__row--interactive {
@@ -2121,13 +2131,13 @@ $effect(() => {
2121
2131
  }
2122
2132
 
2123
2133
  .data-table__row--interactive:focus-visible {
2124
- outline: 2px solid var(--smrt-color-primary, #3b82f6);
2125
- outline-offset: -2px;
2134
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
2135
+ outline-offset: calc(var(--smrt-focus-ring-width) * -1);
2126
2136
  }
2127
2137
 
2128
2138
  .data-table-container--virtualized .data-table__row:focus-visible {
2129
- outline: 2px solid var(--smrt-color-primary, #3b82f6);
2130
- outline-offset: -2px;
2139
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
2140
+ outline-offset: calc(var(--smrt-focus-ring-width) * -1);
2131
2141
  }
2132
2142
 
2133
2143
  .data-table__cell {
@@ -2139,18 +2149,22 @@ $effect(() => {
2139
2149
  .data-table__cell--pinned-end {
2140
2150
  position: sticky;
2141
2151
  z-index: 1;
2142
- background: var(--smrt-color-surface, #ffffff);
2152
+ background: var(--smrt-surface-panel);
2143
2153
  }
2144
2154
 
2145
2155
  .data-table__cell--header.data-table__cell--pinned-start,
2146
2156
  .data-table__cell--header.data-table__cell--pinned-end {
2147
2157
  z-index: 3;
2148
- background: var(--smrt-color-surface-container, #f3f4f6);
2158
+ background: var(--smrt-surface-sunken);
2149
2159
  }
2150
2160
 
2151
2161
  .data-table__row--selected .data-table__cell--pinned-start,
2152
2162
  .data-table__row--selected .data-table__cell--pinned-end {
2153
- background: var(--smrt-color-primary-container, #dbeafe);
2163
+ background: color-mix(
2164
+ in srgb,
2165
+ var(--smrt-color-primary) calc(var(--smrt-state-selected) * 100%),
2166
+ var(--smrt-surface-panel)
2167
+ );
2154
2168
  }
2155
2169
 
2156
2170
  .data-table__cell--checkbox {
@@ -2159,19 +2173,19 @@ $effect(() => {
2159
2173
  }
2160
2174
 
2161
2175
  .data-table__cell--expand { width: 2.75rem; text-align: center; }
2162
- .data-table__expand-button { width: 1.75rem; height: 1.75rem; border: 1px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-full); background: transparent; color: var(--smrt-color-on-surface); cursor: pointer; }
2163
- .data-table__expand-button:focus-visible { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; }
2164
- .data-table__cell--expanded { padding: var(--smrt-spacing-4); background: var(--smrt-color-surface-container-low); }
2165
- .data-table__footer { border-top: 2px solid var(--smrt-color-outline-variant); font-weight: var(--smrt-typography-weight-medium); }
2166
- .data-table__row--structural { background: var(--smrt-color-surface-container-low, #f9fafb); }
2167
- .data-table__row--footer { border-top: 2px solid var(--smrt-color-outline-variant); }
2176
+ .data-table__expand-button { width: 1.75rem; height: 1.75rem; border: var(--smrt-hairline-strong); border-radius: var(--smrt-radius-full); background: transparent; color: var(--smrt-color-on-surface); cursor: pointer; }
2177
+ .data-table__expand-button:focus-visible { outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color); outline-offset: var(--smrt-focus-ring-offset); }
2178
+ .data-table__cell--expanded { padding: var(--smrt-spacing-4); background: var(--smrt-surface-sunken); }
2179
+ .data-table__footer { border-top: var(--smrt-hairline-strong); font-weight: var(--smrt-typography-weight-medium); }
2180
+ .data-table__row--structural { background: var(--smrt-surface-sunken); }
2181
+ .data-table__row--footer { border-top: var(--smrt-hairline-strong); }
2168
2182
  .data-table__cell--structural-label { font-weight: var(--smrt-typography-weight-semibold, 600); }
2169
2183
 
2170
2184
  .data-table__checkbox {
2171
2185
  width: 18px;
2172
2186
  height: 18px;
2173
2187
  cursor: pointer;
2174
- accent-color: var(--smrt-color-primary, #3b82f6);
2188
+ accent-color: var(--smrt-color-primary);
2175
2189
  }
2176
2190
 
2177
2191
  /* Loading */
@@ -2187,15 +2201,15 @@ $effect(() => {
2187
2201
  align-items: center;
2188
2202
  justify-content: center;
2189
2203
  gap: var(--smrt-spacing-2, 0.5rem);
2190
- color: var(--smrt-color-on-surface-variant, #6b7280);
2204
+ color: var(--smrt-color-on-surface-variant);
2191
2205
  }
2192
2206
 
2193
2207
  .data-table__spinner {
2194
2208
  width: 20px;
2195
2209
  height: 20px;
2196
- border: 2px solid var(--smrt-color-outline-variant, #e5e7eb);
2197
- border-top-color: var(--smrt-color-primary, #3b82f6);
2198
- border-radius: var(--smrt-radius-full, 9999px);
2210
+ border: 2px solid var(--smrt-color-outline-variant);
2211
+ border-top-color: var(--smrt-color-primary);
2212
+ border-radius: var(--smrt-radius-full);
2199
2213
  animation: spin 0.8s linear infinite;
2200
2214
  }
2201
2215
 
@@ -2206,7 +2220,7 @@ $effect(() => {
2206
2220
  }
2207
2221
 
2208
2222
  .data-table__empty-state {
2209
- color: var(--smrt-color-on-surface-variant, #6b7280);
2223
+ color: var(--smrt-color-on-surface-variant);
2210
2224
  }
2211
2225
 
2212
2226
  .data-table__error-state,
@@ -2216,17 +2230,17 @@ $effect(() => {
2216
2230
  justify-content: center;
2217
2231
  flex-wrap: wrap;
2218
2232
  gap: var(--smrt-spacing-3, 0.75rem);
2219
- color: var(--smrt-color-on-surface-variant, #6b7280);
2233
+ color: var(--smrt-color-on-surface-variant);
2220
2234
  }
2221
2235
 
2222
2236
  .data-table__error-state,
2223
2237
  .data-table__async-status--error {
2224
- color: var(--smrt-color-error, #b3261e);
2238
+ color: var(--smrt-color-error);
2225
2239
  }
2226
2240
 
2227
2241
  .data-table__async-status {
2228
2242
  padding: var(--smrt-spacing-3, 0.75rem);
2229
- border-top: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
2243
+ border-top: var(--smrt-hairline);
2230
2244
  font: var(--smrt-typography-body-small-font);
2231
2245
  }
2232
2246
 
@@ -2241,8 +2255,8 @@ $effect(() => {
2241
2255
  }
2242
2256
 
2243
2257
  .data-table__retry-button:focus-visible {
2244
- outline: 2px solid var(--smrt-color-primary, #3b82f6);
2245
- outline-offset: 2px;
2258
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
2259
+ outline-offset: var(--smrt-focus-ring-offset);
2246
2260
  }
2247
2261
 
2248
2262
  /* Size variants */
@@ -2308,13 +2322,13 @@ $effect(() => {
2308
2322
  display: block;
2309
2323
  font-size: var(--smrt-typography-label-small-size, 0.75rem);
2310
2324
  font-weight: 600;
2311
- color: var(--smrt-color-on-surface-variant, #4b5563);
2325
+ color: var(--smrt-color-on-surface-variant);
2312
2326
  }
2313
2327
  .data-table-container--phone-cards .data-table__row {
2314
2328
  display: grid;
2315
2329
  gap: var(--smrt-spacing-1, 0.35rem);
2316
2330
  padding: var(--smrt-spacing-3, 0.85rem) var(--smrt-spacing-4, 1rem);
2317
- border-bottom: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
2331
+ border-bottom: var(--smrt-hairline);
2318
2332
  }
2319
2333
  .data-table-container--phone-cards .data-table__cell {
2320
2334
  display: block;
@@ -2331,10 +2345,11 @@ $effect(() => {
2331
2345
  animation: none;
2332
2346
  }
2333
2347
  }
2334
- .data-table-container[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min, 48px); }
2348
+ .data-table-container[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min); }
2335
2349
  .data-table-container[data-density='comfortable'] { --smrt-control-target-min: 0px; }
2336
2350
  .data-table__sort-button { min-height: var(--smrt-control-target-min, 0px); min-width: var(--smrt-control-target-min, 0px); }
2337
2351
  .data-table-container--narrow .data-table { table-layout: fixed; }
2338
2352
  .data-table-container--narrow .data-table__cell { white-space: normal; overflow-wrap: anywhere; }
2339
2353
  .data-table-container--narrow .data-table__sort-button { max-width: 100%; text-align: left; white-space: normal; overflow-wrap: anywhere; }
2354
+ }
2340
2355
  </style>