@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,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"}
|
package/dist/utils/cn.js
ADDED
|
@@ -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"}
|