@synthaxai/ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +262 -0
- package/dist/app.css +2 -0
- package/dist/app.html +12 -0
- package/dist/data-display/DataTable/DataTable.svelte +773 -0
- package/dist/data-display/DataTable/DataTable.svelte.d.ts +120 -0
- package/dist/data-display/DataTable/DataTable.svelte.d.ts.map +1 -0
- package/dist/data-display/DataTable/index.d.ts +2 -0
- package/dist/data-display/DataTable/index.d.ts.map +1 -0
- package/dist/data-display/DataTable/index.js +1 -0
- package/dist/data-display/StatCard/StatCard.svelte +409 -0
- package/dist/data-display/StatCard/StatCard.svelte.d.ts +63 -0
- package/dist/data-display/StatCard/StatCard.svelte.d.ts.map +1 -0
- package/dist/data-display/StatCard/index.d.ts +2 -0
- package/dist/data-display/StatCard/index.d.ts.map +1 -0
- package/dist/data-display/StatCard/index.js +1 -0
- package/dist/data-display/index.d.ts +8 -0
- package/dist/data-display/index.d.ts.map +1 -0
- package/dist/data-display/index.js +7 -0
- package/dist/dialogs/ConfirmDialog/ConfirmDialog.svelte +693 -0
- package/dist/dialogs/ConfirmDialog/ConfirmDialog.svelte.d.ts +66 -0
- package/dist/dialogs/ConfirmDialog/ConfirmDialog.svelte.d.ts.map +1 -0
- package/dist/dialogs/ConfirmDialog/index.d.ts +2 -0
- package/dist/dialogs/ConfirmDialog/index.d.ts.map +1 -0
- package/dist/dialogs/ConfirmDialog/index.js +1 -0
- package/dist/dialogs/Modal/Modal.svelte +441 -0
- package/dist/dialogs/Modal/Modal.svelte.d.ts +69 -0
- package/dist/dialogs/Modal/Modal.svelte.d.ts.map +1 -0
- package/dist/dialogs/Modal/index.d.ts +2 -0
- package/dist/dialogs/Modal/index.d.ts.map +1 -0
- package/dist/dialogs/Modal/index.js +1 -0
- package/dist/dialogs/index.d.ts +8 -0
- package/dist/dialogs/index.d.ts.map +1 -0
- package/dist/dialogs/index.js +7 -0
- package/dist/feedback/Alert/Alert.svelte +565 -0
- package/dist/feedback/Alert/Alert.svelte.d.ts +60 -0
- package/dist/feedback/Alert/Alert.svelte.d.ts.map +1 -0
- package/dist/feedback/Alert/index.d.ts +2 -0
- package/dist/feedback/Alert/index.d.ts.map +1 -0
- package/dist/feedback/Alert/index.js +1 -0
- package/dist/feedback/EmptyState/EmptyState.svelte +377 -0
- package/dist/feedback/EmptyState/EmptyState.svelte.d.ts +63 -0
- package/dist/feedback/EmptyState/EmptyState.svelte.d.ts.map +1 -0
- package/dist/feedback/EmptyState/index.d.ts +2 -0
- package/dist/feedback/EmptyState/index.d.ts.map +1 -0
- package/dist/feedback/EmptyState/index.js +1 -0
- package/dist/feedback/ProgressBar/ProgressBar.svelte +585 -0
- package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts +68 -0
- package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts.map +1 -0
- package/dist/feedback/ProgressBar/index.d.ts +2 -0
- package/dist/feedback/ProgressBar/index.d.ts.map +1 -0
- package/dist/feedback/ProgressBar/index.js +1 -0
- package/dist/feedback/Skeleton/Skeleton.svelte +568 -0
- package/dist/feedback/Skeleton/Skeleton.svelte.d.ts +54 -0
- package/dist/feedback/Skeleton/Skeleton.svelte.d.ts.map +1 -0
- package/dist/feedback/Skeleton/index.d.ts +2 -0
- package/dist/feedback/Skeleton/index.d.ts.map +1 -0
- package/dist/feedback/Skeleton/index.js +1 -0
- package/dist/feedback/Spinner/Spinner.svelte +434 -0
- package/dist/feedback/Spinner/Spinner.svelte.d.ts +49 -0
- package/dist/feedback/Spinner/Spinner.svelte.d.ts.map +1 -0
- package/dist/feedback/Spinner/index.d.ts +2 -0
- package/dist/feedback/Spinner/index.d.ts.map +1 -0
- package/dist/feedback/Spinner/index.js +1 -0
- package/dist/feedback/Toast/Toast.svelte +587 -0
- package/dist/feedback/Toast/Toast.svelte.d.ts +55 -0
- package/dist/feedback/Toast/Toast.svelte.d.ts.map +1 -0
- package/dist/feedback/Toast/ToastContainer.svelte +168 -0
- package/dist/feedback/Toast/ToastContainer.svelte.d.ts +28 -0
- package/dist/feedback/Toast/ToastContainer.svelte.d.ts.map +1 -0
- package/dist/feedback/Toast/index.d.ts +4 -0
- package/dist/feedback/Toast/index.d.ts.map +1 -0
- package/dist/feedback/Toast/index.js +3 -0
- package/dist/feedback/Toast/toast-store.d.ts +72 -0
- package/dist/feedback/Toast/toast-store.d.ts.map +1 -0
- package/dist/feedback/Toast/toast-store.js +157 -0
- package/dist/feedback/index.d.ts +13 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/index.js +12 -0
- package/dist/forms/Checkbox/Checkbox.svelte +404 -0
- package/dist/forms/Checkbox/Checkbox.svelte.d.ts +62 -0
- package/dist/forms/Checkbox/Checkbox.svelte.d.ts.map +1 -0
- package/dist/forms/Checkbox/index.d.ts +2 -0
- package/dist/forms/Checkbox/index.d.ts.map +1 -0
- package/dist/forms/Checkbox/index.js +1 -0
- package/dist/forms/FormField/FormField.svelte +299 -0
- package/dist/forms/FormField/FormField.svelte.d.ts +43 -0
- package/dist/forms/FormField/FormField.svelte.d.ts.map +1 -0
- package/dist/forms/FormField/index.d.ts +2 -0
- package/dist/forms/FormField/index.d.ts.map +1 -0
- package/dist/forms/FormField/index.js +1 -0
- package/dist/forms/RadioGroup/RadioGroup.svelte +418 -0
- package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts +70 -0
- package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts.map +1 -0
- package/dist/forms/RadioGroup/index.d.ts +2 -0
- package/dist/forms/RadioGroup/index.d.ts.map +1 -0
- package/dist/forms/RadioGroup/index.js +1 -0
- package/dist/forms/Select/Select.svelte +548 -0
- package/dist/forms/Select/Select.svelte.d.ts +74 -0
- package/dist/forms/Select/Select.svelte.d.ts.map +1 -0
- package/dist/forms/Select/index.d.ts +2 -0
- package/dist/forms/Select/index.d.ts.map +1 -0
- package/dist/forms/Select/index.js +1 -0
- package/dist/forms/TextInput/TextInput.svelte +628 -0
- package/dist/forms/TextInput/TextInput.svelte.d.ts +97 -0
- package/dist/forms/TextInput/TextInput.svelte.d.ts.map +1 -0
- package/dist/forms/TextInput/index.d.ts +2 -0
- package/dist/forms/TextInput/index.d.ts.map +1 -0
- package/dist/forms/TextInput/index.js +1 -0
- package/dist/forms/Textarea/Textarea.svelte +587 -0
- package/dist/forms/Textarea/Textarea.svelte.d.ts +71 -0
- package/dist/forms/Textarea/Textarea.svelte.d.ts.map +1 -0
- package/dist/forms/Textarea/index.d.ts +2 -0
- package/dist/forms/Textarea/index.d.ts.map +1 -0
- package/dist/forms/Textarea/index.js +1 -0
- package/dist/forms/index.d.ts +13 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/index.js +12 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/layout/Card/Card.svelte +316 -0
- package/dist/layout/Card/Card.svelte.d.ts +63 -0
- package/dist/layout/Card/Card.svelte.d.ts.map +1 -0
- package/dist/layout/Card/index.d.ts +2 -0
- package/dist/layout/Card/index.d.ts.map +1 -0
- package/dist/layout/Card/index.js +1 -0
- package/dist/layout/Container/Container.svelte +252 -0
- package/dist/layout/Container/Container.svelte.d.ts +50 -0
- package/dist/layout/Container/Container.svelte.d.ts.map +1 -0
- package/dist/layout/Container/index.d.ts +2 -0
- package/dist/layout/Container/index.d.ts.map +1 -0
- package/dist/layout/Container/index.js +1 -0
- package/dist/layout/index.d.ts +8 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +7 -0
- package/dist/navigation/StepIndicator/StepIndicator.svelte +601 -0
- package/dist/navigation/StepIndicator/StepIndicator.svelte.d.ts +70 -0
- package/dist/navigation/StepIndicator/StepIndicator.svelte.d.ts.map +1 -0
- package/dist/navigation/StepIndicator/index.d.ts +2 -0
- package/dist/navigation/StepIndicator/index.d.ts.map +1 -0
- package/dist/navigation/StepIndicator/index.js +1 -0
- package/dist/navigation/index.d.ts +7 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +6 -0
- package/dist/primitives/Badge/Badge.svelte +365 -0
- package/dist/primitives/Badge/Badge.svelte.d.ts +39 -0
- package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -0
- package/dist/primitives/Badge/index.d.ts +2 -0
- package/dist/primitives/Badge/index.d.ts.map +1 -0
- package/dist/primitives/Badge/index.js +1 -0
- package/dist/primitives/Button/Button.svelte +430 -0
- package/dist/primitives/Button/Button.svelte.d.ts +50 -0
- package/dist/primitives/Button/Button.svelte.d.ts.map +1 -0
- package/dist/primitives/Button/index.d.ts +2 -0
- package/dist/primitives/Button/index.d.ts.map +1 -0
- package/dist/primitives/Button/index.js +1 -0
- package/dist/primitives/index.d.ts +9 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/index.js +8 -0
- package/dist/routes/+layout.svelte +12 -0
- package/dist/routes/+layout.svelte.d.ts +12 -0
- package/dist/routes/+layout.svelte.d.ts.map +1 -0
- package/dist/routes/+page.svelte +53 -0
- package/dist/routes/+page.svelte.d.ts +27 -0
- package/dist/routes/+page.svelte.d.ts.map +1 -0
- package/dist/styles/tokens.css +399 -0
- package/dist/types/index.d.ts +175 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/utils/accessibility.d.ts +103 -0
- package/dist/utils/accessibility.d.ts.map +1 -0
- package/dist/utils/accessibility.js +202 -0
- package/dist/utils/cn.d.ts +71 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/cn.js +61 -0
- package/dist/utils/form-styles.d.ts +76 -0
- package/dist/utils/form-styles.d.ts.map +1 -0
- package/dist/utils/form-styles.js +95 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +13 -0
- package/dist/utils/keyboard.d.ts +94 -0
- package/dist/utils/keyboard.d.ts.map +1 -0
- package/dist/utils/keyboard.js +179 -0
- package/package.json +119 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Button
|
|
3
|
+
|
|
4
|
+
A versatile button component with multiple variants, sizes, and states.
|
|
5
|
+
Follows WCAG 2.1 AA accessibility guidelines for healthcare applications.
|
|
6
|
+
|
|
7
|
+
@example
|
|
8
|
+
<Button variant="primary" size="md" onclick={() => handleClick()}>
|
|
9
|
+
Click me
|
|
10
|
+
</Button>
|
|
11
|
+
|
|
12
|
+
@example
|
|
13
|
+
<Button variant="secondary" disabled>
|
|
14
|
+
<Icon slot="icon-left" />
|
|
15
|
+
With Icon
|
|
16
|
+
</Button>
|
|
17
|
+
-->
|
|
18
|
+
<script lang="ts">
|
|
19
|
+
import type { Snippet } from 'svelte';
|
|
20
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
21
|
+
import { Loader2 } from 'lucide-svelte';
|
|
22
|
+
import { cn } from '../../utils/cn.js';
|
|
23
|
+
import type { Size, Variant } from '../../types/index.js';
|
|
24
|
+
|
|
25
|
+
type ButtonSize = Exclude<Size, 'xl'>;
|
|
26
|
+
type ButtonVariant = Variant | 'danger';
|
|
27
|
+
|
|
28
|
+
interface Props extends Omit<HTMLButtonAttributes, 'class'> {
|
|
29
|
+
/** Visual variant of the button */
|
|
30
|
+
variant?: ButtonVariant;
|
|
31
|
+
/** Size of the button */
|
|
32
|
+
size?: ButtonSize;
|
|
33
|
+
/** Whether the button takes full width */
|
|
34
|
+
fullWidth?: boolean;
|
|
35
|
+
/** Whether to show loading state */
|
|
36
|
+
loading?: boolean;
|
|
37
|
+
/** Loading text for screen readers (defaults to "Loading...") */
|
|
38
|
+
loadingText?: string;
|
|
39
|
+
/** Icon to display on the left */
|
|
40
|
+
iconLeft?: Snippet;
|
|
41
|
+
/** Icon to display on the right */
|
|
42
|
+
iconRight?: Snippet;
|
|
43
|
+
/** Whether this is an icon-only button (requires aria-label) */
|
|
44
|
+
iconOnly?: boolean;
|
|
45
|
+
/** Additional CSS classes */
|
|
46
|
+
class?: string;
|
|
47
|
+
/** Button content */
|
|
48
|
+
children?: Snippet;
|
|
49
|
+
/** Test ID for e2e testing (Playwright, Cypress) */
|
|
50
|
+
testId?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let {
|
|
54
|
+
variant = 'primary',
|
|
55
|
+
size = 'md',
|
|
56
|
+
fullWidth = false,
|
|
57
|
+
loading = false,
|
|
58
|
+
loadingText = 'Loading...',
|
|
59
|
+
disabled = false,
|
|
60
|
+
type = 'button',
|
|
61
|
+
iconLeft,
|
|
62
|
+
iconRight,
|
|
63
|
+
iconOnly = false,
|
|
64
|
+
class: className = '',
|
|
65
|
+
children,
|
|
66
|
+
testId,
|
|
67
|
+
...restProps
|
|
68
|
+
}: Props = $props();
|
|
69
|
+
|
|
70
|
+
const isDisabled = $derived(disabled || loading);
|
|
71
|
+
|
|
72
|
+
// Icon size based on button size
|
|
73
|
+
const iconSizes: Record<ButtonSize, number> = {
|
|
74
|
+
xs: 14,
|
|
75
|
+
sm: 16,
|
|
76
|
+
md: 18,
|
|
77
|
+
lg: 20
|
|
78
|
+
};
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<button
|
|
82
|
+
{type}
|
|
83
|
+
class={cn(
|
|
84
|
+
'btn',
|
|
85
|
+
`btn-${variant}`,
|
|
86
|
+
`btn-${size}`,
|
|
87
|
+
iconOnly && 'btn-icon-only',
|
|
88
|
+
fullWidth && !iconOnly && 'btn-full-width',
|
|
89
|
+
loading && 'btn-loading',
|
|
90
|
+
className
|
|
91
|
+
)}
|
|
92
|
+
disabled={isDisabled}
|
|
93
|
+
aria-disabled={isDisabled}
|
|
94
|
+
aria-busy={loading}
|
|
95
|
+
data-testid={testId}
|
|
96
|
+
{...restProps}
|
|
97
|
+
>
|
|
98
|
+
{#if loading}
|
|
99
|
+
<span class="btn-spinner" aria-hidden="true">
|
|
100
|
+
<Loader2 size={iconSizes[size]} />
|
|
101
|
+
</span>
|
|
102
|
+
<span class="sr-only">{loadingText}</span>
|
|
103
|
+
{/if}
|
|
104
|
+
|
|
105
|
+
<span class="btn-content" class:btn-content-hidden={loading}>
|
|
106
|
+
{#if iconLeft}
|
|
107
|
+
<span class="btn-icon" aria-hidden="true">
|
|
108
|
+
{@render iconLeft()}
|
|
109
|
+
</span>
|
|
110
|
+
{/if}
|
|
111
|
+
|
|
112
|
+
{#if children}
|
|
113
|
+
{@render children()}
|
|
114
|
+
{/if}
|
|
115
|
+
|
|
116
|
+
{#if iconRight}
|
|
117
|
+
<span class="btn-icon" aria-hidden="true">
|
|
118
|
+
{@render iconRight()}
|
|
119
|
+
</span>
|
|
120
|
+
{/if}
|
|
121
|
+
</span>
|
|
122
|
+
</button>
|
|
123
|
+
|
|
124
|
+
<style>
|
|
125
|
+
/* Base Button Styles */
|
|
126
|
+
.btn {
|
|
127
|
+
position: relative;
|
|
128
|
+
display: inline-flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
gap: 0.5rem;
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
border: none;
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
transition: all 0.2s ease;
|
|
136
|
+
-webkit-tap-highlight-color: transparent;
|
|
137
|
+
user-select: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.btn:focus-visible {
|
|
141
|
+
outline: none;
|
|
142
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-primary) / 0.4);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Dark mode: same style, brighter color for visibility */
|
|
146
|
+
:global([data-theme='dark']) .btn:focus-visible {
|
|
147
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-primary-light) / 0.5);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@media (prefers-color-scheme: dark) {
|
|
151
|
+
:global(:root:not([data-theme='light'])) .btn:focus-visible {
|
|
152
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-primary-light) / 0.5);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Variant-specific focus rings */
|
|
157
|
+
.btn-danger:focus-visible {
|
|
158
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-error) / 0.4);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
:global([data-theme='dark']) .btn-danger:focus-visible {
|
|
162
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-error-light) / 0.5);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@media (prefers-color-scheme: dark) {
|
|
166
|
+
:global(:root:not([data-theme='light'])) .btn-danger:focus-visible {
|
|
167
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-error-light) / 0.5);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.btn:disabled {
|
|
172
|
+
opacity: 0.5;
|
|
173
|
+
cursor: not-allowed;
|
|
174
|
+
transform: none !important;
|
|
175
|
+
box-shadow: none !important;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Size Variants */
|
|
179
|
+
.btn-xs {
|
|
180
|
+
height: 1.75rem;
|
|
181
|
+
padding: 0 0.625rem;
|
|
182
|
+
font-size: 0.75rem;
|
|
183
|
+
border-radius: 0.375rem;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.btn-sm {
|
|
187
|
+
height: 2rem;
|
|
188
|
+
padding: 0 0.875rem;
|
|
189
|
+
font-size: 0.8125rem;
|
|
190
|
+
border-radius: 0.5rem;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.btn-md {
|
|
194
|
+
height: 2.5rem;
|
|
195
|
+
padding: 0 1.25rem;
|
|
196
|
+
font-size: 0.875rem;
|
|
197
|
+
border-radius: 0.5rem;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.btn-lg {
|
|
201
|
+
height: 3rem;
|
|
202
|
+
padding: 0 1.5rem;
|
|
203
|
+
font-size: 1rem;
|
|
204
|
+
border-radius: 0.75rem;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* Icon-only variants */
|
|
208
|
+
.btn-icon-only.btn-xs {
|
|
209
|
+
width: 1.75rem;
|
|
210
|
+
padding: 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.btn-icon-only.btn-sm {
|
|
214
|
+
width: 2rem;
|
|
215
|
+
padding: 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.btn-icon-only.btn-md {
|
|
219
|
+
width: 2.5rem;
|
|
220
|
+
padding: 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.btn-icon-only.btn-lg {
|
|
224
|
+
width: 3rem;
|
|
225
|
+
padding: 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Full width */
|
|
229
|
+
.btn-full-width {
|
|
230
|
+
width: 100%;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* ========================================
|
|
234
|
+
PRIMARY VARIANT - The hero button
|
|
235
|
+
======================================== */
|
|
236
|
+
.btn-primary {
|
|
237
|
+
background: linear-gradient(135deg, rgb(var(--ui-color-primary)), rgb(var(--ui-color-primary-light)));
|
|
238
|
+
color: white;
|
|
239
|
+
box-shadow:
|
|
240
|
+
0 1px 2px rgb(var(--ui-color-primary) / 0.2),
|
|
241
|
+
0 4px 12px rgb(var(--ui-color-primary) / 0.15);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.btn-primary:hover:not(:disabled) {
|
|
245
|
+
transform: translateY(-1px);
|
|
246
|
+
box-shadow:
|
|
247
|
+
0 2px 4px rgb(var(--ui-color-primary) / 0.25),
|
|
248
|
+
0 6px 20px rgb(var(--ui-color-primary) / 0.25);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.btn-primary:active:not(:disabled) {
|
|
252
|
+
transform: translateY(0);
|
|
253
|
+
box-shadow:
|
|
254
|
+
0 1px 2px rgb(var(--ui-color-primary) / 0.3),
|
|
255
|
+
0 2px 8px rgb(var(--ui-color-primary) / 0.2);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* ========================================
|
|
259
|
+
SECONDARY VARIANT - Supporting actions
|
|
260
|
+
======================================== */
|
|
261
|
+
.btn-secondary {
|
|
262
|
+
background: var(--ui-bg-primary);
|
|
263
|
+
color: var(--ui-text-primary);
|
|
264
|
+
border: 1px solid var(--ui-border-default);
|
|
265
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / 0.05);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.btn-secondary:hover:not(:disabled) {
|
|
269
|
+
background: var(--ui-bg-secondary);
|
|
270
|
+
border-color: var(--ui-border-hover);
|
|
271
|
+
box-shadow: 0 2px 4px rgb(0 0 0 / 0.08);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.btn-secondary:active:not(:disabled) {
|
|
275
|
+
background: var(--ui-bg-tertiary);
|
|
276
|
+
box-shadow: none;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* ========================================
|
|
280
|
+
GHOST VARIANT - Minimal emphasis
|
|
281
|
+
======================================== */
|
|
282
|
+
.btn-ghost {
|
|
283
|
+
background: transparent;
|
|
284
|
+
color: var(--ui-text-secondary);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.btn-ghost:hover:not(:disabled) {
|
|
288
|
+
background: var(--ui-bg-tertiary);
|
|
289
|
+
color: var(--ui-text-primary);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.btn-ghost:active:not(:disabled) {
|
|
293
|
+
background: var(--ui-bg-secondary);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* ========================================
|
|
297
|
+
OUTLINE VARIANT - Brand colored outline
|
|
298
|
+
======================================== */
|
|
299
|
+
.btn-outline {
|
|
300
|
+
background: transparent;
|
|
301
|
+
color: rgb(var(--ui-color-primary));
|
|
302
|
+
border: 2px solid rgb(var(--ui-color-primary));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.btn-outline:hover:not(:disabled) {
|
|
306
|
+
background: rgb(var(--ui-color-primary) / 0.08);
|
|
307
|
+
border-color: rgb(var(--ui-color-primary-light));
|
|
308
|
+
color: rgb(var(--ui-color-primary-light));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.btn-outline:active:not(:disabled) {
|
|
312
|
+
background: rgb(var(--ui-color-primary) / 0.12);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* Dark mode: use lighter shade for better contrast */
|
|
316
|
+
:global([data-theme='dark']) .btn-outline {
|
|
317
|
+
color: rgb(var(--ui-color-primary-light));
|
|
318
|
+
border-color: rgb(var(--ui-color-primary-light));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
:global([data-theme='dark']) .btn-outline:hover:not(:disabled) {
|
|
322
|
+
background: rgb(var(--ui-color-primary-light) / 0.15);
|
|
323
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-primary-light) / 0.1);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
@media (prefers-color-scheme: dark) {
|
|
327
|
+
:global(:root:not([data-theme='light'])) .btn-outline {
|
|
328
|
+
color: rgb(var(--ui-color-primary-light));
|
|
329
|
+
border-color: rgb(var(--ui-color-primary-light));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
:global(:root:not([data-theme='light'])) .btn-outline:hover:not(:disabled) {
|
|
333
|
+
background: rgb(var(--ui-color-primary-light) / 0.15);
|
|
334
|
+
box-shadow: 0 0 0 3px rgb(var(--ui-color-primary-light) / 0.1);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/* ========================================
|
|
339
|
+
DANGER VARIANT - Destructive actions
|
|
340
|
+
======================================== */
|
|
341
|
+
.btn-danger {
|
|
342
|
+
background: linear-gradient(135deg, rgb(var(--ui-color-error)), rgb(var(--ui-color-error-light)));
|
|
343
|
+
color: white;
|
|
344
|
+
box-shadow:
|
|
345
|
+
0 1px 2px rgb(var(--ui-color-error) / 0.2),
|
|
346
|
+
0 4px 12px rgb(var(--ui-color-error) / 0.15);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.btn-danger:hover:not(:disabled) {
|
|
350
|
+
transform: translateY(-1px);
|
|
351
|
+
box-shadow:
|
|
352
|
+
0 2px 4px rgb(var(--ui-color-error) / 0.25),
|
|
353
|
+
0 6px 20px rgb(var(--ui-color-error) / 0.25);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.btn-danger:active:not(:disabled) {
|
|
357
|
+
transform: translateY(0);
|
|
358
|
+
box-shadow:
|
|
359
|
+
0 1px 2px rgb(var(--ui-color-error) / 0.3),
|
|
360
|
+
0 2px 8px rgb(var(--ui-color-error) / 0.2);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* ========================================
|
|
364
|
+
CONTENT & STATES
|
|
365
|
+
======================================== */
|
|
366
|
+
.btn-content {
|
|
367
|
+
display: inline-flex;
|
|
368
|
+
align-items: center;
|
|
369
|
+
gap: 0.5rem;
|
|
370
|
+
transition: opacity 0.15s ease;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.btn-content-hidden {
|
|
374
|
+
opacity: 0;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.btn-icon {
|
|
378
|
+
display: inline-flex;
|
|
379
|
+
flex-shrink: 0;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.btn-spinner {
|
|
383
|
+
position: absolute;
|
|
384
|
+
display: inline-flex;
|
|
385
|
+
animation: btn-spin 0.8s linear infinite;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.btn-loading {
|
|
389
|
+
pointer-events: none;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
@keyframes btn-spin {
|
|
393
|
+
from {
|
|
394
|
+
transform: rotate(0deg);
|
|
395
|
+
}
|
|
396
|
+
to {
|
|
397
|
+
transform: rotate(360deg);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* Screen reader only */
|
|
402
|
+
.sr-only {
|
|
403
|
+
position: absolute;
|
|
404
|
+
width: 1px;
|
|
405
|
+
height: 1px;
|
|
406
|
+
padding: 0;
|
|
407
|
+
margin: -1px;
|
|
408
|
+
overflow: hidden;
|
|
409
|
+
clip: rect(0, 0, 0, 0);
|
|
410
|
+
white-space: nowrap;
|
|
411
|
+
border: 0;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/* ========================================
|
|
415
|
+
REDUCED MOTION
|
|
416
|
+
======================================== */
|
|
417
|
+
@media (prefers-reduced-motion: reduce) {
|
|
418
|
+
.btn {
|
|
419
|
+
transition: none;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.btn:hover:not(:disabled) {
|
|
423
|
+
transform: none;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.btn-spinner {
|
|
427
|
+
animation: none;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
3
|
+
import type { Size, Variant } from '../../types/index.js';
|
|
4
|
+
type ButtonSize = Exclude<Size, 'xl'>;
|
|
5
|
+
type ButtonVariant = Variant | 'danger';
|
|
6
|
+
interface Props extends Omit<HTMLButtonAttributes, 'class'> {
|
|
7
|
+
/** Visual variant of the button */
|
|
8
|
+
variant?: ButtonVariant;
|
|
9
|
+
/** Size of the button */
|
|
10
|
+
size?: ButtonSize;
|
|
11
|
+
/** Whether the button takes full width */
|
|
12
|
+
fullWidth?: boolean;
|
|
13
|
+
/** Whether to show loading state */
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
/** Loading text for screen readers (defaults to "Loading...") */
|
|
16
|
+
loadingText?: string;
|
|
17
|
+
/** Icon to display on the left */
|
|
18
|
+
iconLeft?: Snippet;
|
|
19
|
+
/** Icon to display on the right */
|
|
20
|
+
iconRight?: Snippet;
|
|
21
|
+
/** Whether this is an icon-only button (requires aria-label) */
|
|
22
|
+
iconOnly?: boolean;
|
|
23
|
+
/** Additional CSS classes */
|
|
24
|
+
class?: string;
|
|
25
|
+
/** Button content */
|
|
26
|
+
children?: Snippet;
|
|
27
|
+
/** Test ID for e2e testing (Playwright, Cypress) */
|
|
28
|
+
testId?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Button
|
|
32
|
+
*
|
|
33
|
+
* A versatile button component with multiple variants, sizes, and states.
|
|
34
|
+
* Follows WCAG 2.1 AA accessibility guidelines for healthcare applications.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* <Button variant="primary" size="md" onclick={() => handleClick()}>
|
|
38
|
+
* Click me
|
|
39
|
+
* </Button>
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* <Button variant="secondary" disabled>
|
|
43
|
+
* <Icon slot="icon-left" />
|
|
44
|
+
* With Icon
|
|
45
|
+
* </Button>
|
|
46
|
+
*/
|
|
47
|
+
declare const Button: import("svelte").Component<Props, {}, "">;
|
|
48
|
+
type Button = ReturnType<typeof Button>;
|
|
49
|
+
export default Button;
|
|
50
|
+
//# sourceMappingURL=Button.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.svelte.d.ts","sourceRoot":"","sources":["../../../src/primitives/Button/Button.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAG5D,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAG1D,KAAK,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACtC,KAAK,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAC;AAExC,UAAU,KAAM,SAAQ,IAAI,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAC1D,mCAAmC;IACnC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,yBAAyB;IACzB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AA+ED;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,MAAM,2CAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/primitives/Button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Button } from './Button.svelte';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synthaxai/ui - Primitive Components
|
|
3
|
+
*
|
|
4
|
+
* Core building blocks for the UI. These components are atomic
|
|
5
|
+
* and can be composed to build more complex interfaces.
|
|
6
|
+
*/
|
|
7
|
+
export { Button } from './Button/index.js';
|
|
8
|
+
export { Badge } from './Badge/index.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/primitives/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synthaxai/ui - Primitive Components
|
|
3
|
+
*
|
|
4
|
+
* Core building blocks for the UI. These components are atomic
|
|
5
|
+
* and can be composed to build more complex interfaces.
|
|
6
|
+
*/
|
|
7
|
+
export { Button } from './Button/index.js';
|
|
8
|
+
export { Badge } from './Badge/index.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import '../styles/tokens.css';
|
|
3
|
+
|
|
4
|
+
let { children } = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<svelte:head>
|
|
8
|
+
<title>@synthaxai/ui - Component Library</title>
|
|
9
|
+
<meta name="description" content="Production-quality UI component library for Synthax healthcare applications" />
|
|
10
|
+
</svelte:head>
|
|
11
|
+
|
|
12
|
+
{@render children()}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default Layout;
|
|
2
|
+
type Layout = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const Layout: import("svelte").Component<{
|
|
7
|
+
children: import("svelte").Snippet;
|
|
8
|
+
}, {}, "">;
|
|
9
|
+
type $$ComponentProps = {
|
|
10
|
+
children: import("svelte").Snippet;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=+layout.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"+layout.svelte.d.ts","sourceRoot":"","sources":["../../src/routes/+layout.svelte.js"],"names":[],"mappings":";;;;;AAoBA;cAZ6B,OAAO,QAAQ,EAAE,OAAO;WAYA;wBAZpC;IAAE,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAA;CAAE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!-- Development home page for the component library -->
|
|
2
|
+
<script>
|
|
3
|
+
import '../styles/tokens.css';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<main class="min-h-screen bg-[var(--ui-bg-primary)] p-8">
|
|
7
|
+
<div class="max-w-4xl mx-auto">
|
|
8
|
+
<h1 class="text-3xl font-bold text-[var(--ui-text-primary)] mb-4">
|
|
9
|
+
@synthaxai/ui
|
|
10
|
+
</h1>
|
|
11
|
+
<p class="text-[var(--ui-text-secondary)] mb-8">
|
|
12
|
+
Production-quality UI component library for Synthax healthcare applications.
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<div class="grid gap-4">
|
|
16
|
+
<section class="p-6 rounded-xl border border-[var(--ui-border-default)] bg-[var(--ui-bg-secondary)]">
|
|
17
|
+
<h2 class="text-lg font-semibold text-[var(--ui-text-primary)] mb-2">Getting Started</h2>
|
|
18
|
+
<p class="text-sm text-[var(--ui-text-secondary)]">
|
|
19
|
+
Import components from the library:
|
|
20
|
+
</p>
|
|
21
|
+
<pre class="mt-2 p-3 rounded-lg bg-[var(--ui-bg-tertiary)] text-sm font-mono text-[var(--ui-text-primary)]">import {'{'} Button, Card, TextInput {'}'} from '@synthaxai/ui';</pre>
|
|
22
|
+
</section>
|
|
23
|
+
|
|
24
|
+
<section class="p-6 rounded-xl border border-[var(--ui-border-default)] bg-[var(--ui-bg-secondary)]">
|
|
25
|
+
<h2 class="text-lg font-semibold text-[var(--ui-text-primary)] mb-2">Components</h2>
|
|
26
|
+
<ul class="grid grid-cols-2 md:grid-cols-3 gap-2 text-sm text-[var(--ui-text-secondary)]">
|
|
27
|
+
<li>Button</li>
|
|
28
|
+
<li>Badge</li>
|
|
29
|
+
<li>TextInput</li>
|
|
30
|
+
<li>Select</li>
|
|
31
|
+
<li>Checkbox</li>
|
|
32
|
+
<li>FormField</li>
|
|
33
|
+
<li>Spinner</li>
|
|
34
|
+
<li>ProgressBar</li>
|
|
35
|
+
<li>EmptyState</li>
|
|
36
|
+
<li>Toast</li>
|
|
37
|
+
<li>Card</li>
|
|
38
|
+
<li>Container</li>
|
|
39
|
+
<li>StatCard</li>
|
|
40
|
+
<li>DataTable</li>
|
|
41
|
+
<li>StepIndicator</li>
|
|
42
|
+
<li>Modal</li>
|
|
43
|
+
<li>ConfirmDialog</li>
|
|
44
|
+
</ul>
|
|
45
|
+
</section>
|
|
46
|
+
|
|
47
|
+
<section class="p-6 rounded-xl border border-[var(--ui-border-default)] bg-[var(--ui-bg-secondary)]">
|
|
48
|
+
<h2 class="text-lg font-semibold text-[var(--ui-text-primary)] mb-2">Run Tests</h2>
|
|
49
|
+
<pre class="p-3 rounded-lg bg-[var(--ui-bg-tertiary)] text-sm font-mono text-[var(--ui-text-primary)]">pnpm test</pre>
|
|
50
|
+
</section>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</main>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export default Page;
|
|
2
|
+
type Page = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const Page: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
14
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
15
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
16
|
+
$$bindings?: Bindings;
|
|
17
|
+
} & Exports;
|
|
18
|
+
(internal: unknown, props: {
|
|
19
|
+
$$events?: Events;
|
|
20
|
+
$$slots?: Slots;
|
|
21
|
+
}): Exports & {
|
|
22
|
+
$set?: any;
|
|
23
|
+
$on?: any;
|
|
24
|
+
};
|
|
25
|
+
z_$$bindings?: Bindings;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=+page.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"+page.svelte.d.ts","sourceRoot":"","sources":["../../src/routes/+page.svelte.js"],"names":[],"mappings":";;;;;;;;AAsEA;;;;mBAAgH;6CATnE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,OAAO,OAAO,QAAQ;IAC3L,cAAc,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,WAAW,OAAO,SAAS;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,eAAe,QAAQ,CAAC"}
|