@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.
- package/AGENTS.md +14 -0
- package/README.md +68 -0
- package/dist/components/calendar/Calendar.svelte +59 -56
- package/dist/components/calendar/CalendarView.svelte +79 -76
- package/dist/components/calendar/DayView.svelte +39 -36
- package/dist/components/chat/MessageBubble.svelte +26 -23
- package/dist/components/chat/ReactionPicker.svelte +10 -7
- package/dist/components/chat/TypingIndicator.svelte +12 -9
- package/dist/components/data/CollectionList.svelte +10 -7
- package/dist/components/data/CollectionToolbar.svelte +5 -2
- package/dist/components/data/DataTable.svelte +51 -48
- package/dist/components/data/ListSortSelect.svelte +8 -5
- package/dist/components/data/SortableHeader.svelte +9 -6
- package/dist/components/display/ConfidenceBadge.svelte +11 -8
- package/dist/components/display/CurrencyDisplay.svelte +7 -4
- package/dist/components/display/DateDisplay.svelte +6 -3
- package/dist/components/display/Icon.svelte +4 -1
- package/dist/components/display/StatusBadge.svelte +9 -6
- package/dist/components/feedback/Alert.svelte +9 -6
- package/dist/components/feedback/ConfirmDialog.svelte +13 -10
- package/dist/components/feedback/LoadingOverlay.svelte +35 -32
- package/dist/components/feedback/Meter.svelte +4 -1
- package/dist/components/feedback/Modal.svelte +20 -17
- package/dist/components/feedback/PhoneSheet.svelte +4 -1
- package/dist/components/feedback/Progress.svelte +8 -5
- package/dist/components/feedback/ProgressBar.svelte +13 -10
- package/dist/components/feedback/Spinner.svelte +4 -1
- package/dist/components/feedback/ToastViewport.svelte +17 -14
- package/dist/components/feedback/WorkingStrip.svelte +6 -3
- package/dist/components/forms/CameraCapture.svelte +6 -3
- package/dist/components/forms/Checkbox.svelte +10 -7
- package/dist/components/forms/Combobox.svelte +4 -1
- package/dist/components/forms/DatePicker.svelte +7 -2
- package/dist/components/forms/DictationButton.svelte +17 -14
- package/dist/components/forms/DictationStatus.svelte +12 -9
- package/dist/components/forms/ErrorSummary.svelte +4 -1
- package/dist/components/forms/FieldLabel.svelte +9 -6
- package/dist/components/forms/Fieldset.svelte +4 -1
- package/dist/components/forms/FilePicker.svelte +4 -1
- package/dist/components/forms/Form.svelte +1 -1
- package/dist/components/forms/FormActionBar.svelte +4 -1
- package/dist/components/forms/FormGroup.svelte +6 -3
- package/dist/components/forms/Input.svelte +14 -11
- package/dist/components/forms/InputGroup.svelte +5 -2
- package/dist/components/forms/Listbox.svelte +4 -1
- package/dist/components/forms/MultiSelect.svelte +4 -1
- package/dist/components/forms/Radio.svelte +8 -5
- package/dist/components/forms/RadioGroup.svelte +5 -2
- package/dist/components/forms/RangeSlider.svelte +4 -1
- package/dist/components/forms/RelationInput.svelte +7 -4
- package/dist/components/forms/SearchInput.svelte +5 -2
- package/dist/components/forms/SegmentedControl.svelte +5 -2
- package/dist/components/forms/Select.svelte +12 -9
- package/dist/components/forms/SignaturePad.svelte +6 -3
- package/dist/components/forms/Slider.svelte +4 -1
- package/dist/components/forms/StagedControlReview.svelte +15 -12
- package/dist/components/forms/Switch.svelte +7 -4
- package/dist/components/forms/TagsInput.svelte +4 -1
- package/dist/components/forms/Textarea.svelte +13 -10
- package/dist/components/forms/TimePicker.svelte +7 -2
- package/dist/components/forms/Toggle.svelte +13 -10
- package/dist/components/forms/ToggleButton.svelte +4 -1
- package/dist/components/layout/ActionGroup.svelte +4 -1
- package/dist/components/layout/Container.svelte +4 -1
- package/dist/components/layout/EmptyState.svelte +11 -8
- package/dist/components/layout/Footer.svelte +4 -1
- package/dist/components/layout/Grid.svelte +13 -10
- package/dist/components/layout/Header.svelte +4 -1
- package/dist/components/layout/Masthead.svelte +4 -1
- package/dist/components/layout/PageHeader.svelte +10 -7
- package/dist/components/layout/PageLayout.svelte +3 -0
- package/dist/components/layout/SummaryCard.svelte +9 -6
- package/dist/components/memberships/MembershipCard.svelte +5 -2
- package/dist/components/memberships/MembershipList.svelte +5 -2
- package/dist/components/nav/FilterChips.svelte +13 -10
- package/dist/components/nav/Tabs.svelte +28 -24
- package/dist/components/permissions/PermissionPicker.svelte +4 -1
- package/dist/components/roles/RoleBadge.svelte +8 -5
- package/dist/components/roles/RoleSelector.svelte +21 -18
- package/dist/components/theme/ThemeProvider.svelte +7 -4
- package/dist/components/ui/Accordion.svelte +4 -1
- package/dist/components/ui/AccordionItem.svelte +4 -1
- package/dist/components/ui/Avatar.svelte +10 -7
- package/dist/components/ui/Badge.svelte +4 -1
- package/dist/components/ui/Button.svelte +11 -8
- package/dist/components/ui/Card.svelte +7 -4
- package/dist/components/ui/Chip.svelte +12 -9
- package/dist/components/ui/Disclosure.svelte +4 -1
- package/dist/components/ui/Dropdown.svelte +17 -14
- package/dist/components/ui/IconToggle.svelte +10 -7
- package/dist/components/ui/IconToggle.svelte.d.ts +1 -1
- package/dist/components/ui/IconToggle.svelte.d.ts.map +1 -1
- package/dist/components/ui/IconToggleGroup.svelte +8 -5
- package/dist/components/ui/Pagination.svelte +11 -8
- package/dist/components/ui/Popover.svelte +5 -2
- package/dist/components/ui/Skeleton.svelte +10 -7
- package/dist/components/ui/Tooltip.svelte +12 -9
- package/dist/components/ui/Tree.svelte +10 -7
- package/dist/styles/layers.css +8 -0
- package/dist/styles/layers.d.ts +9 -0
- package/dist/styles/layers.d.ts.map +1 -0
- package/dist/styles/layers.js +8 -0
- package/dist/styles/tokens.css +27 -69
- package/dist/styles/unstyled.css +65 -0
- package/dist/svelte/playground/BaseControlsPreview.svelte +3 -0
- package/dist/svelte/playground/CalendarPreview.svelte +5 -2
- package/dist/svelte/playground/CapturePreview.svelte +3 -0
- package/dist/svelte/playground/CodeSelectorsPreview.svelte +3 -0
- package/dist/svelte/playground/CollectionsPreview.svelte +3 -0
- package/dist/svelte/playground/DataTablePreview.svelte +3 -0
- package/dist/svelte/playground/FeedbackPreview.svelte +3 -0
- package/dist/svelte/playground/InteractiveControlsPreview.svelte +3 -0
- package/dist/svelte/playground/StylelessPreview.svelte +110 -0
- package/dist/svelte/playground/StylelessPreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/StylelessPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground.d.ts.map +1 -1
- package/dist/svelte/playground.js +10 -0
- package/dist/test-support/setup.js +9 -0
- package/dist/theme/ThemeProvider.svelte +3 -0
- package/dist/themes/CUSTOM_THEME_GUIDE.md +25 -0
- package/dist/themes/README.md +25 -0
- package/dist/themes/ThemeProvider.svelte +11 -2
- package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
- package/dist/themes/components/ColorSchemeToggle.svelte +17 -14
- package/dist/themes/components/ThemeSwitcher.svelte +14 -11
- package/dist/themes/create-theme.d.ts.map +1 -1
- package/dist/themes/create-theme.js +8 -5
- package/dist/themes/css-generator.d.ts.map +1 -1
- package/dist/themes/css-generator.js +5 -4
- package/dist/themes/required-tokens.generated.json +172 -0
- package/dist/themes/styles/base.css +4 -1
- package/dist/themes/styles/glass.css +4 -1
- package/dist/themes/styles/happyvertical.css +7 -3
- package/dist/themes/styles/smrt.css +4 -1
- package/dist/themes/styles/studio.css +4 -1
- package/dist/utils/theme/typography.d.ts +21 -21
- package/dist/utils/theme/typography.js +21 -21
- package/package.json +8 -2
|
@@ -89,7 +89,7 @@ function onkeydown(event: KeyboardEvent): void {
|
|
|
89
89
|
tabindex="-1"
|
|
90
90
|
data-escape-scope
|
|
91
91
|
data-testid="phone-sheet"
|
|
92
|
-
{onkeydown}
|
|
92
|
+
{onkeydown} data-smrt-component="PhoneSheet"
|
|
93
93
|
>
|
|
94
94
|
<header
|
|
95
95
|
class="phone-sheet__header"
|
|
@@ -129,6 +129,8 @@ function onkeydown(event: KeyboardEvent): void {
|
|
|
129
129
|
</div>
|
|
130
130
|
|
|
131
131
|
<style>
|
|
132
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
133
|
+
@layer smrt.theme {
|
|
132
134
|
.phone-sheet {
|
|
133
135
|
position: absolute;
|
|
134
136
|
inset: 0;
|
|
@@ -221,4 +223,5 @@ function onkeydown(event: KeyboardEvent): void {
|
|
|
221
223
|
transition: none;
|
|
222
224
|
}
|
|
223
225
|
}
|
|
226
|
+
}
|
|
224
227
|
</style>
|
|
@@ -39,18 +39,20 @@ const displayValue = $derived(
|
|
|
39
39
|
</script>
|
|
40
40
|
{#if variant === 'circular'}
|
|
41
41
|
<div class="progress progress--circular progress--{size} {className}" class:indeterminate role="progressbar" aria-label={label}
|
|
42
|
-
aria-valuemin={indeterminate ? undefined : min} aria-valuemax={indeterminate ? undefined : max} aria-valuenow={value}>
|
|
43
|
-
<svg viewBox="0 0 44 44" aria-hidden="true"><circle class="track" cx="22" cy="22" r="18"></circle><circle class="indicator" cx="22" cy="22" r="18" style={`--progress: ${normalized}`}></circle></svg>
|
|
42
|
+
aria-valuemin={indeterminate ? undefined : min} aria-valuemax={indeterminate ? undefined : max} aria-valuenow={value} data-smrt-component="Progress">
|
|
43
|
+
<svg viewBox="0 0 44 44" aria-hidden="true"><circle class="track" cx="22" cy="22" r="18"></circle><circle class="indicator" cx="22" cy="22" r="18" style={`--smrt-progress-value: ${normalized}`}></circle></svg>
|
|
44
44
|
{#if showValue && !indeterminate}<span>{displayValue}</span>{/if}
|
|
45
45
|
</div>
|
|
46
46
|
{:else}
|
|
47
47
|
<div class="progress progress--linear progress--{size} {className}" class:indeterminate role="progressbar" aria-label={label}
|
|
48
|
-
aria-valuemin={indeterminate ? undefined : min} aria-valuemax={indeterminate ? undefined : max} aria-valuenow={value}>
|
|
48
|
+
aria-valuemin={indeterminate ? undefined : min} aria-valuemax={indeterminate ? undefined : max} aria-valuenow={value} data-smrt-component="Progress">
|
|
49
49
|
<span class="track"><span class="indicator" style:width={indeterminate ? undefined : `${normalized}%`}></span></span>
|
|
50
50
|
{#if showValue && !indeterminate}<span class="value">{displayValue}</span>{/if}
|
|
51
51
|
</div>
|
|
52
52
|
{/if}
|
|
53
53
|
<style>
|
|
54
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
55
|
+
@layer smrt.theme {
|
|
54
56
|
.progress--linear { display: flex; align-items: center; gap: var(--smrt-spacing-2); width: 100%; }
|
|
55
57
|
.progress--linear .track { position: relative; display: block; flex: 1; height: 4px; overflow: hidden; border-radius: var(--smrt-radius-full); background: var(--smrt-color-surface-container-highest); }
|
|
56
58
|
.progress--linear.progress--sm .track { height: 2px; } .progress--linear.progress--lg .track { height: 8px; }
|
|
@@ -61,9 +63,10 @@ const displayValue = $derived(
|
|
|
61
63
|
.progress--circular.progress--sm { width: 1.75rem; height: 1.75rem; } .progress--circular.progress--lg { width: 4rem; height: 4rem; }
|
|
62
64
|
.progress--circular svg { width: 100%; height: 100%; transform: rotate(-90deg); }
|
|
63
65
|
.progress--circular circle { fill: none; stroke-width: 4; } .progress--circular .track { stroke: var(--smrt-color-surface-container-highest); }
|
|
64
|
-
.progress--circular .indicator { stroke: var(--smrt-color-primary); stroke-linecap: round; stroke-dasharray: 113.1; stroke-dashoffset: calc(113.1 - (113.1 * var(--progress)) / 100); transition: stroke-dashoffset var(--smrt-duration-short4); }
|
|
66
|
+
.progress--circular .indicator { stroke: var(--smrt-color-primary); stroke-linecap: round; stroke-dasharray: 113.1; stroke-dashoffset: calc(113.1 - (113.1 * var(--smrt-progress-value)) / 100); transition: stroke-dashoffset var(--smrt-duration-short4); }
|
|
65
67
|
.progress--circular.indeterminate svg { animation: spin 1s linear infinite; } .progress--circular.indeterminate .indicator { stroke-dasharray: 70 113.1; }
|
|
66
68
|
.progress--circular > span { position: absolute; font: var(--smrt-typography-label-small-font); }
|
|
67
69
|
@keyframes linear-progress { from { left: -40%; } to { left: 105%; } } @keyframes spin { to { transform: rotate(270deg); } }
|
|
68
|
-
@media (prefers-reduced-motion: reduce) { .indicator { transition: none
|
|
70
|
+
@media (prefers-reduced-motion: reduce) { .progress--linear .indicator, .progress--circular .indicator { transition: none; } .progress--linear.indeterminate .indicator { animation-duration: 2.5s; } }
|
|
71
|
+
}
|
|
69
72
|
</style>
|
|
@@ -76,7 +76,7 @@ const displayLabel = $derived.by(() => {
|
|
|
76
76
|
});
|
|
77
77
|
</script>
|
|
78
78
|
|
|
79
|
-
<div class="progress-container" class:sm={size === 'sm'} class:lg={size === 'lg'}>
|
|
79
|
+
<div class="progress-container" class:sm={size === 'sm'} class:lg={size === 'lg'} data-smrt-component="ProgressBar">
|
|
80
80
|
{#if showLabel || showValue}
|
|
81
81
|
<div class="progress-header">
|
|
82
82
|
<span class="progress-label">{displayLabel}</span>
|
|
@@ -102,6 +102,8 @@ const displayLabel = $derived.by(() => {
|
|
|
102
102
|
</div>
|
|
103
103
|
|
|
104
104
|
<style>
|
|
105
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
106
|
+
@layer smrt.theme {
|
|
105
107
|
.progress-container {
|
|
106
108
|
width: 100%;
|
|
107
109
|
}
|
|
@@ -110,12 +112,12 @@ const displayLabel = $derived.by(() => {
|
|
|
110
112
|
display: flex;
|
|
111
113
|
justify-content: space-between;
|
|
112
114
|
align-items: center;
|
|
113
|
-
margin-bottom: var(--smrt-spacing-2
|
|
115
|
+
margin-bottom: var(--smrt-spacing-2);
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
.progress-label {
|
|
117
119
|
font: var(--smrt-typography-label-large-font);
|
|
118
|
-
color: var(--smrt-color-on-surface-variant
|
|
120
|
+
color: var(--smrt-color-on-surface-variant);
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
.sm .progress-label {
|
|
@@ -125,14 +127,14 @@ const displayLabel = $derived.by(() => {
|
|
|
125
127
|
.over-badge {
|
|
126
128
|
font: var(--smrt-typography-label-small-font);
|
|
127
129
|
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
128
|
-
color: var(--smrt-color-error
|
|
130
|
+
color: var(--smrt-color-error);
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
.progress-track {
|
|
132
134
|
width: 100%;
|
|
133
135
|
height: 4px;
|
|
134
|
-
background-color: var(--smrt-color-surface-container-highest
|
|
135
|
-
border-radius: var(--smrt-radius-sm
|
|
136
|
+
background-color: var(--smrt-color-surface-container-highest);
|
|
137
|
+
border-radius: var(--smrt-radius-sm);
|
|
136
138
|
overflow: hidden;
|
|
137
139
|
}
|
|
138
140
|
|
|
@@ -142,7 +144,7 @@ const displayLabel = $derived.by(() => {
|
|
|
142
144
|
|
|
143
145
|
.lg .progress-track {
|
|
144
146
|
height: 8px;
|
|
145
|
-
border-radius: var(--smrt-radius-sm
|
|
147
|
+
border-radius: var(--smrt-radius-sm);
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
.progress-bar {
|
|
@@ -156,7 +158,8 @@ const displayLabel = $derived.by(() => {
|
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
|
|
159
|
-
.color-primary { background-color: var(--smrt-color-primary
|
|
160
|
-
.color-tertiary { background-color: var(--smrt-color-tertiary
|
|
161
|
-
.color-error { background-color: var(--smrt-color-error
|
|
161
|
+
.color-primary { background-color: var(--smrt-color-primary); }
|
|
162
|
+
.color-tertiary { background-color: var(--smrt-color-tertiary); }
|
|
163
|
+
.color-error { background-color: var(--smrt-color-error); }
|
|
164
|
+
}
|
|
162
165
|
</style>
|
|
@@ -9,12 +9,15 @@ export interface Props {
|
|
|
9
9
|
}
|
|
10
10
|
let { label = 'Loading', size = 'md', class: className = '' }: Props = $props();
|
|
11
11
|
</script>
|
|
12
|
-
<span class="spinner spinner--{size} {className}" role="status"><span class="spinner__ring" aria-hidden="true"></span><span class="visually-hidden">{label}</span></span>
|
|
12
|
+
<span class="spinner spinner--{size} {className}" role="status" data-smrt-component="Spinner"><span class="spinner__ring" aria-hidden="true"></span><span class="visually-hidden">{label}</span></span>
|
|
13
13
|
<style>
|
|
14
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
15
|
+
@layer smrt.theme {
|
|
14
16
|
.spinner { display: inline-flex; }
|
|
15
17
|
.spinner__ring { width: 1.5rem; height: 1.5rem; border: 2px solid var(--smrt-color-surface-container-highest); border-top-color: var(--smrt-color-primary); border-radius: 50%; animation: spin .75s linear infinite; }
|
|
16
18
|
.spinner--sm .spinner__ring { width: 1rem; height: 1rem; } .spinner--lg .spinner__ring { width: 2.5rem; height: 2.5rem; border-width: 3px; }
|
|
17
19
|
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
|
|
18
20
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
19
21
|
@media (prefers-reduced-motion: reduce) { .spinner__ring { animation-duration: 1.5s; } }
|
|
22
|
+
}
|
|
20
23
|
</style>
|
|
@@ -161,12 +161,12 @@ async function runAction(toast: Toast) {
|
|
|
161
161
|
</script>
|
|
162
162
|
|
|
163
163
|
<section use:followModal class="viewport viewport--{position} {className}" aria-label="Notifications" aria-live="polite"
|
|
164
|
-
style:--toast-inset={inset}
|
|
165
|
-
style:--toast-top={bounds ? `${bounds.top}px` : undefined}
|
|
166
|
-
style:--toast-right={bounds ? `${bounds.right}px` : undefined}
|
|
167
|
-
style:--toast-bottom={bounds ? `${bounds.bottom}px` : undefined}
|
|
168
|
-
style:--toast-left={bounds ? `${bounds.left}px` : undefined}
|
|
169
|
-
style:--toast-region-width={bounds ? `${bounds.width}px` : undefined}
|
|
164
|
+
style:--smrt-toast-viewport-inset={inset}
|
|
165
|
+
style:--smrt-toast-viewport-top={bounds ? `${bounds.top}px` : undefined}
|
|
166
|
+
style:--smrt-toast-viewport-right={bounds ? `${bounds.right}px` : undefined}
|
|
167
|
+
style:--smrt-toast-viewport-bottom={bounds ? `${bounds.bottom}px` : undefined}
|
|
168
|
+
style:--smrt-toast-viewport-left={bounds ? `${bounds.left}px` : undefined}
|
|
169
|
+
style:--smrt-toast-viewport-region-width={bounds ? `${bounds.width}px` : undefined} data-smrt-component="ToastViewport"
|
|
170
170
|
>
|
|
171
171
|
{#each toasts as toast (toast.id)}
|
|
172
172
|
<div role="group" aria-label={toast.title ?? 'Notification'}
|
|
@@ -186,14 +186,17 @@ async function runAction(toast: Toast) {
|
|
|
186
186
|
</section>
|
|
187
187
|
|
|
188
188
|
<style>
|
|
189
|
-
|
|
189
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
190
|
+
@layer smrt.theme {
|
|
191
|
+
.viewport { position: fixed; z-index: var(--smrt-z-index-toast, 1200); display: grid; width: min(24rem, calc(var(--smrt-toast-viewport-region-width, 100vw) - 2 * var(--smrt-toast-viewport-inset))); gap: var(--smrt-spacing-2); pointer-events: none; }
|
|
190
192
|
.viewport :global(.alert) { pointer-events: auto; box-shadow: var(--smrt-elevation-3); }
|
|
191
|
-
.viewport--top-start { top: calc(var(--toast-top, 0px) + var(--toast-inset)); left: calc(var(--toast-left, 0px) + var(--toast-inset)); }
|
|
192
|
-
.viewport--top-end { top: calc(var(--toast-top, 0px) + var(--toast-inset)); right: calc(var(--toast-right, 0px) + var(--toast-inset)); }
|
|
193
|
-
.viewport--bottom-start { bottom: calc(var(--toast-bottom, 0px) + var(--toast-inset)); left: calc(var(--toast-left, 0px) + var(--toast-inset)); }
|
|
194
|
-
.viewport--bottom-end { right: calc(var(--toast-right, 0px) + var(--toast-inset)); bottom: calc(var(--toast-bottom, 0px) + var(--toast-inset)); }
|
|
195
|
-
.viewport--top-center, .viewport--bottom-center { left: calc(var(--toast-left, 0px) + var(--toast-region-width, 100vw) / 2); transform: translateX(-50%); }
|
|
196
|
-
.viewport--top-center { top: calc(var(--toast-top, 0px) + var(--toast-inset)); }
|
|
197
|
-
.viewport--bottom-center { bottom: calc(var(--toast-bottom, 0px) + var(--toast-inset)); }
|
|
193
|
+
.viewport--top-start { top: calc(var(--smrt-toast-viewport-top, 0px) + var(--smrt-toast-viewport-inset)); left: calc(var(--smrt-toast-viewport-left, 0px) + var(--smrt-toast-viewport-inset)); }
|
|
194
|
+
.viewport--top-end { top: calc(var(--smrt-toast-viewport-top, 0px) + var(--smrt-toast-viewport-inset)); right: calc(var(--smrt-toast-viewport-right, 0px) + var(--smrt-toast-viewport-inset)); }
|
|
195
|
+
.viewport--bottom-start { bottom: calc(var(--smrt-toast-viewport-bottom, 0px) + var(--smrt-toast-viewport-inset)); left: calc(var(--smrt-toast-viewport-left, 0px) + var(--smrt-toast-viewport-inset)); }
|
|
196
|
+
.viewport--bottom-end { right: calc(var(--smrt-toast-viewport-right, 0px) + var(--smrt-toast-viewport-inset)); bottom: calc(var(--smrt-toast-viewport-bottom, 0px) + var(--smrt-toast-viewport-inset)); }
|
|
197
|
+
.viewport--top-center, .viewport--bottom-center { left: calc(var(--smrt-toast-viewport-left, 0px) + var(--smrt-toast-viewport-region-width, 100vw) / 2); transform: translateX(-50%); }
|
|
198
|
+
.viewport--top-center { top: calc(var(--smrt-toast-viewport-top, 0px) + var(--smrt-toast-viewport-inset)); }
|
|
199
|
+
.viewport--bottom-center { bottom: calc(var(--smrt-toast-viewport-bottom, 0px) + var(--smrt-toast-viewport-inset)); }
|
|
198
200
|
button { padding: var(--smrt-spacing-1) var(--smrt-spacing-2); border: 1px solid currentColor; border-radius: var(--smrt-radius-small); background: transparent; color: inherit; font: inherit; cursor: pointer; }
|
|
201
|
+
}
|
|
199
202
|
</style>
|
|
@@ -144,10 +144,10 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
144
144
|
}
|
|
145
145
|
</script>
|
|
146
146
|
|
|
147
|
-
<div class="working-strip__live" aria-live="polite" aria-atomic="true">
|
|
147
|
+
<div class="working-strip__live" aria-live="polite" aria-atomic="true" data-smrt-component="WorkingStrip">
|
|
148
148
|
{politeText}
|
|
149
149
|
</div>
|
|
150
|
-
<div class="working-strip__live" aria-live="assertive" aria-atomic="true">
|
|
150
|
+
<div class="working-strip__live" aria-live="assertive" aria-atomic="true" data-smrt-component="WorkingStrip">
|
|
151
151
|
{visible && assertive ? accessibleSummary : ''}
|
|
152
152
|
</div>
|
|
153
153
|
|
|
@@ -157,7 +157,7 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
157
157
|
class="working-strip working-strip--{variant}"
|
|
158
158
|
data-phase={phase}
|
|
159
159
|
data-testid="working-strip"
|
|
160
|
-
onkeydown={handleKeydown}
|
|
160
|
+
onkeydown={handleKeydown} data-smrt-component="WorkingStrip"
|
|
161
161
|
>
|
|
162
162
|
{#snippet content()}
|
|
163
163
|
<span class="working-strip__icon" aria-hidden="true">
|
|
@@ -243,6 +243,8 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
243
243
|
{/if}
|
|
244
244
|
|
|
245
245
|
<style>
|
|
246
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
247
|
+
@layer smrt.theme {
|
|
246
248
|
.working-strip__live,
|
|
247
249
|
.working-strip__sr {
|
|
248
250
|
position: absolute;
|
|
@@ -423,4 +425,5 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
423
425
|
border-inline-start-color: currentColor;
|
|
424
426
|
}
|
|
425
427
|
}
|
|
428
|
+
}
|
|
426
429
|
</style>
|
|
@@ -451,7 +451,7 @@ useControlRegistration(() => {
|
|
|
451
451
|
data-smrt-control={controlId}
|
|
452
452
|
data-smrt-form={interactionContext?.formId}
|
|
453
453
|
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
454
|
-
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}
|
|
454
|
+
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id} data-smrt-component="CameraCapture"
|
|
455
455
|
>
|
|
456
456
|
<div class="stage" class:empty={cameraState !== 'streaming' && !previewUrl}>
|
|
457
457
|
<video
|
|
@@ -524,6 +524,8 @@ useControlRegistration(() => {
|
|
|
524
524
|
</div>
|
|
525
525
|
|
|
526
526
|
<style>
|
|
527
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
528
|
+
@layer smrt.theme {
|
|
527
529
|
.camera-capture {
|
|
528
530
|
display: grid;
|
|
529
531
|
gap: var(--smrt-spacing-3);
|
|
@@ -578,8 +580,8 @@ useControlRegistration(() => {
|
|
|
578
580
|
justify-content: center;
|
|
579
581
|
/* Capture is a touch flow: its actions are touch targets at every
|
|
580
582
|
density, on the shared scale (smrt#3252). */
|
|
581
|
-
min-width: var(--smrt-touch-target-min
|
|
582
|
-
min-height: var(--smrt-touch-target-min
|
|
583
|
+
min-width: var(--smrt-touch-target-min);
|
|
584
|
+
min-height: var(--smrt-touch-target-min);
|
|
583
585
|
padding: 0 var(--smrt-spacing-4);
|
|
584
586
|
border: 1px solid var(--smrt-color-outline);
|
|
585
587
|
border-radius: var(--smrt-radius-small);
|
|
@@ -616,4 +618,5 @@ useControlRegistration(() => {
|
|
|
616
618
|
outline: 3px solid var(--smrt-color-tertiary);
|
|
617
619
|
outline-offset: 4px;
|
|
618
620
|
}
|
|
621
|
+
}
|
|
619
622
|
</style>
|
|
@@ -130,7 +130,7 @@ useControlRegistration(() => {
|
|
|
130
130
|
data-smrt-control={controlId}
|
|
131
131
|
data-smrt-form={interactionContext?.formId}
|
|
132
132
|
data-smrt-subject-type={resolvedInteraction === false ? undefined : resolvedInteraction.subject?.type}
|
|
133
|
-
data-smrt-subject-id={resolvedInteraction === false ? undefined : resolvedInteraction.subject?.id}
|
|
133
|
+
data-smrt-subject-id={resolvedInteraction === false ? undefined : resolvedInteraction.subject?.id} data-smrt-component="Checkbox"
|
|
134
134
|
>
|
|
135
135
|
<input
|
|
136
136
|
bind:this={inputEl}
|
|
@@ -154,6 +154,8 @@ useControlRegistration(() => {
|
|
|
154
154
|
</label>
|
|
155
155
|
|
|
156
156
|
<style>
|
|
157
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
158
|
+
@layer smrt.theme {
|
|
157
159
|
/* The visible box stays 18px. A transparent 44x44 hit area (WCAG 2.5.8 / M3 touch target) is
|
|
158
160
|
centred on it with ::before, so clicks nearby still land on the wrapping <label>. It adds no
|
|
159
161
|
layout. The box and the label text sit above every hit area (z-index 1 over 0), so one
|
|
@@ -162,22 +164,22 @@ useControlRegistration(() => {
|
|
|
162
164
|
checkbox stands alone in its parent. Beside anything else (a row title, a link, other text)
|
|
163
165
|
it keeps to the box's own column and grows vertically only. Resize it with
|
|
164
166
|
--smrt-control-hit-size (0px turns it off). */
|
|
165
|
-
.checkbox { --
|
|
166
|
-
.checkbox::before { content: ''; position: absolute; z-index: 0; inset-block-start: 50%; inset-inline-start: calc(var(--
|
|
167
|
+
.checkbox { --smrt-checkbox-box: 1.125rem; --smrt-checkbox-hit: max(var(--smrt-control-hit-size, 2.75rem), var(--smrt-checkbox-box)); position: relative; display: inline-flex; align-items: center; gap: var(--smrt-spacing-2, .5rem); cursor: pointer; color: var(--smrt-color-on-surface); }
|
|
168
|
+
.checkbox::before { content: ''; position: absolute; z-index: 0; inset-block-start: 50%; inset-inline-start: calc(var(--smrt-checkbox-box) / 2); inline-size: var(--smrt-checkbox-hit); block-size: var(--smrt-checkbox-hit); margin-block-start: calc(var(--smrt-checkbox-hit) / -2); margin-inline-start: calc(var(--smrt-checkbox-hit) / -2); }
|
|
167
169
|
.checkbox--disabled { opacity: .5; cursor: not-allowed; }
|
|
168
170
|
input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
|
|
169
|
-
.checkbox__box { position: relative; z-index: 1; width: 1.125rem; height: 1.125rem; display: grid; place-items: center; border: 2px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-extra-small
|
|
171
|
+
.checkbox__box { position: relative; z-index: 1; width: 1.125rem; height: 1.125rem; display: grid; place-items: center; border: 2px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-extra-small); background: var(--smrt-color-surface); transition: background var(--smrt-duration-short2), border-color var(--smrt-duration-short2); }
|
|
170
172
|
.checkbox__label { position: relative; z-index: 1; }
|
|
171
173
|
input:checked + .checkbox__box, input:indeterminate + .checkbox__box { background: var(--smrt-color-primary); border-color: var(--smrt-color-primary); color: var(--smrt-color-on-primary); }
|
|
172
174
|
input:focus-visible + .checkbox__box { outline: 2px solid var(--smrt-color-primary); outline-offset: 3px; }
|
|
173
175
|
.checkbox__check { font-size: .8rem; font-weight: 800; line-height: 1; }
|
|
174
176
|
.checkbox__dash { width: .6rem; height: 2px; background: currentColor; }
|
|
175
|
-
.checkbox:not(:only-child)::before { inline-size: var(--
|
|
177
|
+
.checkbox:not(:only-child)::before { inline-size: var(--smrt-checkbox-box); margin-inline-start: calc(var(--smrt-checkbox-box) / -2); }
|
|
176
178
|
.checkbox[data-smrt-highlighted='true'] { outline: 3px solid var(--smrt-color-tertiary); outline-offset: 4px; border-radius: var(--smrt-radius-small); }
|
|
177
179
|
|
|
178
180
|
/* Table cells: neighbouring cells hold links and other controls, so the hit area never leaves
|
|
179
181
|
the cell's column. It grows vertically only (box wide)... */
|
|
180
|
-
:global(:is(td, th)) .checkbox::before { inline-size: var(--
|
|
182
|
+
:global(:is(td, th)) .checkbox::before { inline-size: var(--smrt-checkbox-box); margin-inline-start: calc(var(--smrt-checkbox-box) / -2); }
|
|
181
183
|
/* ...unless the checkbox is the cell's only content: then the whole cell, clipped to its own
|
|
182
184
|
edges, is the hit area (the 44px target the header and every row share). The cell only needs
|
|
183
185
|
a containing block, so :where() keeps that rule at zero specificity: a sticky header or a
|
|
@@ -188,7 +190,8 @@ useControlRegistration(() => {
|
|
|
188
190
|
|
|
189
191
|
@media (prefers-reduced-motion: reduce) { .checkbox__box { transition: none; } }
|
|
190
192
|
|
|
191
|
-
.checkbox[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min
|
|
193
|
+
.checkbox[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min); }
|
|
192
194
|
.checkbox[data-density='comfortable'] { --smrt-control-target-min: 0px; }
|
|
193
195
|
.checkbox { min-height: var(--smrt-control-target-min, 0px); min-width: var(--smrt-control-target-min, 0px); }
|
|
196
|
+
}
|
|
194
197
|
</style>
|
|
@@ -334,7 +334,7 @@ useControlRegistration(() => {
|
|
|
334
334
|
</script>
|
|
335
335
|
<div bind:this={rootEl} class="combobox {className}" data-smrt-control={controlId} data-smrt-form={interactionContext?.formId}
|
|
336
336
|
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
337
|
-
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}>
|
|
337
|
+
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id} data-smrt-component="Combobox">
|
|
338
338
|
<FieldLabel for={inputId} {label} {required} />
|
|
339
339
|
<!-- The form posts the committed value (an option id), never the label the person sees. -->
|
|
340
340
|
{#if name}<input type="hidden" {name} {value} {disabled} />{/if}
|
|
@@ -347,6 +347,8 @@ useControlRegistration(() => {
|
|
|
347
347
|
{#if status !== undefined}<div class="sr-status" role="status" aria-live="polite">{open ? status : ''}</div>{/if}
|
|
348
348
|
</div>
|
|
349
349
|
<style>
|
|
350
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
351
|
+
@layer smrt.theme {
|
|
350
352
|
.combobox { position: relative; display: grid; gap: 0; color: var(--smrt-color-on-surface); }
|
|
351
353
|
input { box-sizing: border-box; width: 100%; padding: var(--smrt-spacing-2) var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-small); background: var(--smrt-color-surface); color: inherit; }
|
|
352
354
|
input:focus { outline: 2px solid var(--smrt-color-primary); outline-offset: 1px; } .options { position: absolute; z-index: var(--smrt-z-index-dropdown); top: 100%; left: 0; right: 0; display: grid; padding: var(--smrt-spacing-1); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-small); background: var(--smrt-color-surface-container); box-shadow: var(--smrt-elevation-2); }
|
|
@@ -354,4 +356,5 @@ useControlRegistration(() => {
|
|
|
354
356
|
.options.empty { padding: var(--smrt-spacing-2) var(--smrt-spacing-3); color: var(--smrt-color-on-surface-variant); }
|
|
355
357
|
.sr-status { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
|
|
356
358
|
:global(.combobox[data-smrt-highlighted='true']) { outline: 3px solid var(--smrt-color-tertiary); outline-offset: 4px; }
|
|
359
|
+
}
|
|
357
360
|
</style>
|
|
@@ -25,5 +25,10 @@ let {
|
|
|
25
25
|
const instanceId = $props.id();
|
|
26
26
|
const resolvedId = $derived(id ?? `smrt-date-${instanceId}`);
|
|
27
27
|
</script>
|
|
28
|
-
<label class="picker {className}" for={resolvedId}><span>{label}</span><Input id={resolvedId} {name} type="date" aria-label={label} {interaction} bind:value {...rest} /></label>
|
|
29
|
-
<style
|
|
28
|
+
<label class="picker {className}" for={resolvedId} data-smrt-component="DatePicker"><span>{label}</span><Input id={resolvedId} {name} type="date" 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>
|
|
@@ -118,10 +118,12 @@ function handleClick() {
|
|
|
118
118
|
{/if}
|
|
119
119
|
</Button>
|
|
120
120
|
{#if hint !== name}
|
|
121
|
-
<span id={helpId} class="smrt-dictation-help">{hint}</span>
|
|
121
|
+
<span id={helpId} class="smrt-dictation-help" data-smrt-component="DictationButton">{hint}</span>
|
|
122
122
|
{/if}
|
|
123
123
|
|
|
124
124
|
<style>
|
|
125
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
126
|
+
@layer smrt.theme {
|
|
125
127
|
:global(.smrt-dictation-button) {
|
|
126
128
|
position: relative;
|
|
127
129
|
flex-shrink: 0;
|
|
@@ -132,13 +134,13 @@ function handleClick() {
|
|
|
132
134
|
block-size: 44px;
|
|
133
135
|
min-inline-size: 44px;
|
|
134
136
|
padding: 0;
|
|
135
|
-
border-radius: var(--smrt-radius-full
|
|
136
|
-
color: var(--smrt-color-on-surface-variant
|
|
137
|
+
border-radius: var(--smrt-radius-full);
|
|
138
|
+
color: var(--smrt-color-on-surface-variant);
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
:global(.smrt-dictation-button--listening) {
|
|
140
|
-
background: var(--smrt-color-error-container
|
|
141
|
-
color: var(--smrt-color-on-error-container
|
|
142
|
+
background: var(--smrt-color-error-container);
|
|
143
|
+
color: var(--smrt-color-on-error-container);
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
/* Read out with the button's name; never shown. */
|
|
@@ -158,22 +160,22 @@ function handleClick() {
|
|
|
158
160
|
inline-size: 10px;
|
|
159
161
|
block-size: 10px;
|
|
160
162
|
border-radius: 50%;
|
|
161
|
-
background: var(--smrt-color-error
|
|
163
|
+
background: var(--smrt-color-error);
|
|
162
164
|
animation: smrt-dictation-pulse 1.2s ease-in-out infinite;
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
/* Hands-free: a steady ring while listening ... */
|
|
166
168
|
:global(.smrt-dictation-button--hands-free) {
|
|
167
|
-
box-shadow: 0 0 0 2px var(--smrt-color-error
|
|
169
|
+
box-shadow: 0 0 0 2px var(--smrt-color-error);
|
|
168
170
|
}
|
|
169
171
|
|
|
170
172
|
/* ... and a halo that swells with the voice while someone is speaking. */
|
|
171
173
|
:global(.smrt-dictation-button--speaking) {
|
|
172
174
|
box-shadow:
|
|
173
|
-
0 0 0 3px var(--smrt-color-error
|
|
175
|
+
0 0 0 3px var(--smrt-color-error),
|
|
174
176
|
0 0 0
|
|
175
177
|
calc(4px + 10px * var(--smrt-dictation-level, 0))
|
|
176
|
-
color-mix(in srgb, var(--smrt-color-error
|
|
178
|
+
color-mix(in srgb, var(--smrt-color-error) 28%, transparent);
|
|
177
179
|
transition: box-shadow 80ms linear;
|
|
178
180
|
}
|
|
179
181
|
|
|
@@ -181,7 +183,7 @@ function handleClick() {
|
|
|
181
183
|
:global(.smrt-dictation-button--paused) {
|
|
182
184
|
opacity: 0.6;
|
|
183
185
|
box-shadow: none;
|
|
184
|
-
outline: 2px dashed var(--smrt-color-outline
|
|
186
|
+
outline: 2px dashed var(--smrt-color-outline);
|
|
185
187
|
outline-offset: -2px;
|
|
186
188
|
}
|
|
187
189
|
|
|
@@ -198,9 +200,9 @@ function handleClick() {
|
|
|
198
200
|
inline-size: 10px;
|
|
199
201
|
block-size: 10px;
|
|
200
202
|
border-radius: 50%;
|
|
201
|
-
border: 2px solid var(--smrt-color-outline-variant
|
|
202
|
-
border-block-start-color: var(--smrt-color-primary
|
|
203
|
-
background: var(--smrt-color-surface
|
|
203
|
+
border: 2px solid var(--smrt-color-outline-variant);
|
|
204
|
+
border-block-start-color: var(--smrt-color-primary);
|
|
205
|
+
background: var(--smrt-color-surface);
|
|
204
206
|
animation: smrt-dictation-spin 0.9s linear infinite;
|
|
205
207
|
}
|
|
206
208
|
|
|
@@ -229,7 +231,8 @@ function handleClick() {
|
|
|
229
231
|
/* Still ringed, but the halo no longer animates with the voice. */
|
|
230
232
|
:global(.smrt-dictation-button--speaking) {
|
|
231
233
|
transition: none;
|
|
232
|
-
box-shadow: 0 0 0 4px var(--smrt-color-error
|
|
234
|
+
box-shadow: 0 0 0 4px var(--smrt-color-error);
|
|
233
235
|
}
|
|
234
236
|
}
|
|
237
|
+
}
|
|
235
238
|
</style>
|
|
@@ -71,7 +71,7 @@ function errorText(kind: DictationErrorKind | null): string {
|
|
|
71
71
|
}
|
|
72
72
|
</script>
|
|
73
73
|
|
|
74
|
-
<div class={`smrt-dictation-status ${className}`.trim()}>
|
|
74
|
+
<div class={`smrt-dictation-status ${className}`.trim()} data-smrt-component="DictationStatus">
|
|
75
75
|
<p
|
|
76
76
|
class="smrt-dictation-status-line"
|
|
77
77
|
class:smrt-dictation-status--empty={!showLine || announceOnly}
|
|
@@ -118,6 +118,8 @@ function errorText(kind: DictationErrorKind | null): string {
|
|
|
118
118
|
</div>
|
|
119
119
|
|
|
120
120
|
<style>
|
|
121
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
122
|
+
@layer smrt.theme {
|
|
121
123
|
.smrt-dictation-status {
|
|
122
124
|
display: contents;
|
|
123
125
|
}
|
|
@@ -135,7 +137,7 @@ function errorText(kind: DictationErrorKind | null): string {
|
|
|
135
137
|
align-items: center;
|
|
136
138
|
gap: 0.4rem;
|
|
137
139
|
padding: 0.25rem 0;
|
|
138
|
-
color: var(--smrt-color-on-surface
|
|
140
|
+
color: var(--smrt-color-on-surface);
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
/* Kept mounted while empty (live regions must exist before they speak),
|
|
@@ -154,15 +156,15 @@ function errorText(kind: DictationErrorKind | null): string {
|
|
|
154
156
|
inline-size: 8px;
|
|
155
157
|
block-size: 8px;
|
|
156
158
|
border-radius: 50%;
|
|
157
|
-
background: var(--smrt-color-error
|
|
159
|
+
background: var(--smrt-color-error);
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
.smrt-dictation-status-spinner {
|
|
161
163
|
inline-size: 12px;
|
|
162
164
|
block-size: 12px;
|
|
163
165
|
border-radius: 50%;
|
|
164
|
-
border: 2px solid var(--smrt-color-outline-variant
|
|
165
|
-
border-block-start-color: var(--smrt-color-primary
|
|
166
|
+
border: 2px solid var(--smrt-color-outline-variant);
|
|
167
|
+
border-block-start-color: var(--smrt-color-primary);
|
|
166
168
|
animation: smrt-dictation-spin 0.9s linear infinite;
|
|
167
169
|
}
|
|
168
170
|
|
|
@@ -179,14 +181,15 @@ function errorText(kind: DictationErrorKind | null): string {
|
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
.smrt-dictation-status-interim {
|
|
182
|
-
color: var(--smrt-color-on-surface-variant
|
|
184
|
+
color: var(--smrt-color-on-surface-variant);
|
|
183
185
|
font-style: italic;
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
.smrt-dictation-status-error {
|
|
187
189
|
padding: 0.4rem 0.6rem;
|
|
188
|
-
border-radius: var(--smrt-radius-medium
|
|
189
|
-
background: var(--smrt-color-error-container
|
|
190
|
-
color: var(--smrt-color-on-error-container
|
|
190
|
+
border-radius: var(--smrt-radius-medium);
|
|
191
|
+
background: var(--smrt-color-error-container);
|
|
192
|
+
color: var(--smrt-color-on-error-container);
|
|
191
193
|
}
|
|
194
|
+
}
|
|
192
195
|
</style>
|
|
@@ -28,9 +28,12 @@ function select(error: FormError) {
|
|
|
28
28
|
onselect?.(error.controlId);
|
|
29
29
|
}
|
|
30
30
|
</script>
|
|
31
|
-
{#if errors.length > 0}<section class="error-summary {className}" role="alert" aria-labelledby={titleId}><h2 id={titleId}>{title}</h2><ul>{#each errors as error}<li><button type="button" onclick={() => select(error)}>{error.label ? `${error.label}: ` : ''}{error.message}</button></li>{/each}</ul></section>{/if}
|
|
31
|
+
{#if errors.length > 0}<section class="error-summary {className}" role="alert" aria-labelledby={titleId} data-smrt-component="ErrorSummary"><h2 id={titleId}>{title}</h2><ul>{#each errors as error}<li><button type="button" onclick={() => select(error)}>{error.label ? `${error.label}: ` : ''}{error.message}</button></li>{/each}</ul></section>{/if}
|
|
32
32
|
<style>
|
|
33
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
34
|
+
@layer smrt.theme {
|
|
33
35
|
.error-summary { padding: var(--smrt-spacing-4); border-inline-start: 4px solid var(--smrt-color-error); border-radius: var(--smrt-radius-small); background: var(--smrt-color-error-container); color: var(--smrt-color-on-error-container); }
|
|
34
36
|
h2 { margin: 0 0 var(--smrt-spacing-2); font: var(--smrt-typography-title-small-font); } ul { margin: 0; padding-inline-start: var(--smrt-spacing-5); }
|
|
35
37
|
button { padding: 0; border: 0; background: transparent; color: inherit; text-decoration: underline; cursor: pointer; }
|
|
38
|
+
}
|
|
36
39
|
</style>
|
|
@@ -19,26 +19,29 @@ let { label, for: forId, id, required = false }: Props = $props();
|
|
|
19
19
|
</script>
|
|
20
20
|
|
|
21
21
|
{#if forId}
|
|
22
|
-
<label {id} for={forId} class="smrt-field-label">{label}{#if required}<span class="required" aria-hidden="true">*</span>{/if}</label>
|
|
22
|
+
<label {id} for={forId} class="smrt-field-label" data-smrt-component="FieldLabel">{label}{#if required}<span class="required" aria-hidden="true">*</span>{/if}</label>
|
|
23
23
|
{:else}
|
|
24
|
-
<span {id} class="smrt-field-label">{label}{#if required}<span class="required" aria-hidden="true">*</span>{/if}</span>
|
|
24
|
+
<span {id} class="smrt-field-label" data-smrt-component="FieldLabel">{label}{#if required}<span class="required" aria-hidden="true">*</span>{/if}</span>
|
|
25
25
|
{/if}
|
|
26
26
|
|
|
27
27
|
<style>
|
|
28
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
29
|
+
@layer smrt.theme {
|
|
28
30
|
.smrt-field-label {
|
|
29
31
|
display: block;
|
|
30
|
-
margin-bottom: var(--smrt-spacing-1
|
|
32
|
+
margin-bottom: var(--smrt-spacing-1);
|
|
31
33
|
font-size: var(--smrt-typography-label-large-size, 0.875rem);
|
|
32
34
|
font-weight: var(--smrt-typography-weight-medium, 500);
|
|
33
35
|
line-height: var(--smrt-typography-label-large-line-height, 1.4);
|
|
34
36
|
letter-spacing: normal;
|
|
35
37
|
text-transform: none;
|
|
36
38
|
font-family: inherit;
|
|
37
|
-
color: var(--smrt-color-on-surface
|
|
39
|
+
color: var(--smrt-color-on-surface);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
.required {
|
|
41
|
-
color: var(--smrt-color-error
|
|
42
|
-
margin-left: var(--smrt-spacing-1
|
|
43
|
+
color: var(--smrt-color-error);
|
|
44
|
+
margin-left: var(--smrt-spacing-1);
|
|
43
45
|
}
|
|
46
|
+
}
|
|
44
47
|
</style>
|
|
@@ -30,12 +30,15 @@ const descriptionId = $derived(
|
|
|
30
30
|
);
|
|
31
31
|
const errorId = $derived(error ? `fieldset-${instanceId}-error` : undefined);
|
|
32
32
|
</script>
|
|
33
|
-
<fieldset class="fieldset {className}" aria-describedby={[descriptionId, errorId].filter(Boolean).join(' ') || undefined} {...rest}>
|
|
33
|
+
<fieldset class="fieldset {className}" aria-describedby={[descriptionId, errorId].filter(Boolean).join(' ') || undefined} {...rest} data-smrt-component="Fieldset">
|
|
34
34
|
<legend>{legend}</legend>{#if description}<p id={descriptionId} class="description">{description}</p>{/if}<div class="content" class:content--stack={stack}>{@render children()}</div>{#if error}<p id={errorId} class="error" role="alert">{error}</p>{/if}
|
|
35
35
|
</fieldset>
|
|
36
36
|
<style>
|
|
37
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
38
|
+
@layer smrt.theme {
|
|
37
39
|
.fieldset { margin: 0; padding: var(--smrt-spacing-4); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-medium); }
|
|
38
40
|
legend { padding: 0 var(--smrt-spacing-2); color: var(--smrt-color-on-surface); font: var(--smrt-typography-title-small-font); }
|
|
39
41
|
.content--stack { display: grid; gap: var(--smrt-spacing-4); }
|
|
40
42
|
.description, .error { margin: 0 0 var(--smrt-spacing-3); font: var(--smrt-typography-body-small-font); color: var(--smrt-color-on-surface-variant); } .error { margin: var(--smrt-spacing-3) 0 0; color: var(--smrt-color-error); }
|
|
43
|
+
}
|
|
41
44
|
</style>
|
|
@@ -111,11 +111,13 @@ useControlRegistration(() => {
|
|
|
111
111
|
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
112
112
|
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}
|
|
113
113
|
ondragenter={(event) => { event.preventDefault(); dragging = true; }}
|
|
114
|
-
ondragover={(event) => event.preventDefault()} ondragleave={() => dragging = false} ondrop={handleDrop}>
|
|
114
|
+
ondragover={(event) => event.preventDefault()} ondragleave={() => dragging = false} ondrop={handleDrop} data-smrt-component="FilePicker">
|
|
115
115
|
<input bind:this={inputEl} id={resolvedId} type="file" {name} {accept} {multiple} {disabled} {required} onchange={handleChange} {...rest} />
|
|
116
116
|
<span class="label">{label}</span><span class="description">{files.length ? `${files.length} file${files.length === 1 ? '' : 's'} selected` : description}</span>
|
|
117
117
|
</label>
|
|
118
118
|
<style>
|
|
119
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
120
|
+
@layer smrt.theme {
|
|
119
121
|
.file-picker { display: inline-flex; flex-direction: column; gap: var(--smrt-spacing-1); padding: var(--smrt-spacing-3) var(--smrt-spacing-4); border: 1px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-small); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); cursor: pointer; }
|
|
120
122
|
.file-picker.dropzone { width: 100%; min-height: 8rem; align-items: center; justify-content: center; border-style: dashed; text-align: center; }
|
|
121
123
|
.file-picker.dragging { border-color: var(--smrt-color-primary); background: var(--smrt-color-primary-container); }
|
|
@@ -123,4 +125,5 @@ useControlRegistration(() => {
|
|
|
123
125
|
input:focus-visible ~ .label { outline: 2px solid var(--smrt-color-primary); outline-offset: 3px; }
|
|
124
126
|
.label { font: var(--smrt-typography-label-large-font); } .description { font: var(--smrt-typography-body-small-font); color: var(--smrt-color-on-surface-variant); }
|
|
125
127
|
.file-picker[data-smrt-highlighted='true'] { outline: 3px solid var(--smrt-color-tertiary); outline-offset: 4px; }
|
|
128
|
+
}
|
|
126
129
|
</style>
|
|
@@ -152,7 +152,7 @@ function handleChange(event: Event & { currentTarget: HTMLFormElement }) {
|
|
|
152
152
|
{onclick}
|
|
153
153
|
oninput={handleInput}
|
|
154
154
|
onchange={handleChange}
|
|
155
|
-
{...rest}
|
|
155
|
+
{...rest} data-smrt-component="Form"
|
|
156
156
|
>
|
|
157
157
|
{@render children()}
|
|
158
158
|
<StagedControlReview
|