@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
@@ -141,10 +141,12 @@ export function getElement(): HTMLTextAreaElement | null {
141
141
  data-smrt-form={controlInteraction?.formId}
142
142
  data-smrt-subject-type={resolvedInteraction === false ? undefined : resolvedInteraction.subject?.type}
143
143
  data-smrt-subject-id={resolvedInteraction === false ? undefined : resolvedInteraction.subject?.id}
144
- {...rest}
144
+ {...rest} data-smrt-component="Textarea"
145
145
  ></textarea>
146
146
 
147
147
  <style>
148
+ @layer smrt.reset, smrt.structure, smrt.theme;
149
+ @layer smrt.theme {
148
150
  .textarea {
149
151
  box-sizing: border-box;
150
152
  display: block;
@@ -152,9 +154,9 @@ export function getElement(): HTMLTextAreaElement | null {
152
154
  padding: 0.5rem 0.75rem;
153
155
  font-size: var(--smrt-typography-body-medium-size, 0.875rem);
154
156
  line-height: var(--smrt-typography-body-medium-line-height, 1.5);
155
- color: var(--smrt-color-on-surface, #1f2937);
156
- background-color: var(--smrt-color-surface, #fff);
157
- border: 1px solid var(--smrt-color-outline, #6b7280);
157
+ color: var(--smrt-color-on-surface);
158
+ background-color: var(--smrt-color-surface);
159
+ border: 1px solid var(--smrt-color-outline);
158
160
  border-radius: 0.375rem;
159
161
  resize: vertical;
160
162
  min-height: 80px;
@@ -165,23 +167,23 @@ export function getElement(): HTMLTextAreaElement | null {
165
167
 
166
168
  .textarea:focus {
167
169
  outline: none;
168
- border-color: var(--smrt-color-primary, #005ac1);
169
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary, #005ac1) 10%, transparent);
170
+ border-color: var(--smrt-color-primary);
171
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary) 10%, transparent);
170
172
  }
171
173
 
172
174
  .textarea[data-smrt-highlighted='true'] {
173
- outline: 3px solid var(--smrt-color-tertiary, #7d5260);
175
+ outline: 3px solid var(--smrt-color-tertiary);
174
176
  outline-offset: 3px;
175
177
  }
176
178
 
177
179
  .textarea:disabled {
178
- background-color: var(--smrt-color-surface-container-high, #f3f4f6);
180
+ background-color: var(--smrt-color-surface-container-high);
179
181
  cursor: not-allowed;
180
182
  opacity: 0.7;
181
183
  }
182
184
 
183
185
  .textarea::placeholder {
184
- color: var(--smrt-color-on-surface-variant, #9ca3af);
186
+ color: var(--smrt-color-on-surface-variant);
185
187
  }
186
188
 
187
189
  /* Phones: 16px text so iOS Safari doesn't zoom the page when the field
@@ -198,7 +200,8 @@ export function getElement(): HTMLTextAreaElement | null {
198
200
  }
199
201
  }
200
202
 
201
- .textarea[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min, 48px); }
203
+ .textarea[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min); }
202
204
  .textarea[data-density='comfortable'] { --smrt-control-target-min: 0px; }
203
205
  .textarea { min-height: max(80px, var(--smrt-control-target-min, 0px)); }
206
+ }
204
207
  </style>
@@ -25,5 +25,10 @@ let {
25
25
  const instanceId = $props.id();
26
26
  const resolvedId = $derived(id ?? `smrt-time-${instanceId}`);
27
27
  </script>
28
- <label class="picker {className}" for={resolvedId}><span>{label}</span><Input id={resolvedId} {name} type="time" aria-label={label} {interaction} bind:value {...rest} /></label>
29
- <style>.picker { display: grid; gap: var(--smrt-spacing-1); color: var(--smrt-color-on-surface); font: var(--smrt-typography-label-large-font); }</style>
28
+ <label class="picker {className}" for={resolvedId} data-smrt-component="TimePicker"><span>{label}</span><Input id={resolvedId} {name} type="time" aria-label={label} {interaction} bind:value {...rest} /></label>
29
+ <style>
30
+ @layer smrt.reset, smrt.structure, smrt.theme;
31
+ @layer smrt.theme {
32
+ .picker { display: grid; gap: var(--smrt-spacing-1); color: var(--smrt-color-on-surface); font: var(--smrt-typography-label-large-font); }
33
+ }
34
+ </style>
@@ -60,7 +60,7 @@ const sizeClasses = {
60
60
  };
61
61
  </script>
62
62
 
63
- <label class="toggle {sizeClasses[size]}" class:toggle--disabled={disabled}>
63
+ <label class="toggle {sizeClasses[size]}" class:toggle--disabled={disabled} data-smrt-component="Toggle">
64
64
  {#if label && labelPosition === 'left'}
65
65
  <span class="toggle__label toggle__label--left">{label}</span>
66
66
  {/if}
@@ -86,6 +86,8 @@ const sizeClasses = {
86
86
  </label>
87
87
 
88
88
  <style>
89
+ @layer smrt.reset, smrt.structure, smrt.theme;
90
+ @layer smrt.theme {
89
91
  .toggle {
90
92
  display: inline-flex;
91
93
  align-items: center;
@@ -101,7 +103,7 @@ const sizeClasses = {
101
103
 
102
104
  .toggle__label {
103
105
  font-size: var(--smrt-typography-body-medium-size, 0.875rem);
104
- color: var(--smrt-color-on-surface, #111827);
106
+ color: var(--smrt-color-on-surface);
105
107
  line-height: 1.5;
106
108
  }
107
109
 
@@ -126,38 +128,38 @@ const sizeClasses = {
126
128
 
127
129
  .toggle__thumb {
128
130
  position: relative;
129
- background: var(--smrt-color-surface-container-highest, #e5e7eb);
130
- border-radius: var(--smrt-radius-full, 9999px);
131
+ background: var(--smrt-color-surface-container-highest);
132
+ border-radius: var(--smrt-radius-full);
131
133
  transition: background-color var(--smrt-duration-short2, 150ms) var(--smrt-easing-standard, ease);
132
134
  }
133
135
 
134
136
  .toggle__thumb::after {
135
137
  content: '';
136
138
  position: absolute;
137
- background: var(--smrt-color-surface, #ffffff);
138
- border-radius: var(--smrt-radius-full, 9999px);
139
+ background: var(--smrt-color-surface);
140
+ border-radius: var(--smrt-radius-full);
139
141
  box-shadow: var(--smrt-elevation-1, 0 1px 3px color-mix(in srgb, var(--smrt-color-shadow) 20%, transparent));
140
142
  transition: transform var(--smrt-duration-short2, 150ms) var(--smrt-easing-standard, ease);
141
143
  }
142
144
 
143
145
  /* Checked state */
144
146
  .toggle__input:checked + .toggle__thumb {
145
- background: var(--smrt-color-primary, #005ac1);
147
+ background: var(--smrt-color-primary);
146
148
  }
147
149
 
148
150
  /* Focus state */
149
151
  .toggle__input:focus-visible + .toggle__thumb {
150
- outline: 2px solid var(--smrt-color-primary, #005ac1);
152
+ outline: 2px solid var(--smrt-color-primary);
151
153
  outline-offset: 2px;
152
154
  }
153
155
 
154
156
  /* Hover state */
155
157
  .toggle:not(.toggle--disabled):hover .toggle__thumb {
156
- background: var(--smrt-color-surface-container-high, #d1d5db);
158
+ background: var(--smrt-color-surface-container-high);
157
159
  }
158
160
 
159
161
  .toggle:not(.toggle--disabled):hover .toggle__input:checked + .toggle__thumb {
160
- background: var(--smrt-color-primary, #2563eb);
162
+ background: var(--smrt-color-primary);
161
163
  }
162
164
 
163
165
  /* Size: Small */
@@ -221,4 +223,5 @@ const sizeClasses = {
221
223
  transition: none;
222
224
  }
223
225
  }
226
+ }
224
227
  </style>
@@ -90,11 +90,14 @@ useControlRegistration(() => {
90
90
  aria-pressed={pressed} aria-label={ariaLabel} data-smrt-control={controlId} data-smrt-form={interactionContext?.formId}
91
91
  data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
92
92
  data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}
93
- onclick={handleClick} {...rest}>{@render children?.()}</button>
93
+ onclick={handleClick} {...rest} data-smrt-component="ToggleButton">{@render children?.()}</button>
94
94
  <style>
95
+ @layer smrt.reset, smrt.structure, smrt.theme;
96
+ @layer smrt.theme {
95
97
  .toggle-button { display: inline-flex; align-items: center; justify-content: center; min-height: 2.5rem; padding: 0 var(--smrt-spacing-4); border: 1px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-full); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); cursor: pointer; }
96
98
  .toggle-button.pressed { background: var(--smrt-color-secondary-container); color: var(--smrt-color-on-secondary-container); border-color: var(--smrt-color-secondary); }
97
99
  .toggle-button:focus-visible { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; }
98
100
  .toggle-button:disabled { opacity: .5; cursor: not-allowed; }
99
101
  .toggle-button[data-smrt-highlighted='true'] { outline: 3px solid var(--smrt-color-tertiary); outline-offset: 4px; }
102
+ }
100
103
  </style>
@@ -25,11 +25,13 @@ const {
25
25
  }: Props = $props();
26
26
  </script>
27
27
 
28
- <div class="action-group gap-{gap} justify-{justify} {className}" {...rest}>
28
+ <div class="action-group gap-{gap} justify-{justify} {className}" {...rest} data-smrt-component="ActionGroup">
29
29
  {@render children()}
30
30
  </div>
31
31
 
32
32
  <style>
33
+ @layer smrt.reset, smrt.structure, smrt.theme;
34
+ @layer smrt.theme {
33
35
  .action-group {
34
36
  display: flex;
35
37
  flex-wrap: wrap;
@@ -52,4 +54,5 @@ const {
52
54
  .justify-end {
53
55
  justify-content: flex-end;
54
56
  }
57
+ }
55
58
  </style>
@@ -14,11 +14,13 @@ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'class'> {
14
14
  const { maxWidth = 'lg', children, ...rest }: Props = $props();
15
15
  </script>
16
16
 
17
- <div class="container max-w-{maxWidth}" {...rest}>
17
+ <div class="container max-w-{maxWidth}" {...rest} data-smrt-component="Container">
18
18
  {@render children?.()}
19
19
  </div>
20
20
 
21
21
  <style>
22
+ @layer smrt.reset, smrt.structure, smrt.theme;
23
+ @layer smrt.theme {
22
24
  .container {
23
25
  box-sizing: border-box;
24
26
  width: 100%;
@@ -53,4 +55,5 @@ const { maxWidth = 'lg', children, ...rest }: Props = $props();
53
55
  padding-right: var(--smrt-spacing-6);
54
56
  }
55
57
  }
58
+ }
56
59
  </style>
@@ -61,7 +61,7 @@ const icons = {
61
61
  };
62
62
  </script>
63
63
 
64
- <div class="empty-state" class:sm={size === 'sm'} class:lg={size === 'lg'}>
64
+ <div class="empty-state" class:sm={size === 'sm'} class:lg={size === 'lg'} data-smrt-component="EmptyState">
65
65
  <div class="icon-container">
66
66
  {#if typeof icon === 'string'}
67
67
  {@html icons[icon] ?? icons.inbox}
@@ -90,6 +90,8 @@ const icons = {
90
90
  </div>
91
91
 
92
92
  <style>
93
+ @layer smrt.reset, smrt.structure, smrt.theme;
94
+ @layer smrt.theme {
93
95
  .empty-state {
94
96
  display: flex;
95
97
  flex-direction: column;
@@ -117,15 +119,15 @@ const icons = {
117
119
  background-color: var(--smrt-color-secondary-container);
118
120
  color: var(--smrt-color-on-secondary-container);
119
121
  border-radius: var(--smrt-radius-3xl, 32px); /* M3 extra large shape */
120
- padding: var(--smrt-spacing-6, 24px);
122
+ padding: var(--smrt-spacing-6);
121
123
  }
122
124
 
123
125
  .sm .icon-container {
124
126
  width: 64px;
125
127
  height: 64px;
126
128
  margin-bottom: 1.5rem;
127
- border-radius: var(--smrt-radius-xl, 16px);
128
- padding: var(--smrt-spacing-4, 16px);
129
+ border-radius: var(--smrt-radius-xl);
130
+ padding: var(--smrt-spacing-4);
129
131
  }
130
132
 
131
133
  .lg .icon-container {
@@ -133,7 +135,7 @@ const icons = {
133
135
  height: 120px;
134
136
  margin-bottom: 2.5rem;
135
137
  border-radius: var(--smrt-radius-3xl, 32px);
136
- padding: var(--smrt-spacing-8, 32px);
138
+ padding: var(--smrt-spacing-8);
137
139
  }
138
140
 
139
141
  .empty-title {
@@ -163,15 +165,15 @@ const icons = {
163
165
  display: inline-flex;
164
166
  align-items: center;
165
167
  justify-content: center;
166
- gap: var(--smrt-spacing-2, 8px);
167
- padding: 0 var(--smrt-spacing-6, 24px);
168
+ gap: var(--smrt-spacing-2);
169
+ padding: 0 var(--smrt-spacing-6);
168
170
  height: 40px;
169
171
  font: var(--smrt-typography-label-large-font);
170
172
  font-weight: var(--smrt-typography-weight-medium, 500);
171
173
  color: var(--smrt-color-on-primary);
172
174
  background-color: var(--smrt-color-primary);
173
175
  border: none;
174
- border-radius: var(--smrt-radius-2xl, 24px);
176
+ border-radius: var(--smrt-radius-2xl);
175
177
  text-decoration: none;
176
178
  cursor: pointer;
177
179
  transition: box-shadow 200ms, background-color 200ms;
@@ -184,4 +186,5 @@ const icons = {
184
186
  background-color: var(--smrt-color-primary);
185
187
  box-shadow: var(--smrt-elevation-2);
186
188
  }
189
+ }
187
190
  </style>
@@ -16,7 +16,7 @@ const { children }: Props = $props();
16
16
  const currentYear = new Date().getFullYear();
17
17
  </script>
18
18
 
19
- <footer class="site-footer">
19
+ <footer class="site-footer" data-smrt-component="Footer">
20
20
  <Container>
21
21
  <div class="footer-content">
22
22
  <p class="copyright">&copy; {currentYear} {t(M['ui.footer.all_rights_reserved'])}</p>
@@ -31,6 +31,8 @@ const currentYear = new Date().getFullYear();
31
31
  </footer>
32
32
 
33
33
  <style>
34
+ @layer smrt.reset, smrt.structure, smrt.theme;
35
+ @layer smrt.theme {
34
36
  .site-footer {
35
37
  background: var(--smrt-color-surface-container-low);
36
38
  border-top: 1px solid var(--smrt-color-outline-variant);
@@ -61,4 +63,5 @@ const currentYear = new Date().getFullYear();
61
63
  .footer-links :global(a:hover) {
62
64
  text-decoration: underline;
63
65
  }
66
+ }
64
67
  </style>
@@ -84,10 +84,10 @@ const responsiveStyles = $derived.by(() => {
84
84
  if (!isResponsive) return '';
85
85
  const cols = columns as ResponsiveColumns;
86
86
  const vars: string[] = [];
87
- if (cols.sm !== undefined) vars.push(`--grid-columns-sm: ${cols.sm}`);
88
- if (cols.md !== undefined) vars.push(`--grid-columns-md: ${cols.md}`);
89
- if (cols.lg !== undefined) vars.push(`--grid-columns-lg: ${cols.lg}`);
90
- if (cols.xl !== undefined) vars.push(`--grid-columns-xl: ${cols.xl}`);
87
+ if (cols.sm !== undefined) vars.push(`--smrt-grid-columns-sm: ${cols.sm}`);
88
+ if (cols.md !== undefined) vars.push(`--smrt-grid-columns-md: ${cols.md}`);
89
+ if (cols.lg !== undefined) vars.push(`--smrt-grid-columns-lg: ${cols.lg}`);
90
+ if (cols.xl !== undefined) vars.push(`--smrt-grid-columns-xl: ${cols.xl}`);
91
91
  return vars.join('; ');
92
92
  });
93
93
 
@@ -143,19 +143,21 @@ const gridClasses = $derived.by(() => {
143
143
  </script>
144
144
 
145
145
  {#if header}
146
- <div class="grid-header">
146
+ <div class="grid-header" data-smrt-component="Grid">
147
147
  {@render header()}
148
148
  </div>
149
149
  {/if}
150
150
  <div
151
151
  class={gridClasses}
152
152
  style={inlineStyles}
153
- {...rest}
153
+ {...rest} data-smrt-component="Grid"
154
154
  >
155
155
  {@render children?.()}
156
156
  </div>
157
157
 
158
158
  <style>
159
+ @layer smrt.reset, smrt.structure, smrt.theme;
160
+ @layer smrt.theme {
159
161
  .grid {
160
162
  display: grid;
161
163
  min-width: 0;
@@ -168,24 +170,24 @@ const gridClasses = $derived.by(() => {
168
170
 
169
171
  /* Responsive grid - uses CSS variables set via inline styles */
170
172
  .grid-responsive {
171
- grid-template-columns: repeat(var(--grid-columns-sm, 1), 1fr);
173
+ grid-template-columns: repeat(var(--smrt-grid-columns-sm, 1), 1fr);
172
174
  }
173
175
 
174
176
  @media (min-width: 640px) {
175
177
  .grid-responsive {
176
- grid-template-columns: repeat(var(--grid-columns-md, var(--grid-columns-sm, 2)), 1fr);
178
+ grid-template-columns: repeat(var(--smrt-grid-columns-md, var(--smrt-grid-columns-sm, 2)), 1fr);
177
179
  }
178
180
  }
179
181
 
180
182
  @media (min-width: 1024px) {
181
183
  .grid-responsive {
182
- grid-template-columns: repeat(var(--grid-columns-lg, var(--grid-columns-md, var(--grid-columns-sm, 3))), 1fr);
184
+ grid-template-columns: repeat(var(--smrt-grid-columns-lg, var(--smrt-grid-columns-md, var(--smrt-grid-columns-sm, 3))), 1fr);
183
185
  }
184
186
  }
185
187
 
186
188
  @media (min-width: 1280px) {
187
189
  .grid-responsive {
188
- grid-template-columns: repeat(var(--grid-columns-xl, var(--grid-columns-lg, var(--grid-columns-md, var(--grid-columns-sm, 4)))), 1fr);
190
+ grid-template-columns: repeat(var(--smrt-grid-columns-xl, var(--smrt-grid-columns-lg, var(--smrt-grid-columns-md, var(--smrt-grid-columns-sm, 4)))), 1fr);
189
191
  }
190
192
  }
191
193
 
@@ -239,4 +241,5 @@ const gridClasses = $derived.by(() => {
239
241
  .col-gap-xl {
240
242
  column-gap: var(--smrt-spacing-12);
241
243
  }
244
+ }
242
245
  </style>
@@ -12,7 +12,7 @@ export interface Props {
12
12
  const { logo, nav }: Props = $props();
13
13
  </script>
14
14
 
15
- <header class="site-header">
15
+ <header class="site-header" data-smrt-component="Header">
16
16
  <Container>
17
17
  <div class="header-content">
18
18
  {#if logo}
@@ -31,6 +31,8 @@ const { logo, nav }: Props = $props();
31
31
  </header>
32
32
 
33
33
  <style>
34
+ @layer smrt.reset, smrt.structure, smrt.theme;
35
+ @layer smrt.theme {
34
36
  .site-header {
35
37
  background: var(--smrt-color-primary);
36
38
  color: var(--smrt-color-on-primary);
@@ -85,4 +87,5 @@ const { logo, nav }: Props = $props();
85
87
  font-size: var(--smrt-typography-headline-medium-size);
86
88
  }
87
89
  }
90
+ }
88
91
  </style>
@@ -36,7 +36,7 @@ const {
36
36
  }: Props = $props();
37
37
  </script>
38
38
 
39
- <div class="masthead">
39
+ <div class="masthead" data-smrt-component="Masthead">
40
40
  <Container>
41
41
  <!-- Desktop layout -->
42
42
  <div class="subheader desktop">
@@ -87,6 +87,8 @@ const {
87
87
  </div>
88
88
 
89
89
  <style>
90
+ @layer smrt.reset, smrt.structure, smrt.theme;
91
+ @layer smrt.theme {
90
92
  .masthead {
91
93
  border-bottom: 1px solid var(--smrt-color-outline-variant);
92
94
  background: var(--smrt-color-surface);
@@ -222,4 +224,5 @@ const {
222
224
  justify-self: unset;
223
225
  }
224
226
  }
227
+ }
225
228
  </style>
@@ -91,7 +91,7 @@ const trail = $derived<readonly PageHeaderCrumb[]>(
91
91
  $effect(() => shell?.report?.({ title: shortTitle ?? title, parents }));
92
92
  </script>
93
93
 
94
- <header class="page-header" data-page-header>
94
+ <header class="page-header" data-page-header data-smrt-component="PageHeader">
95
95
  {#if trail.length > 0}
96
96
  <nav class="page-crumbs" aria-label={crumbsLabel} data-shell-breadcrumbs>
97
97
  <ol>
@@ -140,12 +140,14 @@ $effect(() => shell?.report?.({ title: shortTitle ?? title, parents }));
140
140
  </header>
141
141
 
142
142
  <style>
143
+ @layer smrt.reset, smrt.structure, smrt.theme;
144
+ @layer smrt.theme {
143
145
  .page-header {
144
146
  margin-bottom: 1.5rem;
145
147
  }
146
148
 
147
149
  .page-crumbs {
148
- margin-bottom: var(--smrt-spacing-1, 4px);
150
+ margin-bottom: var(--smrt-spacing-1);
149
151
  color: var(--smrt-color-on-surface-variant);
150
152
  font: var(--smrt-typography-body-small-font);
151
153
  font-size: 0.84rem;
@@ -187,7 +189,7 @@ $effect(() => shell?.report?.({ title: shortTitle ?? title, parents }));
187
189
  .page-crumbs a:focus-visible {
188
190
  outline: 2px solid var(--smrt-color-primary);
189
191
  outline-offset: 2px;
190
- border-radius: var(--smrt-radius-sm, 4px);
192
+ border-radius: var(--smrt-radius-sm);
191
193
  }
192
194
 
193
195
  .header-main {
@@ -201,7 +203,7 @@ $effect(() => shell?.report?.({ title: shortTitle ?? title, parents }));
201
203
  .header-content {
202
204
  display: flex;
203
205
  flex-direction: column;
204
- gap: var(--smrt-spacing-1, 4px);
206
+ gap: var(--smrt-spacing-1);
205
207
  flex: 1;
206
208
  min-width: min(100%, 200px);
207
209
  }
@@ -209,13 +211,13 @@ $effect(() => shell?.report?.({ title: shortTitle ?? title, parents }));
209
211
  .back-link {
210
212
  display: inline-flex;
211
213
  align-items: center;
212
- gap: var(--smrt-spacing-1, 4px);
214
+ gap: var(--smrt-spacing-1);
213
215
  color: var(--smrt-color-primary);
214
216
  font: var(--smrt-typography-label-large-font);
215
217
  text-decoration: none;
216
218
  margin-bottom: 0.75rem;
217
- padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-2, 8px) var(--smrt-spacing-1, 4px) var(--smrt-spacing-1, 4px);
218
- border-radius: var(--smrt-radius-md, 8px);
219
+ padding: var(--smrt-spacing-1) var(--smrt-spacing-2) var(--smrt-spacing-1) var(--smrt-spacing-1);
220
+ border-radius: var(--smrt-radius-md);
219
221
  margin-left: -4px; /* Align icon with text below */
220
222
  transition: background-color 200ms;
221
223
  }
@@ -262,4 +264,5 @@ $effect(() => shell?.report?.({ title: shortTitle ?? title, parents }));
262
264
  .header-extra {
263
265
  margin-top: 1rem;
264
266
  }
267
+ }
265
268
  </style>
@@ -33,6 +33,8 @@ const {
33
33
  </Container>
34
34
 
35
35
  <style>
36
+ @layer smrt.reset, smrt.structure, smrt.theme;
37
+ @layer smrt.theme {
36
38
  .page-layout {
37
39
  display: grid;
38
40
  grid-template-columns: minmax(0, 1fr);
@@ -58,4 +60,5 @@ const {
58
60
  padding-block: var(--smrt-spacing-6) var(--smrt-spacing-10);
59
61
  }
60
62
  }
63
+ }
61
64
  </style>
@@ -76,7 +76,7 @@ const valueColorClass = $derived.by(() => {
76
76
  class:highlight
77
77
  class:clickable={true}
78
78
  {href}
79
- use:ripple
79
+ use:ripple data-smrt-component="SummaryCard"
80
80
  >
81
81
  {@render cardIcon()}
82
82
  <div class="card-content">
@@ -93,7 +93,7 @@ const valueColorClass = $derived.by(() => {
93
93
  </div>
94
94
  </a>
95
95
  {:else}
96
- <div class="summary-card" class:highlight>
96
+ <div class="summary-card" class:highlight data-smrt-component="SummaryCard">
97
97
  {@render cardIcon()}
98
98
  <div class="card-content">
99
99
  <span class="card-label">
@@ -108,13 +108,15 @@ const valueColorClass = $derived.by(() => {
108
108
  {/if}
109
109
 
110
110
  <style>
111
+ @layer smrt.reset, smrt.structure, smrt.theme;
112
+ @layer smrt.theme {
111
113
  .summary-card {
112
114
  display: flex;
113
115
  align-items: center;
114
116
  gap: 1rem;
115
117
  padding: 1rem 1.25rem;
116
118
  background-color: var(--smrt-color-surface-container-low);
117
- border-radius: var(--smrt-radius-lg, 12px);
119
+ border-radius: var(--smrt-radius-lg);
118
120
  text-decoration: none;
119
121
  color: var(--smrt-color-on-surface);
120
122
  transition: all 200ms cubic-bezier(0.2, 0, 0, 1);
@@ -140,7 +142,7 @@ const valueColorClass = $derived.by(() => {
140
142
  width: 3rem;
141
143
  height: 3rem;
142
144
  background-color: var(--smrt-color-surface-container-high);
143
- border-radius: var(--smrt-radius-lg, 12px);
145
+ border-radius: var(--smrt-radius-lg);
144
146
  color: var(--smrt-color-primary);
145
147
  flex-shrink: 0;
146
148
  }
@@ -154,7 +156,7 @@ const valueColorClass = $derived.by(() => {
154
156
  flex: 1;
155
157
  display: flex;
156
158
  flex-direction: column;
157
- gap: var(--smrt-spacing-1, 4px);
159
+ gap: var(--smrt-spacing-1);
158
160
  }
159
161
 
160
162
  .card-label {
@@ -180,7 +182,7 @@ const valueColorClass = $derived.by(() => {
180
182
  font: var(--smrt-typography-label-small-font);
181
183
  background-color: var(--smrt-color-primary);
182
184
  color: var(--smrt-color-on-primary);
183
- border-radius: var(--smrt-radius-full, 9999px);
185
+ border-radius: var(--smrt-radius-full);
184
186
  }
185
187
 
186
188
  .card-value {
@@ -202,4 +204,5 @@ const valueColorClass = $derived.by(() => {
202
204
  opacity: 1;
203
205
  color: var(--smrt-color-primary);
204
206
  }
207
+ }
205
208
  </style>
@@ -43,7 +43,7 @@ function formatDate(date: Date | string | null | undefined): string {
43
43
  }
44
44
  </script>
45
45
 
46
- <div class="membership-card">
46
+ <div class="membership-card" data-smrt-component="MembershipCard">
47
47
  <div class="main">
48
48
  <div class="tenant-info">
49
49
  <span class="tenant-name">{tenant.name}</span>
@@ -72,6 +72,8 @@ function formatDate(date: Date | string | null | undefined): string {
72
72
  </div>
73
73
 
74
74
  <style>
75
+ @layer smrt.reset, smrt.structure, smrt.theme;
76
+ @layer smrt.theme {
75
77
  .membership-card {
76
78
  padding: 1rem;
77
79
  background: var(--smrt-color-surface);
@@ -100,7 +102,7 @@ function formatDate(date: Date | string | null | undefined): string {
100
102
  .status {
101
103
  font-size: var(--smrt-typography-label-small-size, 0.625rem);
102
104
  padding: 0.125rem 0.375rem;
103
- border-radius: var(--smrt-radius-full, 9999px);
105
+ border-radius: var(--smrt-radius-full);
104
106
  text-transform: uppercase;
105
107
  font-weight: var(--smrt-typography-weight-semibold, 600);
106
108
  }
@@ -165,4 +167,5 @@ function formatDate(date: Date | string | null | undefined): string {
165
167
  .action-btn.danger:hover {
166
168
  background: var(--smrt-color-error-container);
167
169
  }
170
+ }
168
171
  </style>
@@ -37,7 +37,7 @@ const {
37
37
  }: Props = $props();
38
38
  </script>
39
39
 
40
- <div class="membership-list">
40
+ <div class="membership-list" data-smrt-component="MembershipList">
41
41
  {#if loading}
42
42
  <div class="loading">
43
43
  <div class="spinner"></div>
@@ -63,6 +63,8 @@ const {
63
63
  </div>
64
64
 
65
65
  <style>
66
+ @layer smrt.reset, smrt.structure, smrt.theme;
67
+ @layer smrt.theme {
66
68
  .membership-list {
67
69
  display: flex;
68
70
  flex-direction: column;
@@ -83,7 +85,7 @@ const {
83
85
  height: 1.25rem;
84
86
  border: 2px solid var(--smrt-color-outline-variant);
85
87
  border-top-color: var(--smrt-color-primary);
86
- border-radius: var(--smrt-radius-full, 9999px);
88
+ border-radius: var(--smrt-radius-full);
87
89
  animation: spin 0.6s linear infinite;
88
90
  }
89
91
 
@@ -101,4 +103,5 @@ const {
101
103
  border: 1px dashed var(--smrt-color-outline);
102
104
  border-radius: 0.5rem;
103
105
  }
106
+ }
104
107
  </style>