@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.
Files changed (185) hide show
  1. package/README.md +262 -0
  2. package/dist/app.css +2 -0
  3. package/dist/app.html +12 -0
  4. package/dist/data-display/DataTable/DataTable.svelte +773 -0
  5. package/dist/data-display/DataTable/DataTable.svelte.d.ts +120 -0
  6. package/dist/data-display/DataTable/DataTable.svelte.d.ts.map +1 -0
  7. package/dist/data-display/DataTable/index.d.ts +2 -0
  8. package/dist/data-display/DataTable/index.d.ts.map +1 -0
  9. package/dist/data-display/DataTable/index.js +1 -0
  10. package/dist/data-display/StatCard/StatCard.svelte +409 -0
  11. package/dist/data-display/StatCard/StatCard.svelte.d.ts +63 -0
  12. package/dist/data-display/StatCard/StatCard.svelte.d.ts.map +1 -0
  13. package/dist/data-display/StatCard/index.d.ts +2 -0
  14. package/dist/data-display/StatCard/index.d.ts.map +1 -0
  15. package/dist/data-display/StatCard/index.js +1 -0
  16. package/dist/data-display/index.d.ts +8 -0
  17. package/dist/data-display/index.d.ts.map +1 -0
  18. package/dist/data-display/index.js +7 -0
  19. package/dist/dialogs/ConfirmDialog/ConfirmDialog.svelte +693 -0
  20. package/dist/dialogs/ConfirmDialog/ConfirmDialog.svelte.d.ts +66 -0
  21. package/dist/dialogs/ConfirmDialog/ConfirmDialog.svelte.d.ts.map +1 -0
  22. package/dist/dialogs/ConfirmDialog/index.d.ts +2 -0
  23. package/dist/dialogs/ConfirmDialog/index.d.ts.map +1 -0
  24. package/dist/dialogs/ConfirmDialog/index.js +1 -0
  25. package/dist/dialogs/Modal/Modal.svelte +441 -0
  26. package/dist/dialogs/Modal/Modal.svelte.d.ts +69 -0
  27. package/dist/dialogs/Modal/Modal.svelte.d.ts.map +1 -0
  28. package/dist/dialogs/Modal/index.d.ts +2 -0
  29. package/dist/dialogs/Modal/index.d.ts.map +1 -0
  30. package/dist/dialogs/Modal/index.js +1 -0
  31. package/dist/dialogs/index.d.ts +8 -0
  32. package/dist/dialogs/index.d.ts.map +1 -0
  33. package/dist/dialogs/index.js +7 -0
  34. package/dist/feedback/Alert/Alert.svelte +565 -0
  35. package/dist/feedback/Alert/Alert.svelte.d.ts +60 -0
  36. package/dist/feedback/Alert/Alert.svelte.d.ts.map +1 -0
  37. package/dist/feedback/Alert/index.d.ts +2 -0
  38. package/dist/feedback/Alert/index.d.ts.map +1 -0
  39. package/dist/feedback/Alert/index.js +1 -0
  40. package/dist/feedback/EmptyState/EmptyState.svelte +377 -0
  41. package/dist/feedback/EmptyState/EmptyState.svelte.d.ts +63 -0
  42. package/dist/feedback/EmptyState/EmptyState.svelte.d.ts.map +1 -0
  43. package/dist/feedback/EmptyState/index.d.ts +2 -0
  44. package/dist/feedback/EmptyState/index.d.ts.map +1 -0
  45. package/dist/feedback/EmptyState/index.js +1 -0
  46. package/dist/feedback/ProgressBar/ProgressBar.svelte +585 -0
  47. package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts +68 -0
  48. package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts.map +1 -0
  49. package/dist/feedback/ProgressBar/index.d.ts +2 -0
  50. package/dist/feedback/ProgressBar/index.d.ts.map +1 -0
  51. package/dist/feedback/ProgressBar/index.js +1 -0
  52. package/dist/feedback/Skeleton/Skeleton.svelte +568 -0
  53. package/dist/feedback/Skeleton/Skeleton.svelte.d.ts +54 -0
  54. package/dist/feedback/Skeleton/Skeleton.svelte.d.ts.map +1 -0
  55. package/dist/feedback/Skeleton/index.d.ts +2 -0
  56. package/dist/feedback/Skeleton/index.d.ts.map +1 -0
  57. package/dist/feedback/Skeleton/index.js +1 -0
  58. package/dist/feedback/Spinner/Spinner.svelte +434 -0
  59. package/dist/feedback/Spinner/Spinner.svelte.d.ts +49 -0
  60. package/dist/feedback/Spinner/Spinner.svelte.d.ts.map +1 -0
  61. package/dist/feedback/Spinner/index.d.ts +2 -0
  62. package/dist/feedback/Spinner/index.d.ts.map +1 -0
  63. package/dist/feedback/Spinner/index.js +1 -0
  64. package/dist/feedback/Toast/Toast.svelte +587 -0
  65. package/dist/feedback/Toast/Toast.svelte.d.ts +55 -0
  66. package/dist/feedback/Toast/Toast.svelte.d.ts.map +1 -0
  67. package/dist/feedback/Toast/ToastContainer.svelte +168 -0
  68. package/dist/feedback/Toast/ToastContainer.svelte.d.ts +28 -0
  69. package/dist/feedback/Toast/ToastContainer.svelte.d.ts.map +1 -0
  70. package/dist/feedback/Toast/index.d.ts +4 -0
  71. package/dist/feedback/Toast/index.d.ts.map +1 -0
  72. package/dist/feedback/Toast/index.js +3 -0
  73. package/dist/feedback/Toast/toast-store.d.ts +72 -0
  74. package/dist/feedback/Toast/toast-store.d.ts.map +1 -0
  75. package/dist/feedback/Toast/toast-store.js +157 -0
  76. package/dist/feedback/index.d.ts +13 -0
  77. package/dist/feedback/index.d.ts.map +1 -0
  78. package/dist/feedback/index.js +12 -0
  79. package/dist/forms/Checkbox/Checkbox.svelte +404 -0
  80. package/dist/forms/Checkbox/Checkbox.svelte.d.ts +62 -0
  81. package/dist/forms/Checkbox/Checkbox.svelte.d.ts.map +1 -0
  82. package/dist/forms/Checkbox/index.d.ts +2 -0
  83. package/dist/forms/Checkbox/index.d.ts.map +1 -0
  84. package/dist/forms/Checkbox/index.js +1 -0
  85. package/dist/forms/FormField/FormField.svelte +299 -0
  86. package/dist/forms/FormField/FormField.svelte.d.ts +43 -0
  87. package/dist/forms/FormField/FormField.svelte.d.ts.map +1 -0
  88. package/dist/forms/FormField/index.d.ts +2 -0
  89. package/dist/forms/FormField/index.d.ts.map +1 -0
  90. package/dist/forms/FormField/index.js +1 -0
  91. package/dist/forms/RadioGroup/RadioGroup.svelte +418 -0
  92. package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts +70 -0
  93. package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts.map +1 -0
  94. package/dist/forms/RadioGroup/index.d.ts +2 -0
  95. package/dist/forms/RadioGroup/index.d.ts.map +1 -0
  96. package/dist/forms/RadioGroup/index.js +1 -0
  97. package/dist/forms/Select/Select.svelte +548 -0
  98. package/dist/forms/Select/Select.svelte.d.ts +74 -0
  99. package/dist/forms/Select/Select.svelte.d.ts.map +1 -0
  100. package/dist/forms/Select/index.d.ts +2 -0
  101. package/dist/forms/Select/index.d.ts.map +1 -0
  102. package/dist/forms/Select/index.js +1 -0
  103. package/dist/forms/TextInput/TextInput.svelte +628 -0
  104. package/dist/forms/TextInput/TextInput.svelte.d.ts +97 -0
  105. package/dist/forms/TextInput/TextInput.svelte.d.ts.map +1 -0
  106. package/dist/forms/TextInput/index.d.ts +2 -0
  107. package/dist/forms/TextInput/index.d.ts.map +1 -0
  108. package/dist/forms/TextInput/index.js +1 -0
  109. package/dist/forms/Textarea/Textarea.svelte +587 -0
  110. package/dist/forms/Textarea/Textarea.svelte.d.ts +71 -0
  111. package/dist/forms/Textarea/Textarea.svelte.d.ts.map +1 -0
  112. package/dist/forms/Textarea/index.d.ts +2 -0
  113. package/dist/forms/Textarea/index.d.ts.map +1 -0
  114. package/dist/forms/Textarea/index.js +1 -0
  115. package/dist/forms/index.d.ts +13 -0
  116. package/dist/forms/index.d.ts.map +1 -0
  117. package/dist/forms/index.js +12 -0
  118. package/dist/index.d.ts +37 -0
  119. package/dist/index.d.ts.map +1 -0
  120. package/dist/index.js +65 -0
  121. package/dist/layout/Card/Card.svelte +316 -0
  122. package/dist/layout/Card/Card.svelte.d.ts +63 -0
  123. package/dist/layout/Card/Card.svelte.d.ts.map +1 -0
  124. package/dist/layout/Card/index.d.ts +2 -0
  125. package/dist/layout/Card/index.d.ts.map +1 -0
  126. package/dist/layout/Card/index.js +1 -0
  127. package/dist/layout/Container/Container.svelte +252 -0
  128. package/dist/layout/Container/Container.svelte.d.ts +50 -0
  129. package/dist/layout/Container/Container.svelte.d.ts.map +1 -0
  130. package/dist/layout/Container/index.d.ts +2 -0
  131. package/dist/layout/Container/index.d.ts.map +1 -0
  132. package/dist/layout/Container/index.js +1 -0
  133. package/dist/layout/index.d.ts +8 -0
  134. package/dist/layout/index.d.ts.map +1 -0
  135. package/dist/layout/index.js +7 -0
  136. package/dist/navigation/StepIndicator/StepIndicator.svelte +601 -0
  137. package/dist/navigation/StepIndicator/StepIndicator.svelte.d.ts +70 -0
  138. package/dist/navigation/StepIndicator/StepIndicator.svelte.d.ts.map +1 -0
  139. package/dist/navigation/StepIndicator/index.d.ts +2 -0
  140. package/dist/navigation/StepIndicator/index.d.ts.map +1 -0
  141. package/dist/navigation/StepIndicator/index.js +1 -0
  142. package/dist/navigation/index.d.ts +7 -0
  143. package/dist/navigation/index.d.ts.map +1 -0
  144. package/dist/navigation/index.js +6 -0
  145. package/dist/primitives/Badge/Badge.svelte +365 -0
  146. package/dist/primitives/Badge/Badge.svelte.d.ts +39 -0
  147. package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -0
  148. package/dist/primitives/Badge/index.d.ts +2 -0
  149. package/dist/primitives/Badge/index.d.ts.map +1 -0
  150. package/dist/primitives/Badge/index.js +1 -0
  151. package/dist/primitives/Button/Button.svelte +430 -0
  152. package/dist/primitives/Button/Button.svelte.d.ts +50 -0
  153. package/dist/primitives/Button/Button.svelte.d.ts.map +1 -0
  154. package/dist/primitives/Button/index.d.ts +2 -0
  155. package/dist/primitives/Button/index.d.ts.map +1 -0
  156. package/dist/primitives/Button/index.js +1 -0
  157. package/dist/primitives/index.d.ts +9 -0
  158. package/dist/primitives/index.d.ts.map +1 -0
  159. package/dist/primitives/index.js +8 -0
  160. package/dist/routes/+layout.svelte +12 -0
  161. package/dist/routes/+layout.svelte.d.ts +12 -0
  162. package/dist/routes/+layout.svelte.d.ts.map +1 -0
  163. package/dist/routes/+page.svelte +53 -0
  164. package/dist/routes/+page.svelte.d.ts +27 -0
  165. package/dist/routes/+page.svelte.d.ts.map +1 -0
  166. package/dist/styles/tokens.css +399 -0
  167. package/dist/types/index.d.ts +175 -0
  168. package/dist/types/index.d.ts.map +1 -0
  169. package/dist/types/index.js +7 -0
  170. package/dist/utils/accessibility.d.ts +103 -0
  171. package/dist/utils/accessibility.d.ts.map +1 -0
  172. package/dist/utils/accessibility.js +202 -0
  173. package/dist/utils/cn.d.ts +71 -0
  174. package/dist/utils/cn.d.ts.map +1 -0
  175. package/dist/utils/cn.js +61 -0
  176. package/dist/utils/form-styles.d.ts +76 -0
  177. package/dist/utils/form-styles.d.ts.map +1 -0
  178. package/dist/utils/form-styles.js +95 -0
  179. package/dist/utils/index.d.ts +10 -0
  180. package/dist/utils/index.d.ts.map +1 -0
  181. package/dist/utils/index.js +13 -0
  182. package/dist/utils/keyboard.d.ts +94 -0
  183. package/dist/utils/keyboard.d.ts.map +1 -0
  184. package/dist/utils/keyboard.js +179 -0
  185. package/package.json +119 -0
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Accessibility utilities for healthcare UI components.
3
+ *
4
+ * Implements WCAG 2.1 Level AA compliance requirements for
5
+ * critical healthcare applications.
6
+ */
7
+ /**
8
+ * Screen reader only text.
9
+ * Visually hidden but accessible to assistive technologies.
10
+ */
11
+ export const srOnlyClass = 'sr-only';
12
+ /**
13
+ * Announces a message to screen readers.
14
+ *
15
+ * @param message - The message to announce
16
+ * @param priority - 'polite' (default) or 'assertive'
17
+ *
18
+ * @example
19
+ * announce('Form submitted successfully');
20
+ * announce('Error: Please fix the highlighted fields', 'assertive');
21
+ */
22
+ export function announce(message, priority = 'polite') {
23
+ if (typeof document === 'undefined')
24
+ return;
25
+ // Find or create the announcer element
26
+ let announcer = document.getElementById(`ui-announcer-${priority}`);
27
+ if (!announcer) {
28
+ announcer = document.createElement('div');
29
+ announcer.id = `ui-announcer-${priority}`;
30
+ announcer.setAttribute('aria-live', priority);
31
+ announcer.setAttribute('aria-atomic', 'true');
32
+ announcer.setAttribute('role', priority === 'assertive' ? 'alert' : 'status');
33
+ announcer.className = 'sr-only';
34
+ announcer.style.cssText = `
35
+ position: absolute;
36
+ width: 1px;
37
+ height: 1px;
38
+ padding: 0;
39
+ margin: -1px;
40
+ overflow: hidden;
41
+ clip: rect(0, 0, 0, 0);
42
+ white-space: nowrap;
43
+ border: 0;
44
+ `;
45
+ document.body.appendChild(announcer);
46
+ }
47
+ // Clear and set message (triggers announcement)
48
+ announcer.textContent = '';
49
+ // Use requestAnimationFrame to ensure the clear is processed
50
+ requestAnimationFrame(() => {
51
+ if (announcer) {
52
+ announcer.textContent = message;
53
+ }
54
+ });
55
+ }
56
+ /**
57
+ * Checks if the user prefers reduced motion.
58
+ *
59
+ * @returns true if reduced motion is preferred
60
+ */
61
+ export function prefersReducedMotion() {
62
+ if (typeof window === 'undefined')
63
+ return false;
64
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
65
+ }
66
+ /**
67
+ * Returns animation duration based on user preferences.
68
+ * Returns 0 if user prefers reduced motion, otherwise returns the provided duration.
69
+ *
70
+ * @param duration - Normal animation duration in ms
71
+ * @returns Adjusted duration
72
+ */
73
+ export function getAnimationDuration(duration) {
74
+ return prefersReducedMotion() ? 0 : duration;
75
+ }
76
+ /**
77
+ * Checks if high contrast mode is preferred.
78
+ *
79
+ * @returns true if high contrast is preferred
80
+ */
81
+ export function prefersHighContrast() {
82
+ if (typeof window === 'undefined')
83
+ return false;
84
+ return window.matchMedia('(prefers-contrast: more)').matches;
85
+ }
86
+ /**
87
+ * Describes an element for screen readers.
88
+ * Returns appropriate ARIA attributes for a described element.
89
+ *
90
+ * @param description - The description text
91
+ * @param id - The ID to use for the description element
92
+ */
93
+ export function createDescription(description, id) {
94
+ return {
95
+ describedById: id,
96
+ descriptionProps: {
97
+ id,
98
+ className: srOnlyClass
99
+ },
100
+ text: description
101
+ };
102
+ }
103
+ /**
104
+ * Formats a value for screen reader announcement.
105
+ * Useful for live regions that need to announce changes.
106
+ *
107
+ * @param value - The value to format
108
+ * @param label - Label describing the value
109
+ * @param unit - Optional unit (e.g., 'percent', 'dollars')
110
+ */
111
+ export function formatForAnnouncement(value, label, unit) {
112
+ const formattedValue = typeof value === 'number' ? value.toLocaleString() : value;
113
+ return unit ? `${label}: ${formattedValue} ${unit}` : `${label}: ${formattedValue}`;
114
+ }
115
+ /**
116
+ * Checks if an element is visible and focusable.
117
+ */
118
+ export function isElementFocusable(element) {
119
+ if (!(element instanceof HTMLElement))
120
+ return false;
121
+ // Check if hidden
122
+ if (element.hidden || element.getAttribute('aria-hidden') === 'true') {
123
+ return false;
124
+ }
125
+ // Check computed styles
126
+ const style = window.getComputedStyle(element);
127
+ if (style.display === 'none' || style.visibility === 'hidden') {
128
+ return false;
129
+ }
130
+ // Check if disabled
131
+ if (element.disabled) {
132
+ return false;
133
+ }
134
+ // Check tabindex
135
+ const tabindex = element.getAttribute('tabindex');
136
+ if (tabindex === '-1') {
137
+ return false;
138
+ }
139
+ return true;
140
+ }
141
+ /**
142
+ * Gets all focusable elements within a container.
143
+ */
144
+ export function getFocusableElements(container) {
145
+ const selector = [
146
+ 'button:not([disabled])',
147
+ '[href]',
148
+ 'input:not([disabled]):not([type="hidden"])',
149
+ 'select:not([disabled])',
150
+ 'textarea:not([disabled])',
151
+ '[tabindex]:not([tabindex="-1"])',
152
+ '[contenteditable="true"]'
153
+ ].join(', ');
154
+ return Array.from(container.querySelectorAll(selector)).filter(isElementFocusable);
155
+ }
156
+ /**
157
+ * Creates an accessible label for a form field.
158
+ * Returns either labelledby or label props based on visibility.
159
+ */
160
+ export function createFieldLabel(label, fieldId, options = {}) {
161
+ const { visible = true, required = false } = options;
162
+ const labelId = `${fieldId}-label`;
163
+ return {
164
+ labelId,
165
+ labelProps: {
166
+ id: labelId,
167
+ for: fieldId,
168
+ ...(required && { 'data-required': true })
169
+ },
170
+ fieldProps: visible
171
+ ? { id: fieldId, 'aria-labelledby': labelId }
172
+ : { id: fieldId, 'aria-label': label }
173
+ };
174
+ }
175
+ /**
176
+ * Creates ARIA props for an error message.
177
+ */
178
+ export function createErrorProps(fieldId, error) {
179
+ const errorId = `${fieldId}-error`;
180
+ return {
181
+ errorId,
182
+ errorProps: {
183
+ id: errorId,
184
+ role: 'alert',
185
+ 'aria-live': 'polite'
186
+ },
187
+ fieldErrorProps: error
188
+ ? { 'aria-invalid': 'true', 'aria-describedby': errorId }
189
+ : { 'aria-invalid': 'false' }
190
+ };
191
+ }
192
+ /**
193
+ * Role descriptions for healthcare-specific contexts.
194
+ * Can be used with aria-roledescription for more specific announcements.
195
+ */
196
+ export const healthcareRoles = {
197
+ patientCard: 'patient information card',
198
+ vitalSign: 'vital sign indicator',
199
+ medicationItem: 'medication entry',
200
+ alertBanner: 'clinical alert',
201
+ statusIndicator: 'status indicator'
202
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Class name utility for conditionally joining class names.
3
+ *
4
+ * A lightweight alternative to clsx/classnames that handles:
5
+ * - Strings
6
+ * - Objects with boolean values
7
+ * - Arrays (including nested)
8
+ * - Falsy values (ignored)
9
+ *
10
+ * @example
11
+ * cn('base', condition && 'conditional', { active: isActive })
12
+ * // => 'base conditional active' (if both conditions are true)
13
+ *
14
+ * @example
15
+ * cn('btn', {
16
+ * 'btn-primary': variant === 'primary',
17
+ * 'btn-disabled': disabled
18
+ * })
19
+ */
20
+ export type ClassValue = string | number | boolean | null | undefined | ClassValue[] | Record<string, boolean | null | undefined>;
21
+ /**
22
+ * Merges multiple class values into a single class string.
23
+ *
24
+ * @param inputs - Class values to merge
25
+ * @returns Merged class string with duplicates removed
26
+ */
27
+ export declare function cn(...inputs: ClassValue[]): string;
28
+ /**
29
+ * Creates a variant-based class name generator.
30
+ *
31
+ * @example
32
+ * const buttonVariants = createVariants({
33
+ * base: 'btn',
34
+ * variants: {
35
+ * variant: {
36
+ * primary: 'btn-primary',
37
+ * secondary: 'btn-secondary'
38
+ * },
39
+ * size: {
40
+ * sm: 'btn-sm',
41
+ * md: 'btn-md',
42
+ * lg: 'btn-lg'
43
+ * }
44
+ * },
45
+ * defaults: { variant: 'primary', size: 'md' }
46
+ * });
47
+ *
48
+ * buttonVariants({ variant: 'secondary' })
49
+ * // => 'btn btn-secondary btn-md'
50
+ */
51
+ export interface VariantConfig<T extends Record<string, Record<string, string>>> {
52
+ /** Base classes always applied */
53
+ base?: string;
54
+ /** Variant definitions */
55
+ variants: T;
56
+ /** Default values for each variant */
57
+ defaults?: Partial<{
58
+ [K in keyof T]: keyof T[K];
59
+ }>;
60
+ /** Compound variants for specific combinations */
61
+ compounds?: Array<{
62
+ conditions: Partial<{
63
+ [K in keyof T]: keyof T[K];
64
+ }>;
65
+ class: string;
66
+ }>;
67
+ }
68
+ export declare function createVariants<T extends Record<string, Record<string, string>>>(config: VariantConfig<T>): (props?: Partial<{
69
+ [K in keyof T]: keyof T[K];
70
+ }>) => string;
71
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/utils/cn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,UAAU,GACnB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,UAAU,EAAE,GACZ,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAsBlD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9E,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,QAAQ,EAAE,CAAC,CAAC;IACZ,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;KAAE,CAAC,CAAC;IACnD,kDAAkD;IAClD,SAAS,CAAC,EAAE,KAAK,CAAC;QACjB,UAAU,EAAE,OAAO,CAAC;aAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;SAAE,CAAC,CAAC;QACpD,KAAK,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACH;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC9E,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GACtB,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC,KAAK,MAAM,CAgC7D"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Merges multiple class values into a single class string.
3
+ *
4
+ * @param inputs - Class values to merge
5
+ * @returns Merged class string with duplicates removed
6
+ */
7
+ export function cn(...inputs) {
8
+ const classes = [];
9
+ for (const input of inputs) {
10
+ if (!input)
11
+ continue;
12
+ if (typeof input === 'string') {
13
+ classes.push(input);
14
+ }
15
+ else if (typeof input === 'number') {
16
+ classes.push(String(input));
17
+ }
18
+ else if (Array.isArray(input)) {
19
+ const nested = cn(...input);
20
+ if (nested)
21
+ classes.push(nested);
22
+ }
23
+ else if (typeof input === 'object') {
24
+ for (const [key, value] of Object.entries(input)) {
25
+ if (value)
26
+ classes.push(key);
27
+ }
28
+ }
29
+ }
30
+ // Remove duplicates while preserving order
31
+ return [...new Set(classes)].join(' ');
32
+ }
33
+ export function createVariants(config) {
34
+ return (props = {}) => {
35
+ const classes = [];
36
+ // Add base classes
37
+ if (config.base) {
38
+ classes.push(config.base);
39
+ }
40
+ // Add variant classes
41
+ for (const [variantName, variantOptions] of Object.entries(config.variants)) {
42
+ const value = props[variantName] ?? config.defaults?.[variantName];
43
+ if (value && variantOptions[value]) {
44
+ classes.push(variantOptions[value]);
45
+ }
46
+ }
47
+ // Add compound variant classes
48
+ if (config.compounds) {
49
+ for (const compound of config.compounds) {
50
+ const matches = Object.entries(compound.conditions).every(([key, value]) => {
51
+ const propValue = props[key] ?? config.defaults?.[key];
52
+ return propValue === value;
53
+ });
54
+ if (matches) {
55
+ classes.push(compound.class);
56
+ }
57
+ }
58
+ }
59
+ return cn(...classes);
60
+ };
61
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Shared form component styles.
3
+ *
4
+ * Provides consistent styling patterns across all form components.
5
+ */
6
+ /**
7
+ * Common form field sizes.
8
+ */
9
+ export type FormFieldSize = 'sm' | 'md' | 'lg';
10
+ /**
11
+ * Base label styles for all form fields.
12
+ */
13
+ export declare const labelBaseClass = "flex items-center gap-1.5 font-medium text-[var(--ui-text-primary)]";
14
+ /**
15
+ * Label size classes.
16
+ */
17
+ export declare const labelSizeClasses: Record<FormFieldSize, string>;
18
+ /**
19
+ * Error message base styles.
20
+ */
21
+ export declare const errorMessageClass = "text-xs text-[rgb(var(--ui-color-error))]";
22
+ /**
23
+ * Error message with icon styles.
24
+ */
25
+ export declare const errorMessageWithIconClass = "text-xs text-[rgb(var(--ui-color-error))] flex items-center gap-1";
26
+ /**
27
+ * Success message styles.
28
+ */
29
+ export declare const successMessageClass = "text-xs text-[rgb(var(--ui-color-success))]";
30
+ /**
31
+ * Hint text styles.
32
+ */
33
+ export declare const hintTextClass = "text-xs text-[var(--ui-text-tertiary)]";
34
+ /**
35
+ * Description text styles.
36
+ */
37
+ export declare const descriptionTextClass = "text-xs text-[var(--ui-text-tertiary)]";
38
+ /**
39
+ * Required indicator styles.
40
+ */
41
+ export declare const requiredIndicatorClass = "text-[rgb(var(--ui-color-error))]";
42
+ /**
43
+ * Input field base styles (shared across text inputs, textareas, selects).
44
+ */
45
+ export declare const inputBaseClass: string;
46
+ /**
47
+ * Input size classes.
48
+ */
49
+ export declare const inputSizeClasses: Record<FormFieldSize, string>;
50
+ /**
51
+ * Get border classes based on validation state.
52
+ */
53
+ export declare function getInputBorderClasses(options: {
54
+ hasError: boolean;
55
+ isValid: boolean;
56
+ }): string;
57
+ /**
58
+ * Form field wrapper styles.
59
+ */
60
+ export declare const fieldWrapperClass = "flex flex-col gap-1.5";
61
+ /**
62
+ * Disabled field wrapper modifier.
63
+ */
64
+ export declare const disabledWrapperClass = "opacity-60";
65
+ /**
66
+ * Checkbox/Radio sizes.
67
+ */
68
+ export declare const checkboxSizeClasses: Record<FormFieldSize, {
69
+ box: string;
70
+ icon: number;
71
+ }>;
72
+ /**
73
+ * Get aria-describedby value from optional error and hint IDs.
74
+ */
75
+ export declare function buildAriaDescribedBy(...ids: (string | false | undefined | null)[]): string | undefined;
76
+ //# sourceMappingURL=form-styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-styles.d.ts","sourceRoot":"","sources":["../../src/utils/form-styles.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,cAAc,wEAAwE,CAAC;AAEpG;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAI1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,8CAA8C,CAAC;AAE7E;;GAEG;AACH,eAAO,MAAM,yBAAyB,sEAC8B,CAAC;AAErE;;GAEG;AACH,eAAO,MAAM,mBAAmB,gDAAgD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,aAAa,2CAA2C,CAAC;AAEtE;;GAEG;AACH,eAAO,MAAM,oBAAoB,2CAA2C,CAAC;AAE7E;;GAEG;AACH,eAAO,MAAM,sBAAsB,sCAAsC,CAAC;AAE1E;;GAEG;AACH,eAAO,MAAM,cAAc,QAMnB,CAAC;AAET;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAI1D,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CACjB,GAAG,MAAM,CAYT;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,0BAA0B,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,aAAa,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAIpF,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CACnC,GAAG,GAAG,EAAE,CAAC,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,GAC3C,MAAM,GAAG,SAAS,CAGpB"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Shared form component styles.
3
+ *
4
+ * Provides consistent styling patterns across all form components.
5
+ */
6
+ /**
7
+ * Base label styles for all form fields.
8
+ */
9
+ export const labelBaseClass = 'flex items-center gap-1.5 font-medium text-[var(--ui-text-primary)]';
10
+ /**
11
+ * Label size classes.
12
+ */
13
+ export const labelSizeClasses = {
14
+ sm: 'text-xs',
15
+ md: 'text-sm',
16
+ lg: 'text-sm'
17
+ };
18
+ /**
19
+ * Error message base styles.
20
+ */
21
+ export const errorMessageClass = 'text-xs text-[rgb(var(--ui-color-error))]';
22
+ /**
23
+ * Error message with icon styles.
24
+ */
25
+ export const errorMessageWithIconClass = 'text-xs text-[rgb(var(--ui-color-error))] flex items-center gap-1';
26
+ /**
27
+ * Success message styles.
28
+ */
29
+ export const successMessageClass = 'text-xs text-[rgb(var(--ui-color-success))]';
30
+ /**
31
+ * Hint text styles.
32
+ */
33
+ export const hintTextClass = 'text-xs text-[var(--ui-text-tertiary)]';
34
+ /**
35
+ * Description text styles.
36
+ */
37
+ export const descriptionTextClass = 'text-xs text-[var(--ui-text-tertiary)]';
38
+ /**
39
+ * Required indicator styles.
40
+ */
41
+ export const requiredIndicatorClass = 'text-[rgb(var(--ui-color-error))]';
42
+ /**
43
+ * Input field base styles (shared across text inputs, textareas, selects).
44
+ */
45
+ export const inputBaseClass = `
46
+ w-full rounded-lg border-2 transition-all duration-200
47
+ bg-[var(--ui-bg-secondary)] text-[var(--ui-text-primary)]
48
+ placeholder:text-[var(--ui-text-tertiary)]
49
+ focus:outline-none focus:bg-[var(--ui-bg-primary)]
50
+ disabled:cursor-not-allowed disabled:bg-[var(--ui-bg-tertiary)]
51
+ `.trim();
52
+ /**
53
+ * Input size classes.
54
+ */
55
+ export const inputSizeClasses = {
56
+ sm: 'h-8 px-3 text-sm',
57
+ md: 'h-10 px-3 text-sm',
58
+ lg: 'h-12 px-4 text-base'
59
+ };
60
+ /**
61
+ * Get border classes based on validation state.
62
+ */
63
+ export function getInputBorderClasses(options) {
64
+ const { hasError, isValid } = options;
65
+ if (hasError) {
66
+ return 'border-[rgb(var(--ui-color-error))] focus:ring-2 focus:ring-[rgb(var(--ui-color-error)/0.2)]';
67
+ }
68
+ if (isValid) {
69
+ return 'border-[rgb(var(--ui-color-success))] focus:ring-2 focus:ring-[rgb(var(--ui-color-success)/0.2)]';
70
+ }
71
+ return 'border-[var(--ui-border-default)] focus:border-[rgb(var(--ui-color-primary))] focus:ring-2 focus:ring-[rgb(var(--ui-color-primary)/0.1)]';
72
+ }
73
+ /**
74
+ * Form field wrapper styles.
75
+ */
76
+ export const fieldWrapperClass = 'flex flex-col gap-1.5';
77
+ /**
78
+ * Disabled field wrapper modifier.
79
+ */
80
+ export const disabledWrapperClass = 'opacity-60';
81
+ /**
82
+ * Checkbox/Radio sizes.
83
+ */
84
+ export const checkboxSizeClasses = {
85
+ sm: { box: 'w-4 h-4', icon: 12 },
86
+ md: { box: 'w-5 h-5', icon: 14 },
87
+ lg: { box: 'w-6 h-6', icon: 16 }
88
+ };
89
+ /**
90
+ * Get aria-describedby value from optional error and hint IDs.
91
+ */
92
+ export function buildAriaDescribedBy(...ids) {
93
+ const filtered = ids.filter(Boolean);
94
+ return filtered.length > 0 ? filtered.join(' ') : undefined;
95
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @synthaxai/ui - Utility Functions
3
+ *
4
+ * Shared utilities for building accessible, consistent UI components.
5
+ */
6
+ export { cn, createVariants, type ClassValue, type VariantConfig } from './cn.js';
7
+ export { type FormFieldSize, labelBaseClass, labelSizeClasses, errorMessageClass, errorMessageWithIconClass, successMessageClass, hintTextClass, descriptionTextClass, requiredIndicatorClass, inputBaseClass, inputSizeClasses, getInputBorderClasses, fieldWrapperClass, disabledWrapperClass, checkboxSizeClasses, buildAriaDescribedBy } from './form-styles.js';
8
+ export { Keys, isKey, isActivationKey, isNavigationKey, createListNavigation, createFocusTrap, generateId, type Key, type ListNavigationOptions, type FocusTrap } from './keyboard.js';
9
+ export { announce, prefersReducedMotion, getAnimationDuration, prefersHighContrast, createDescription, formatForAnnouncement, isElementFocusable, getFocusableElements, createFieldLabel, createErrorProps, healthcareRoles, srOnlyClass } from './accessibility.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAGlF,OAAO,EACN,KAAK,aAAa,EAClB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACN,IAAI,EACJ,KAAK,EACL,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,UAAU,EACV,KAAK,GAAG,EACR,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,MAAM,eAAe,CAAC;AAGvB,OAAO,EACN,QAAQ,EACR,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @synthaxai/ui - Utility Functions
3
+ *
4
+ * Shared utilities for building accessible, consistent UI components.
5
+ */
6
+ // Class name utilities
7
+ export { cn, createVariants } from './cn.js';
8
+ // Form styling utilities
9
+ export { labelBaseClass, labelSizeClasses, errorMessageClass, errorMessageWithIconClass, successMessageClass, hintTextClass, descriptionTextClass, requiredIndicatorClass, inputBaseClass, inputSizeClasses, getInputBorderClasses, fieldWrapperClass, disabledWrapperClass, checkboxSizeClasses, buildAriaDescribedBy } from './form-styles.js';
10
+ // Keyboard navigation
11
+ export { Keys, isKey, isActivationKey, isNavigationKey, createListNavigation, createFocusTrap, generateId } from './keyboard.js';
12
+ // Accessibility utilities
13
+ export { announce, prefersReducedMotion, getAnimationDuration, prefersHighContrast, createDescription, formatForAnnouncement, isElementFocusable, getFocusableElements, createFieldLabel, createErrorProps, healthcareRoles, srOnlyClass } from './accessibility.js';
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Keyboard navigation utilities for accessible components.
3
+ *
4
+ * Provides consistent keyboard handling across the component library,
5
+ * following WCAG 2.1 and WAI-ARIA best practices.
6
+ */
7
+ /**
8
+ * Common keyboard keys used in component interactions.
9
+ */
10
+ export declare const Keys: {
11
+ readonly Enter: "Enter";
12
+ readonly Space: " ";
13
+ readonly Escape: "Escape";
14
+ readonly Tab: "Tab";
15
+ readonly ArrowUp: "ArrowUp";
16
+ readonly ArrowDown: "ArrowDown";
17
+ readonly ArrowLeft: "ArrowLeft";
18
+ readonly ArrowRight: "ArrowRight";
19
+ readonly Home: "Home";
20
+ readonly End: "End";
21
+ readonly PageUp: "PageUp";
22
+ readonly PageDown: "PageDown";
23
+ readonly Backspace: "Backspace";
24
+ readonly Delete: "Delete";
25
+ };
26
+ export type Key = (typeof Keys)[keyof typeof Keys];
27
+ /**
28
+ * Checks if a keyboard event matches the specified key.
29
+ */
30
+ export declare function isKey(event: KeyboardEvent, key: Key): boolean;
31
+ /**
32
+ * Checks if the event is an activation key (Enter or Space).
33
+ * Used for button-like elements.
34
+ */
35
+ export declare function isActivationKey(event: KeyboardEvent): boolean;
36
+ /**
37
+ * Checks if the event is a navigation key (arrows, home, end).
38
+ */
39
+ export declare function isNavigationKey(event: KeyboardEvent): boolean;
40
+ /**
41
+ * Creates a keyboard event handler for list navigation.
42
+ *
43
+ * @param options - Navigation options
44
+ * @returns Event handler function
45
+ *
46
+ * @example
47
+ * const handleKeyDown = createListNavigation({
48
+ * items: menuItems,
49
+ * currentIndex,
50
+ * onNavigate: (index) => { currentIndex = index; },
51
+ * onSelect: (index) => { selectItem(items[index]); },
52
+ * onCancel: () => { closeMenu(); }
53
+ * });
54
+ */
55
+ export interface ListNavigationOptions<T> {
56
+ /** List of items to navigate */
57
+ items: T[];
58
+ /** Currently focused index */
59
+ currentIndex: number;
60
+ /** Callback when navigation occurs */
61
+ onNavigate: (index: number) => void;
62
+ /** Callback when item is selected (Enter/Space) */
63
+ onSelect?: (index: number) => void;
64
+ /** Callback when navigation is cancelled (Escape) */
65
+ onCancel?: () => void;
66
+ /** Whether to loop at boundaries */
67
+ loop?: boolean;
68
+ /** Navigation orientation */
69
+ orientation?: 'vertical' | 'horizontal' | 'both';
70
+ }
71
+ export declare function createListNavigation<T>(options: ListNavigationOptions<T>): (event: KeyboardEvent) => void;
72
+ /**
73
+ * Creates a focus trap for modal-like components.
74
+ *
75
+ * @param containerElement - The container element to trap focus within
76
+ * @returns Object with activate/deactivate methods
77
+ *
78
+ * @example
79
+ * const trap = createFocusTrap(modalElement);
80
+ * trap.activate();
81
+ * // ... modal is open
82
+ * trap.deactivate();
83
+ */
84
+ export interface FocusTrap {
85
+ /** Activates the focus trap */
86
+ activate: () => void;
87
+ /** Deactivates the focus trap */
88
+ deactivate: () => void;
89
+ /** Returns the currently focused element */
90
+ getFocusedElement: () => Element | null;
91
+ }
92
+ export declare function createFocusTrap(containerElement: HTMLElement): FocusTrap;
93
+ export declare function generateId(prefix?: string): string;
94
+ //# sourceMappingURL=keyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/utils/keyboard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;CAeP,CAAC;AAEX,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;AAEnD;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAE7D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAS7D;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACvC,gCAAgC;IAChC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,oCAAoC;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6BAA6B;IAC7B,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;CACjD;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACrC,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC/B,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CA4EhC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,SAAS;IACzB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,iCAAiC;IACjC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,4CAA4C;IAC5C,iBAAiB,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;CACxC;AAED,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,WAAW,GAAG,SAAS,CAyDxE;AASD,wBAAgB,UAAU,CAAC,MAAM,SAAO,GAAG,MAAM,CAGhD"}