@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,568 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Skeleton
|
|
3
|
+
|
|
4
|
+
A world-class loading placeholder component with multiple variants and animations.
|
|
5
|
+
Designed for healthcare applications where data loading states must be clearly
|
|
6
|
+
communicated without causing anxiety.
|
|
7
|
+
|
|
8
|
+
Features:
|
|
9
|
+
- Multiple preset variants (text, avatar, card, table-row, patient-card, etc.)
|
|
10
|
+
- Wave animation (perceived as faster than pulse)
|
|
11
|
+
- Composite skeletons for common patterns
|
|
12
|
+
- Proper accessibility without over-announcing
|
|
13
|
+
- Reduced motion support
|
|
14
|
+
|
|
15
|
+
@example
|
|
16
|
+
<Skeleton width="200px" height="20px" />
|
|
17
|
+
|
|
18
|
+
@example
|
|
19
|
+
<Skeleton variant="text" lines={3} />
|
|
20
|
+
|
|
21
|
+
@example
|
|
22
|
+
<Skeleton variant="patient-card" />
|
|
23
|
+
-->
|
|
24
|
+
<script lang="ts">
|
|
25
|
+
type SkeletonVariant =
|
|
26
|
+
| 'rectangle'
|
|
27
|
+
| 'circle'
|
|
28
|
+
| 'text'
|
|
29
|
+
| 'avatar'
|
|
30
|
+
| 'button'
|
|
31
|
+
| 'card'
|
|
32
|
+
| 'image'
|
|
33
|
+
| 'table-row'
|
|
34
|
+
| 'patient-card'
|
|
35
|
+
| 'stat-card'
|
|
36
|
+
| 'list-item';
|
|
37
|
+
|
|
38
|
+
type SkeletonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
39
|
+
type SkeletonAnimation = 'wave' | 'pulse' | 'none';
|
|
40
|
+
|
|
41
|
+
interface Props {
|
|
42
|
+
/** Skeleton variant */
|
|
43
|
+
variant?: SkeletonVariant;
|
|
44
|
+
/** Size preset (for avatar, button, text variants) */
|
|
45
|
+
size?: SkeletonSize;
|
|
46
|
+
/** Custom width (CSS value) */
|
|
47
|
+
width?: string;
|
|
48
|
+
/** Custom height (CSS value) */
|
|
49
|
+
height?: string;
|
|
50
|
+
/** Number of lines (for text variant) */
|
|
51
|
+
lines?: number;
|
|
52
|
+
/** Animation style - wave is perceived as faster */
|
|
53
|
+
animation?: SkeletonAnimation;
|
|
54
|
+
/** Border radius preset or custom CSS value */
|
|
55
|
+
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full' | string;
|
|
56
|
+
/** Accessible label for screen readers */
|
|
57
|
+
label?: string;
|
|
58
|
+
/** Number of items for list-based variants (table-row, list-item) */
|
|
59
|
+
count?: number;
|
|
60
|
+
/** Additional CSS classes */
|
|
61
|
+
class?: string;
|
|
62
|
+
/** ID for the skeleton element */
|
|
63
|
+
id?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let {
|
|
67
|
+
variant = 'rectangle',
|
|
68
|
+
size = 'md',
|
|
69
|
+
width,
|
|
70
|
+
height,
|
|
71
|
+
lines = 1,
|
|
72
|
+
animation = 'wave',
|
|
73
|
+
rounded = 'md',
|
|
74
|
+
label = 'Loading content',
|
|
75
|
+
count = 1,
|
|
76
|
+
class: className = '',
|
|
77
|
+
id
|
|
78
|
+
}: Props = $props();
|
|
79
|
+
|
|
80
|
+
// Size presets for different variants
|
|
81
|
+
const avatarSizes: Record<SkeletonSize, { width: string; height: string }> = {
|
|
82
|
+
xs: { width: '1.5rem', height: '1.5rem' },
|
|
83
|
+
sm: { width: '2rem', height: '2rem' },
|
|
84
|
+
md: { width: '2.5rem', height: '2.5rem' },
|
|
85
|
+
lg: { width: '3rem', height: '3rem' },
|
|
86
|
+
xl: { width: '4rem', height: '4rem' }
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const buttonSizes: Record<SkeletonSize, { width: string; height: string }> = {
|
|
90
|
+
xs: { width: '4rem', height: '1.75rem' },
|
|
91
|
+
sm: { width: '5rem', height: '2rem' },
|
|
92
|
+
md: { width: '6rem', height: '2.5rem' },
|
|
93
|
+
lg: { width: '8rem', height: '3rem' },
|
|
94
|
+
xl: { width: '10rem', height: '3.5rem' }
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const textHeights: Record<SkeletonSize, string> = {
|
|
98
|
+
xs: '0.625rem',
|
|
99
|
+
sm: '0.75rem',
|
|
100
|
+
md: '1rem',
|
|
101
|
+
lg: '1.25rem',
|
|
102
|
+
xl: '1.5rem'
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Border radius presets
|
|
106
|
+
const radiusMap: Record<string, string> = {
|
|
107
|
+
none: '0',
|
|
108
|
+
sm: '0.25rem',
|
|
109
|
+
md: '0.375rem',
|
|
110
|
+
lg: '0.5rem',
|
|
111
|
+
xl: '0.75rem',
|
|
112
|
+
full: '9999px'
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const getRadius = (r: string) => radiusMap[r] || r;
|
|
116
|
+
|
|
117
|
+
// Generate array for multiple items
|
|
118
|
+
const itemArray = $derived(Array.from({ length: count }, (_, i) => i));
|
|
119
|
+
const lineArray = $derived(Array.from({ length: lines }, (_, i) => i));
|
|
120
|
+
|
|
121
|
+
// Last line width for text variant (shorter to look natural)
|
|
122
|
+
const getLineWidth = (index: number) => {
|
|
123
|
+
if (lines === 1) return '100%';
|
|
124
|
+
if (index === lines - 1) return `${55 + Math.random() * 25}%`;
|
|
125
|
+
return '100%';
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Check if variant is a composite type
|
|
129
|
+
const isComposite = $derived(
|
|
130
|
+
['patient-card', 'stat-card', 'table-row', 'list-item'].includes(variant)
|
|
131
|
+
);
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<!-- Composite: Patient Card Skeleton -->
|
|
135
|
+
{#if variant === 'patient-card'}
|
|
136
|
+
<div
|
|
137
|
+
{id}
|
|
138
|
+
class="skeleton-composite skeleton-patient-card {className}"
|
|
139
|
+
class:skeleton-wave={animation === 'wave'}
|
|
140
|
+
class:skeleton-pulse={animation === 'pulse'}
|
|
141
|
+
role="status"
|
|
142
|
+
aria-label={label}
|
|
143
|
+
aria-busy="true"
|
|
144
|
+
>
|
|
145
|
+
<span class="sr-only">{label}</span>
|
|
146
|
+
<div class="skeleton-patient-header">
|
|
147
|
+
<div class="skeleton-base skeleton-avatar" aria-hidden="true"></div>
|
|
148
|
+
<div class="skeleton-patient-info">
|
|
149
|
+
<div class="skeleton-base skeleton-text-lg" aria-hidden="true"></div>
|
|
150
|
+
<div class="skeleton-base skeleton-text-sm skeleton-short" aria-hidden="true"></div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="skeleton-patient-body">
|
|
154
|
+
<div class="skeleton-base skeleton-text-md" aria-hidden="true"></div>
|
|
155
|
+
<div class="skeleton-base skeleton-text-md skeleton-medium" aria-hidden="true"></div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<!-- Composite: Stat Card Skeleton -->
|
|
160
|
+
{:else if variant === 'stat-card'}
|
|
161
|
+
<div
|
|
162
|
+
{id}
|
|
163
|
+
class="skeleton-composite skeleton-stat-card {className}"
|
|
164
|
+
class:skeleton-wave={animation === 'wave'}
|
|
165
|
+
class:skeleton-pulse={animation === 'pulse'}
|
|
166
|
+
role="status"
|
|
167
|
+
aria-label={label}
|
|
168
|
+
aria-busy="true"
|
|
169
|
+
>
|
|
170
|
+
<span class="sr-only">{label}</span>
|
|
171
|
+
<div class="skeleton-base skeleton-text-sm skeleton-short" aria-hidden="true"></div>
|
|
172
|
+
<div class="skeleton-base skeleton-stat-value" aria-hidden="true"></div>
|
|
173
|
+
<div class="skeleton-base skeleton-text-xs skeleton-medium" aria-hidden="true"></div>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<!-- Composite: Table Row Skeleton -->
|
|
177
|
+
{:else if variant === 'table-row'}
|
|
178
|
+
<div
|
|
179
|
+
{id}
|
|
180
|
+
class="skeleton-composite skeleton-table-rows {className}"
|
|
181
|
+
role="status"
|
|
182
|
+
aria-label={label}
|
|
183
|
+
aria-busy="true"
|
|
184
|
+
>
|
|
185
|
+
<span class="sr-only">{label}</span>
|
|
186
|
+
{#each itemArray as index (index)}
|
|
187
|
+
<div
|
|
188
|
+
class="skeleton-table-row"
|
|
189
|
+
class:skeleton-wave={animation === 'wave'}
|
|
190
|
+
class:skeleton-pulse={animation === 'pulse'}
|
|
191
|
+
aria-hidden="true"
|
|
192
|
+
>
|
|
193
|
+
<div class="skeleton-base skeleton-cell skeleton-cell-sm"></div>
|
|
194
|
+
<div class="skeleton-base skeleton-cell skeleton-cell-lg"></div>
|
|
195
|
+
<div class="skeleton-base skeleton-cell skeleton-cell-md"></div>
|
|
196
|
+
<div class="skeleton-base skeleton-cell skeleton-cell-sm"></div>
|
|
197
|
+
</div>
|
|
198
|
+
{/each}
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<!-- Composite: List Item Skeleton -->
|
|
202
|
+
{:else if variant === 'list-item'}
|
|
203
|
+
<div
|
|
204
|
+
{id}
|
|
205
|
+
class="skeleton-composite skeleton-list-items {className}"
|
|
206
|
+
role="status"
|
|
207
|
+
aria-label={label}
|
|
208
|
+
aria-busy="true"
|
|
209
|
+
>
|
|
210
|
+
<span class="sr-only">{label}</span>
|
|
211
|
+
{#each itemArray as index (index)}
|
|
212
|
+
<div
|
|
213
|
+
class="skeleton-list-item"
|
|
214
|
+
class:skeleton-wave={animation === 'wave'}
|
|
215
|
+
class:skeleton-pulse={animation === 'pulse'}
|
|
216
|
+
aria-hidden="true"
|
|
217
|
+
>
|
|
218
|
+
<div class="skeleton-base skeleton-avatar-sm"></div>
|
|
219
|
+
<div class="skeleton-list-content">
|
|
220
|
+
<div class="skeleton-base skeleton-text-md skeleton-medium"></div>
|
|
221
|
+
<div class="skeleton-base skeleton-text-sm skeleton-short"></div>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
{/each}
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
<!-- Text with multiple lines -->
|
|
228
|
+
{:else if variant === 'text' && lines > 1}
|
|
229
|
+
<div
|
|
230
|
+
{id}
|
|
231
|
+
class="skeleton-text-group {className}"
|
|
232
|
+
role="status"
|
|
233
|
+
aria-label={label}
|
|
234
|
+
aria-busy="true"
|
|
235
|
+
>
|
|
236
|
+
<span class="sr-only">{label}</span>
|
|
237
|
+
{#each lineArray as index (index)}
|
|
238
|
+
<div
|
|
239
|
+
class="skeleton-base skeleton-text"
|
|
240
|
+
class:skeleton-wave={animation === 'wave'}
|
|
241
|
+
class:skeleton-pulse={animation === 'pulse'}
|
|
242
|
+
style="width: {getLineWidth(index)}; height: {textHeights[size]};"
|
|
243
|
+
aria-hidden="true"
|
|
244
|
+
></div>
|
|
245
|
+
{/each}
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
<!-- Simple variants -->
|
|
249
|
+
{:else}
|
|
250
|
+
<div
|
|
251
|
+
{id}
|
|
252
|
+
class="skeleton-base {className}"
|
|
253
|
+
class:skeleton-wave={animation === 'wave'}
|
|
254
|
+
class:skeleton-pulse={animation === 'pulse'}
|
|
255
|
+
style="
|
|
256
|
+
width: {width || (variant === 'avatar' || variant === 'circle' ? avatarSizes[size].width : variant === 'button' ? buttonSizes[size].width : variant === 'text' ? '100%' : variant === 'card' ? '100%' : variant === 'image' ? '100%' : '100%')};
|
|
257
|
+
height: {height || (variant === 'avatar' || variant === 'circle' ? avatarSizes[size].height : variant === 'button' ? buttonSizes[size].height : variant === 'text' ? textHeights[size] : variant === 'card' ? '8rem' : variant === 'image' ? '12rem' : '1rem')};
|
|
258
|
+
border-radius: {variant === 'avatar' || variant === 'circle' ? '9999px' : variant === 'button' ? '0.5rem' : variant === 'card' || variant === 'image' ? '0.75rem' : getRadius(rounded)};
|
|
259
|
+
"
|
|
260
|
+
role="status"
|
|
261
|
+
aria-label={label}
|
|
262
|
+
aria-busy="true"
|
|
263
|
+
>
|
|
264
|
+
<span class="sr-only">{label}</span>
|
|
265
|
+
</div>
|
|
266
|
+
{/if}
|
|
267
|
+
|
|
268
|
+
<style>
|
|
269
|
+
/* ========================================
|
|
270
|
+
BASE SKELETON STYLES
|
|
271
|
+
======================================== */
|
|
272
|
+
.skeleton-base {
|
|
273
|
+
background-color: var(--ui-bg-tertiary);
|
|
274
|
+
position: relative;
|
|
275
|
+
overflow: hidden;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* Screen reader only */
|
|
279
|
+
.sr-only {
|
|
280
|
+
position: absolute;
|
|
281
|
+
width: 1px;
|
|
282
|
+
height: 1px;
|
|
283
|
+
padding: 0;
|
|
284
|
+
margin: -1px;
|
|
285
|
+
overflow: hidden;
|
|
286
|
+
clip: rect(0, 0, 0, 0);
|
|
287
|
+
white-space: nowrap;
|
|
288
|
+
border: 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* ========================================
|
|
292
|
+
WAVE ANIMATION (Perceived as faster)
|
|
293
|
+
Uses clip-path to prevent overflow issues
|
|
294
|
+
======================================== */
|
|
295
|
+
.skeleton-wave {
|
|
296
|
+
overflow: hidden;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.skeleton-wave::after {
|
|
300
|
+
content: '';
|
|
301
|
+
position: absolute;
|
|
302
|
+
top: 0;
|
|
303
|
+
left: 0;
|
|
304
|
+
right: 0;
|
|
305
|
+
bottom: 0;
|
|
306
|
+
background: linear-gradient(
|
|
307
|
+
90deg,
|
|
308
|
+
transparent 0%,
|
|
309
|
+
rgba(255, 255, 255, 0.4) 50%,
|
|
310
|
+
transparent 100%
|
|
311
|
+
);
|
|
312
|
+
animation: skeleton-wave 1.6s ease-in-out infinite;
|
|
313
|
+
transform: translateX(-100%);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
:global([data-theme='dark']) .skeleton-wave::after {
|
|
317
|
+
background: linear-gradient(
|
|
318
|
+
90deg,
|
|
319
|
+
transparent 0%,
|
|
320
|
+
rgba(255, 255, 255, 0.08) 50%,
|
|
321
|
+
transparent 100%
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
@media (prefers-color-scheme: dark) {
|
|
326
|
+
:global(:root:not([data-theme='light'])) .skeleton-wave::after {
|
|
327
|
+
background: linear-gradient(
|
|
328
|
+
90deg,
|
|
329
|
+
transparent 0%,
|
|
330
|
+
rgba(255, 255, 255, 0.08) 50%,
|
|
331
|
+
transparent 100%
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
@keyframes skeleton-wave {
|
|
337
|
+
0% {
|
|
338
|
+
transform: translateX(-100%);
|
|
339
|
+
}
|
|
340
|
+
60%, 100% {
|
|
341
|
+
transform: translateX(100%);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* ========================================
|
|
346
|
+
PULSE ANIMATION
|
|
347
|
+
======================================== */
|
|
348
|
+
.skeleton-pulse {
|
|
349
|
+
animation: skeleton-pulse 2s ease-in-out infinite;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
@keyframes skeleton-pulse {
|
|
353
|
+
0%, 100% {
|
|
354
|
+
opacity: 1;
|
|
355
|
+
}
|
|
356
|
+
50% {
|
|
357
|
+
opacity: 0.5;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* ========================================
|
|
362
|
+
TEXT SKELETON
|
|
363
|
+
======================================== */
|
|
364
|
+
.skeleton-text-group {
|
|
365
|
+
display: flex;
|
|
366
|
+
flex-direction: column;
|
|
367
|
+
gap: 0.5rem;
|
|
368
|
+
overflow: hidden;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.skeleton-text {
|
|
372
|
+
border-radius: 0.25rem;
|
|
373
|
+
overflow: hidden;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* ========================================
|
|
377
|
+
COMPOSITE SHARED STYLES
|
|
378
|
+
======================================== */
|
|
379
|
+
.skeleton-composite {
|
|
380
|
+
overflow: hidden;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* ========================================
|
|
384
|
+
COMPOSITE: PATIENT CARD
|
|
385
|
+
======================================== */
|
|
386
|
+
.skeleton-patient-card {
|
|
387
|
+
padding: 1rem;
|
|
388
|
+
background: var(--ui-bg-primary);
|
|
389
|
+
border: 1px solid var(--ui-border-default);
|
|
390
|
+
border-radius: 0.75rem;
|
|
391
|
+
overflow: hidden;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.skeleton-patient-header {
|
|
395
|
+
display: flex;
|
|
396
|
+
align-items: center;
|
|
397
|
+
gap: 0.75rem;
|
|
398
|
+
margin-bottom: 1rem;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.skeleton-avatar {
|
|
402
|
+
width: 3rem;
|
|
403
|
+
height: 3rem;
|
|
404
|
+
border-radius: 9999px;
|
|
405
|
+
flex-shrink: 0;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.skeleton-avatar-sm {
|
|
409
|
+
width: 2.5rem;
|
|
410
|
+
height: 2.5rem;
|
|
411
|
+
border-radius: 9999px;
|
|
412
|
+
flex-shrink: 0;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.skeleton-patient-info {
|
|
416
|
+
flex: 1;
|
|
417
|
+
display: flex;
|
|
418
|
+
flex-direction: column;
|
|
419
|
+
gap: 0.375rem;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.skeleton-patient-body {
|
|
423
|
+
display: flex;
|
|
424
|
+
flex-direction: column;
|
|
425
|
+
gap: 0.375rem;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* ========================================
|
|
429
|
+
COMPOSITE: STAT CARD
|
|
430
|
+
======================================== */
|
|
431
|
+
.skeleton-stat-card {
|
|
432
|
+
padding: 1.25rem;
|
|
433
|
+
background: var(--ui-bg-primary);
|
|
434
|
+
border: 1px solid var(--ui-border-default);
|
|
435
|
+
border-radius: 0.75rem;
|
|
436
|
+
display: flex;
|
|
437
|
+
flex-direction: column;
|
|
438
|
+
gap: 0.5rem;
|
|
439
|
+
overflow: hidden;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.skeleton-stat-value {
|
|
443
|
+
height: 2rem;
|
|
444
|
+
width: 5rem;
|
|
445
|
+
border-radius: 0.375rem;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/* ========================================
|
|
449
|
+
COMPOSITE: TABLE ROW
|
|
450
|
+
======================================== */
|
|
451
|
+
.skeleton-table-rows {
|
|
452
|
+
display: flex;
|
|
453
|
+
flex-direction: column;
|
|
454
|
+
overflow: hidden;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.skeleton-table-row {
|
|
458
|
+
display: flex;
|
|
459
|
+
align-items: center;
|
|
460
|
+
gap: 1rem;
|
|
461
|
+
padding: 0.875rem 1rem;
|
|
462
|
+
border-bottom: 1px solid var(--ui-border-default);
|
|
463
|
+
overflow: hidden;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.skeleton-table-row:last-child {
|
|
467
|
+
border-bottom: none;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.skeleton-cell {
|
|
471
|
+
height: 1rem;
|
|
472
|
+
border-radius: 0.25rem;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.skeleton-cell-sm {
|
|
476
|
+
width: 4rem;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.skeleton-cell-md {
|
|
480
|
+
width: 8rem;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.skeleton-cell-lg {
|
|
484
|
+
flex: 1;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/* ========================================
|
|
488
|
+
COMPOSITE: LIST ITEM
|
|
489
|
+
======================================== */
|
|
490
|
+
.skeleton-list-items {
|
|
491
|
+
display: flex;
|
|
492
|
+
flex-direction: column;
|
|
493
|
+
overflow: hidden;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.skeleton-list-item {
|
|
497
|
+
display: flex;
|
|
498
|
+
align-items: center;
|
|
499
|
+
gap: 0.75rem;
|
|
500
|
+
padding: 0.75rem 0;
|
|
501
|
+
border-bottom: 1px solid var(--ui-border-default);
|
|
502
|
+
overflow: hidden;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.skeleton-list-item:last-child {
|
|
506
|
+
border-bottom: none;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.skeleton-list-content {
|
|
510
|
+
flex: 1;
|
|
511
|
+
display: flex;
|
|
512
|
+
flex-direction: column;
|
|
513
|
+
gap: 0.25rem;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/* ========================================
|
|
517
|
+
TEXT SIZE HELPERS
|
|
518
|
+
======================================== */
|
|
519
|
+
.skeleton-text-xs {
|
|
520
|
+
height: 0.625rem;
|
|
521
|
+
border-radius: 0.125rem;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.skeleton-text-sm {
|
|
525
|
+
height: 0.75rem;
|
|
526
|
+
border-radius: 0.125rem;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.skeleton-text-md {
|
|
530
|
+
height: 1rem;
|
|
531
|
+
border-radius: 0.25rem;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.skeleton-text-lg {
|
|
535
|
+
height: 1.25rem;
|
|
536
|
+
border-radius: 0.25rem;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/* Width helpers */
|
|
540
|
+
.skeleton-short {
|
|
541
|
+
width: 40%;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.skeleton-medium {
|
|
545
|
+
width: 70%;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/* ========================================
|
|
549
|
+
REDUCED MOTION
|
|
550
|
+
======================================== */
|
|
551
|
+
@media (prefers-reduced-motion: reduce) {
|
|
552
|
+
.skeleton-wave::after {
|
|
553
|
+
animation: none;
|
|
554
|
+
transform: none;
|
|
555
|
+
background: none;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.skeleton-pulse {
|
|
559
|
+
animation: none;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/* Show static slightly lighter state instead */
|
|
563
|
+
.skeleton-wave,
|
|
564
|
+
.skeleton-pulse {
|
|
565
|
+
opacity: 0.7;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
</style>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
type SkeletonVariant = 'rectangle' | 'circle' | 'text' | 'avatar' | 'button' | 'card' | 'image' | 'table-row' | 'patient-card' | 'stat-card' | 'list-item';
|
|
2
|
+
type SkeletonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
3
|
+
type SkeletonAnimation = 'wave' | 'pulse' | 'none';
|
|
4
|
+
interface Props {
|
|
5
|
+
/** Skeleton variant */
|
|
6
|
+
variant?: SkeletonVariant;
|
|
7
|
+
/** Size preset (for avatar, button, text variants) */
|
|
8
|
+
size?: SkeletonSize;
|
|
9
|
+
/** Custom width (CSS value) */
|
|
10
|
+
width?: string;
|
|
11
|
+
/** Custom height (CSS value) */
|
|
12
|
+
height?: string;
|
|
13
|
+
/** Number of lines (for text variant) */
|
|
14
|
+
lines?: number;
|
|
15
|
+
/** Animation style - wave is perceived as faster */
|
|
16
|
+
animation?: SkeletonAnimation;
|
|
17
|
+
/** Border radius preset or custom CSS value */
|
|
18
|
+
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full' | string;
|
|
19
|
+
/** Accessible label for screen readers */
|
|
20
|
+
label?: string;
|
|
21
|
+
/** Number of items for list-based variants (table-row, list-item) */
|
|
22
|
+
count?: number;
|
|
23
|
+
/** Additional CSS classes */
|
|
24
|
+
class?: string;
|
|
25
|
+
/** ID for the skeleton element */
|
|
26
|
+
id?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Skeleton
|
|
30
|
+
*
|
|
31
|
+
* A world-class loading placeholder component with multiple variants and animations.
|
|
32
|
+
* Designed for healthcare applications where data loading states must be clearly
|
|
33
|
+
* communicated without causing anxiety.
|
|
34
|
+
*
|
|
35
|
+
* Features:
|
|
36
|
+
* - Multiple preset variants (text, avatar, card, table-row, patient-card, etc.)
|
|
37
|
+
* - Wave animation (perceived as faster than pulse)
|
|
38
|
+
* - Composite skeletons for common patterns
|
|
39
|
+
* - Proper accessibility without over-announcing
|
|
40
|
+
* - Reduced motion support
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* <Skeleton width="200px" height="20px" />
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* <Skeleton variant="text" lines={3} />
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* <Skeleton variant="patient-card" />
|
|
50
|
+
*/
|
|
51
|
+
declare const Skeleton: import("svelte").Component<Props, {}, "">;
|
|
52
|
+
type Skeleton = ReturnType<typeof Skeleton>;
|
|
53
|
+
export default Skeleton;
|
|
54
|
+
//# sourceMappingURL=Skeleton.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skeleton.svelte.d.ts","sourceRoot":"","sources":["../../../src/feedback/Skeleton/Skeleton.svelte.ts"],"names":[],"mappings":"AAGC,KAAK,eAAe,GACjB,WAAW,GACX,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,OAAO,GACP,WAAW,GACX,cAAc,GACd,WAAW,GACX,WAAW,CAAC;AAEf,KAAK,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACrD,KAAK,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEnD,UAAU,KAAK;IACd,uBAAuB;IACvB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,sDAAsD;IACtD,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/D,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AA2JF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/feedback/Skeleton/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Skeleton } from './Skeleton.svelte';
|