pulse-js-framework 1.7.9 → 1.7.10
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/cli/lint.js +442 -3
- package/compiler/lexer.js +6 -0
- package/compiler/parser.js +144 -1
- package/compiler/transformer/imports.js +15 -0
- package/compiler/transformer/index.js +46 -0
- package/compiler/transformer/view.js +180 -5
- package/package.json +9 -2
- package/runtime/a11y.js +1005 -0
- package/runtime/devtools/a11y-audit.js +442 -0
- package/runtime/devtools/diagnostics.js +403 -0
- package/runtime/devtools/index.js +53 -0
- package/runtime/devtools/time-travel.js +189 -0
- package/runtime/devtools.js +138 -497
- package/runtime/dom-binding.js +7 -4
- package/runtime/dom-element.js +192 -1
- package/runtime/dom.js +8 -2
- package/runtime/index.js +2 -0
- package/runtime/native.js +2 -2
- package/runtime/security.js +461 -0
- package/runtime/utils.js +37 -16
- package/types/a11y.d.ts +336 -0
package/types/a11y.d.ts
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse A11y - TypeScript Definitions
|
|
3
|
+
* Accessibility utilities for inclusive web applications
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Pulse } from './pulse';
|
|
7
|
+
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// LIVE REGIONS
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
export interface AnnounceOptions {
|
|
13
|
+
/** Announcement priority (default: 'polite') */
|
|
14
|
+
priority?: 'polite' | 'assertive';
|
|
15
|
+
/** Clear message after ms (default: 1000, 0 = never) */
|
|
16
|
+
clearAfter?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Announce a message to screen readers
|
|
21
|
+
*/
|
|
22
|
+
export function announce(message: string, options?: AnnounceOptions): void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Announce politely (waits for user to finish current task)
|
|
26
|
+
*/
|
|
27
|
+
export function announcePolite(message: string): void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Announce assertively (interrupts current announcement)
|
|
31
|
+
*/
|
|
32
|
+
export function announceAssertive(message: string): void;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a reactive live region that announces when value changes
|
|
36
|
+
*/
|
|
37
|
+
export function createLiveAnnouncer(
|
|
38
|
+
getter: () => string | null | undefined,
|
|
39
|
+
options?: AnnounceOptions
|
|
40
|
+
): () => void;
|
|
41
|
+
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// FOCUS MANAGEMENT
|
|
44
|
+
// =============================================================================
|
|
45
|
+
|
|
46
|
+
export interface TrapFocusOptions {
|
|
47
|
+
/** Auto focus first element (default: true) */
|
|
48
|
+
autoFocus?: boolean;
|
|
49
|
+
/** Return focus on release (default: true) */
|
|
50
|
+
returnFocus?: boolean;
|
|
51
|
+
/** Element to focus initially */
|
|
52
|
+
initialFocus?: HTMLElement | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get all focusable elements within a container
|
|
57
|
+
*/
|
|
58
|
+
export function getFocusableElements(container: HTMLElement): HTMLElement[];
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Focus the first focusable element in a container
|
|
62
|
+
*/
|
|
63
|
+
export function focusFirst(container: HTMLElement): HTMLElement | null;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Focus the last focusable element in a container
|
|
67
|
+
*/
|
|
68
|
+
export function focusLast(container: HTMLElement): HTMLElement | null;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Trap focus within a container (for modals, dialogs)
|
|
72
|
+
* @returns Release function to remove trap
|
|
73
|
+
*/
|
|
74
|
+
export function trapFocus(
|
|
75
|
+
container: HTMLElement,
|
|
76
|
+
options?: TrapFocusOptions
|
|
77
|
+
): () => void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Save current focus to stack
|
|
81
|
+
*/
|
|
82
|
+
export function saveFocus(): void;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Restore focus from stack
|
|
86
|
+
*/
|
|
87
|
+
export function restoreFocus(): void;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Clear focus stack
|
|
91
|
+
*/
|
|
92
|
+
export function clearFocusStack(): void;
|
|
93
|
+
|
|
94
|
+
// =============================================================================
|
|
95
|
+
// SKIP LINKS
|
|
96
|
+
// =============================================================================
|
|
97
|
+
|
|
98
|
+
export interface SkipLinkOptions {
|
|
99
|
+
/** CSS class name */
|
|
100
|
+
className?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Create a skip link for keyboard navigation
|
|
105
|
+
*/
|
|
106
|
+
export function createSkipLink(
|
|
107
|
+
targetId: string,
|
|
108
|
+
text?: string,
|
|
109
|
+
options?: SkipLinkOptions
|
|
110
|
+
): HTMLAnchorElement;
|
|
111
|
+
|
|
112
|
+
export interface SkipLinkDefinition {
|
|
113
|
+
target: string;
|
|
114
|
+
text: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Install skip links at the beginning of the document
|
|
119
|
+
*/
|
|
120
|
+
export function installSkipLinks(links: SkipLinkDefinition[]): HTMLElement;
|
|
121
|
+
|
|
122
|
+
// =============================================================================
|
|
123
|
+
// USER PREFERENCES
|
|
124
|
+
// =============================================================================
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check if user prefers reduced motion
|
|
128
|
+
*/
|
|
129
|
+
export function prefersReducedMotion(): boolean;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Check user's preferred color scheme
|
|
133
|
+
*/
|
|
134
|
+
export function prefersColorScheme(): 'light' | 'dark' | 'no-preference';
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Check if user prefers high contrast
|
|
138
|
+
*/
|
|
139
|
+
export function prefersHighContrast(): boolean;
|
|
140
|
+
|
|
141
|
+
export interface UserPreferences {
|
|
142
|
+
reducedMotion: Pulse<boolean>;
|
|
143
|
+
colorScheme: Pulse<'light' | 'dark' | 'no-preference'>;
|
|
144
|
+
highContrast: Pulse<boolean>;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Create reactive user preferences pulse
|
|
149
|
+
*/
|
|
150
|
+
export function createPreferences(): UserPreferences;
|
|
151
|
+
|
|
152
|
+
// =============================================================================
|
|
153
|
+
// ARIA HELPERS
|
|
154
|
+
// =============================================================================
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Set multiple ARIA attributes on an element
|
|
158
|
+
* @param attrs - ARIA attributes without 'aria-' prefix
|
|
159
|
+
*/
|
|
160
|
+
export function setAriaAttributes(
|
|
161
|
+
element: HTMLElement,
|
|
162
|
+
attrs: Record<string, string | number | boolean | null | undefined>
|
|
163
|
+
): void;
|
|
164
|
+
|
|
165
|
+
export interface DisclosureOptions {
|
|
166
|
+
/** Start in open state */
|
|
167
|
+
defaultOpen?: boolean;
|
|
168
|
+
/** Callback when toggled */
|
|
169
|
+
onToggle?: (isOpen: boolean) => void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface DisclosureControl {
|
|
173
|
+
expanded: Pulse<boolean>;
|
|
174
|
+
toggle: () => void;
|
|
175
|
+
open: () => void;
|
|
176
|
+
close: () => void;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Create an ARIA-compliant disclosure widget
|
|
181
|
+
*/
|
|
182
|
+
export function createDisclosure(
|
|
183
|
+
trigger: HTMLElement,
|
|
184
|
+
content: HTMLElement,
|
|
185
|
+
options?: DisclosureOptions
|
|
186
|
+
): DisclosureControl;
|
|
187
|
+
|
|
188
|
+
export interface TabsOptions {
|
|
189
|
+
/** Initially selected tab index */
|
|
190
|
+
defaultIndex?: number;
|
|
191
|
+
/** Tab orientation */
|
|
192
|
+
orientation?: 'horizontal' | 'vertical';
|
|
193
|
+
/** Callback when tab selected */
|
|
194
|
+
onSelect?: (index: number) => void;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface TabsControl {
|
|
198
|
+
selectedIndex: Pulse<number>;
|
|
199
|
+
select: (index: number) => void;
|
|
200
|
+
tabs: HTMLElement[];
|
|
201
|
+
panels: (HTMLElement | null)[];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Create ARIA-compliant tabs
|
|
206
|
+
*/
|
|
207
|
+
export function createTabs(
|
|
208
|
+
tablist: HTMLElement,
|
|
209
|
+
options?: TabsOptions
|
|
210
|
+
): TabsControl;
|
|
211
|
+
|
|
212
|
+
// =============================================================================
|
|
213
|
+
// KEYBOARD NAVIGATION
|
|
214
|
+
// =============================================================================
|
|
215
|
+
|
|
216
|
+
export interface RovingTabindexOptions {
|
|
217
|
+
/** Selector for items */
|
|
218
|
+
selector?: string;
|
|
219
|
+
/** Navigation orientation */
|
|
220
|
+
orientation?: 'horizontal' | 'vertical';
|
|
221
|
+
/** Loop navigation */
|
|
222
|
+
loop?: boolean;
|
|
223
|
+
/** Selection callback */
|
|
224
|
+
onSelect?: (element: HTMLElement, index: number) => void;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Handle arrow key navigation within a container (roving tabindex)
|
|
229
|
+
* @returns Cleanup function
|
|
230
|
+
*/
|
|
231
|
+
export function createRovingTabindex(
|
|
232
|
+
container: HTMLElement,
|
|
233
|
+
options?: RovingTabindexOptions
|
|
234
|
+
): () => void;
|
|
235
|
+
|
|
236
|
+
// =============================================================================
|
|
237
|
+
// VALIDATION & AUDITING
|
|
238
|
+
// =============================================================================
|
|
239
|
+
|
|
240
|
+
export interface A11yIssue {
|
|
241
|
+
severity: 'error' | 'warning';
|
|
242
|
+
rule: string;
|
|
243
|
+
message: string;
|
|
244
|
+
element: HTMLElement;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Validate accessibility of a container
|
|
249
|
+
*/
|
|
250
|
+
export function validateA11y(container?: HTMLElement): A11yIssue[];
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Log validation results to console
|
|
254
|
+
*/
|
|
255
|
+
export function logA11yIssues(issues: A11yIssue[]): void;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Highlight elements with accessibility issues in the DOM
|
|
259
|
+
* @returns Cleanup function to remove highlights
|
|
260
|
+
*/
|
|
261
|
+
export function highlightA11yIssues(issues: A11yIssue[]): () => void;
|
|
262
|
+
|
|
263
|
+
// =============================================================================
|
|
264
|
+
// UTILITIES
|
|
265
|
+
// =============================================================================
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Generate a unique ID for ARIA relationships
|
|
269
|
+
*/
|
|
270
|
+
export function generateId(prefix?: string): string;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Check if an element is visible to screen readers
|
|
274
|
+
*/
|
|
275
|
+
export function isAccessiblyHidden(element: HTMLElement | null): boolean;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Make an element inert (non-interactive, hidden from a11y tree)
|
|
279
|
+
* @returns Restore function
|
|
280
|
+
*/
|
|
281
|
+
export function makeInert(element: HTMLElement): () => void;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Create screen reader only text (visually hidden)
|
|
285
|
+
*/
|
|
286
|
+
export function srOnly(text: string): HTMLSpanElement;
|
|
287
|
+
|
|
288
|
+
// =============================================================================
|
|
289
|
+
// DEFAULT EXPORT
|
|
290
|
+
// =============================================================================
|
|
291
|
+
|
|
292
|
+
export interface PulseA11y {
|
|
293
|
+
// Announcements
|
|
294
|
+
announce: typeof announce;
|
|
295
|
+
announcePolite: typeof announcePolite;
|
|
296
|
+
announceAssertive: typeof announceAssertive;
|
|
297
|
+
createLiveAnnouncer: typeof createLiveAnnouncer;
|
|
298
|
+
|
|
299
|
+
// Focus
|
|
300
|
+
trapFocus: typeof trapFocus;
|
|
301
|
+
focusFirst: typeof focusFirst;
|
|
302
|
+
focusLast: typeof focusLast;
|
|
303
|
+
saveFocus: typeof saveFocus;
|
|
304
|
+
restoreFocus: typeof restoreFocus;
|
|
305
|
+
getFocusableElements: typeof getFocusableElements;
|
|
306
|
+
|
|
307
|
+
// Skip links
|
|
308
|
+
createSkipLink: typeof createSkipLink;
|
|
309
|
+
installSkipLinks: typeof installSkipLinks;
|
|
310
|
+
|
|
311
|
+
// Preferences
|
|
312
|
+
prefersReducedMotion: typeof prefersReducedMotion;
|
|
313
|
+
prefersColorScheme: typeof prefersColorScheme;
|
|
314
|
+
prefersHighContrast: typeof prefersHighContrast;
|
|
315
|
+
createPreferences: typeof createPreferences;
|
|
316
|
+
|
|
317
|
+
// ARIA helpers
|
|
318
|
+
setAriaAttributes: typeof setAriaAttributes;
|
|
319
|
+
createDisclosure: typeof createDisclosure;
|
|
320
|
+
createTabs: typeof createTabs;
|
|
321
|
+
createRovingTabindex: typeof createRovingTabindex;
|
|
322
|
+
|
|
323
|
+
// Validation
|
|
324
|
+
validateA11y: typeof validateA11y;
|
|
325
|
+
logA11yIssues: typeof logA11yIssues;
|
|
326
|
+
highlightA11yIssues: typeof highlightA11yIssues;
|
|
327
|
+
|
|
328
|
+
// Utilities
|
|
329
|
+
generateId: typeof generateId;
|
|
330
|
+
isAccessiblyHidden: typeof isAccessiblyHidden;
|
|
331
|
+
makeInert: typeof makeInert;
|
|
332
|
+
srOnly: typeof srOnly;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
declare const _default: PulseA11y;
|
|
336
|
+
export default _default;
|