pulse-js-framework 1.7.33 → 1.7.38

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/types/a11y.d.ts CHANGED
@@ -91,6 +91,24 @@ export function restoreFocus(): void;
91
91
  */
92
92
  export function clearFocusStack(): void;
93
93
 
94
+ /**
95
+ * Handle escape key press within a container
96
+ * @returns Cleanup function to remove listener
97
+ */
98
+ export function onEscapeKey(
99
+ container: HTMLElement,
100
+ onEscape: () => void,
101
+ options?: { stopPropagation?: boolean }
102
+ ): () => void;
103
+
104
+ /**
105
+ * Track keyboard vs mouse focus for :focus-visible styling
106
+ */
107
+ export function createFocusVisibleTracker(): {
108
+ isKeyboardUser: Pulse<boolean>;
109
+ cleanup: () => void;
110
+ };
111
+
94
112
  // =============================================================================
95
113
  // SKIP LINKS
96
114
  // =============================================================================
@@ -138,10 +156,28 @@ export function prefersColorScheme(): 'light' | 'dark' | 'no-preference';
138
156
  */
139
157
  export function prefersHighContrast(): boolean;
140
158
 
159
+ /**
160
+ * Check if user prefers reduced transparency
161
+ */
162
+ export function prefersReducedTransparency(): boolean;
163
+
164
+ /**
165
+ * Check if forced colors mode is active (Windows High Contrast Mode)
166
+ */
167
+ export function forcedColorsMode(): 'active' | 'none';
168
+
169
+ /**
170
+ * Check user's preferred contrast level
171
+ */
172
+ export function prefersContrast(): 'no-preference' | 'more' | 'less' | 'custom';
173
+
141
174
  export interface UserPreferences {
142
175
  reducedMotion: Pulse<boolean>;
143
176
  colorScheme: Pulse<'light' | 'dark' | 'no-preference'>;
144
177
  highContrast: Pulse<boolean>;
178
+ reducedTransparency?: Pulse<boolean>;
179
+ forcedColors?: Pulse<'active' | 'none'>;
180
+ contrast?: Pulse<'no-preference' | 'more' | 'less' | 'custom'>;
145
181
  }
146
182
 
147
183
  /**
@@ -209,6 +245,96 @@ export function createTabs(
209
245
  options?: TabsOptions
210
246
  ): TabsControl;
211
247
 
248
+ // =============================================================================
249
+ // ARIA WIDGETS
250
+ // =============================================================================
251
+
252
+ export interface ModalOptions {
253
+ labelledBy?: string;
254
+ describedBy?: string;
255
+ closeOnBackdropClick?: boolean;
256
+ onClose?: () => void;
257
+ }
258
+
259
+ export interface ModalControl {
260
+ open: () => void;
261
+ close: () => void;
262
+ isOpen: Pulse<boolean>;
263
+ }
264
+
265
+ /**
266
+ * Create an ARIA-compliant modal dialog
267
+ */
268
+ export function createModal(
269
+ dialog: HTMLElement,
270
+ options?: ModalOptions
271
+ ): ModalControl;
272
+
273
+ export interface TooltipOptions {
274
+ showDelay?: number;
275
+ hideDelay?: number;
276
+ }
277
+
278
+ export interface TooltipControl {
279
+ isVisible: Pulse<boolean>;
280
+ cleanup: () => void;
281
+ }
282
+
283
+ /**
284
+ * Create an ARIA-compliant tooltip
285
+ */
286
+ export function createTooltip(
287
+ trigger: HTMLElement,
288
+ tooltip: HTMLElement,
289
+ options?: TooltipOptions
290
+ ): TooltipControl;
291
+
292
+ export interface AccordionOptions {
293
+ triggerSelector?: string;
294
+ panelSelector?: string;
295
+ allowMultiple?: boolean;
296
+ defaultOpen?: number;
297
+ }
298
+
299
+ export interface AccordionControl {
300
+ open: (index: number) => void;
301
+ close: (index: number) => void;
302
+ toggle: (index: number) => void;
303
+ closeAll: () => void;
304
+ openIndices: Pulse<number[]>;
305
+ cleanup: () => void;
306
+ }
307
+
308
+ /**
309
+ * Create an ARIA-compliant accordion
310
+ */
311
+ export function createAccordion(
312
+ container: HTMLElement,
313
+ options?: AccordionOptions
314
+ ): AccordionControl;
315
+
316
+ export interface MenuOptions {
317
+ itemSelector?: string;
318
+ closeOnSelect?: boolean;
319
+ onSelect?: (element: HTMLElement, index: number) => void;
320
+ }
321
+
322
+ export interface MenuControl {
323
+ open: () => void;
324
+ close: () => void;
325
+ toggle: () => void;
326
+ cleanup: () => void;
327
+ }
328
+
329
+ /**
330
+ * Create an ARIA-compliant dropdown menu
331
+ */
332
+ export function createMenu(
333
+ button: HTMLElement,
334
+ menu: HTMLElement,
335
+ options?: MenuOptions
336
+ ): MenuControl;
337
+
212
338
  // =============================================================================
213
339
  // KEYBOARD NAVIGATION
214
340
  // =============================================================================
@@ -260,6 +386,61 @@ export function logA11yIssues(issues: A11yIssue[]): void;
260
386
  */
261
387
  export function highlightA11yIssues(issues: A11yIssue[]): () => void;
262
388
 
389
+ // =============================================================================
390
+ // COLOR CONTRAST
391
+ // =============================================================================
392
+
393
+ /**
394
+ * Calculate WCAG contrast ratio between two colors
395
+ */
396
+ export function getContrastRatio(foreground: string, background: string): number;
397
+
398
+ /**
399
+ * Check if a contrast ratio meets WCAG requirements
400
+ */
401
+ export function meetsContrastRequirement(
402
+ ratio: number,
403
+ level?: 'AA' | 'AAA',
404
+ textSize?: 'normal' | 'large'
405
+ ): boolean;
406
+
407
+ /**
408
+ * Get the effective background color of an element (handles transparency)
409
+ */
410
+ export function getEffectiveBackgroundColor(element: HTMLElement): string;
411
+
412
+ /**
413
+ * Check contrast of a specific element
414
+ */
415
+ export function checkElementContrast(
416
+ element: HTMLElement,
417
+ level?: 'AA' | 'AAA'
418
+ ): {
419
+ ratio: number;
420
+ passes: boolean;
421
+ foreground: string;
422
+ background: string;
423
+ };
424
+
425
+ // =============================================================================
426
+ // ANNOUNCEMENT QUEUE
427
+ // =============================================================================
428
+
429
+ export interface AnnouncementQueueOptions {
430
+ minDelay?: number;
431
+ }
432
+
433
+ export interface AnnouncementQueue {
434
+ add: (message: string, options?: { priority?: 'polite' | 'assertive' }) => void;
435
+ clear: () => void;
436
+ queueLength: Pulse<number>;
437
+ }
438
+
439
+ /**
440
+ * Create a queue for managing multiple announcements
441
+ */
442
+ export function createAnnouncementQueue(options?: AnnouncementQueueOptions): AnnouncementQueue;
443
+
263
444
  // =============================================================================
264
445
  // UTILITIES
265
446
  // =============================================================================
@@ -285,6 +466,11 @@ export function makeInert(element: HTMLElement): () => void;
285
466
  */
286
467
  export function srOnly(text: string): HTMLSpanElement;
287
468
 
469
+ /**
470
+ * Compute the accessible name of an element (aria-label, text content, etc.)
471
+ */
472
+ export function getAccessibleName(element: HTMLElement): string;
473
+
288
474
  // =============================================================================
289
475
  // DEFAULT EXPORT
290
476
  // =============================================================================
@@ -0,0 +1,418 @@
1
+ /**
2
+ * Pulse Framework - DevTools Type Definitions
3
+ * @module pulse-js-framework/runtime/devtools
4
+ */
5
+
6
+ import { Pulse } from './pulse';
7
+
8
+ // =============================================================================
9
+ // CONFIGURATION
10
+ // =============================================================================
11
+
12
+ /** DevTools configuration options */
13
+ export interface DevToolsOptions {
14
+ /** Enable dev tools (default: false) */
15
+ enabled?: boolean;
16
+ /** Enable automatic timeline recording (default: false) */
17
+ autoTimeline?: boolean;
18
+ /** Debounce interval for auto-timeline in ms (default: 100) */
19
+ timelineDebounce?: number;
20
+ /** Maximum number of state snapshots to retain (default: 50) */
21
+ maxSnapshots?: number;
22
+ /** Log pulse updates to console (default: false) */
23
+ logUpdates?: boolean;
24
+ /** Warn when effects take longer than one frame (default: true) */
25
+ warnOnSlowEffects?: boolean;
26
+ }
27
+
28
+ // =============================================================================
29
+ // DIAGNOSTICS
30
+ // =============================================================================
31
+
32
+ /** Diagnostics summary of the reactive system */
33
+ export interface Diagnostics {
34
+ /** Number of tracked pulses */
35
+ pulseCount: number;
36
+ /** Number of tracked effects */
37
+ effectCount: number;
38
+ /** Average effect execution time in ms */
39
+ avgEffectTime: number;
40
+ /** Number of state snapshots in history */
41
+ snapshotCount: number;
42
+ /** Additional diagnostic properties */
43
+ [key: string]: unknown;
44
+ }
45
+
46
+ /** Performance statistics for a tracked effect */
47
+ export interface EffectStat {
48
+ /** Unique identifier of the effect */
49
+ id: string;
50
+ /** Display name of the effect */
51
+ name: string;
52
+ /** Number of times the effect has run */
53
+ runCount: number;
54
+ /** Average execution time in ms */
55
+ avgTime: number;
56
+ }
57
+
58
+ /** Information about a tracked pulse */
59
+ export interface PulseInfo {
60
+ /** Unique identifier of the pulse */
61
+ id: string;
62
+ /** Display name of the pulse */
63
+ name: string;
64
+ /** Current value of the pulse */
65
+ value: unknown;
66
+ /** Number of active subscribers */
67
+ subscriberCount: number;
68
+ }
69
+
70
+ /** Reactive dependency graph structure */
71
+ export interface DependencyGraph {
72
+ /** Nodes representing pulses and effects */
73
+ nodes: Array<{ id: string; type: string; name?: string }>;
74
+ /** Edges representing dependencies between nodes */
75
+ edges: Array<{ from: string; to: string }>;
76
+ }
77
+
78
+ /**
79
+ * Get diagnostics summary of the reactive system
80
+ */
81
+ export declare function getDiagnostics(): Diagnostics;
82
+
83
+ /**
84
+ * Get performance statistics for all tracked effects
85
+ */
86
+ export declare function getEffectStats(): EffectStat[];
87
+
88
+ /**
89
+ * Get information about all tracked pulses
90
+ */
91
+ export declare function getPulseList(): PulseInfo[];
92
+
93
+ /**
94
+ * Get the reactive dependency graph
95
+ */
96
+ export declare function getDependencyGraph(): DependencyGraph;
97
+
98
+ /**
99
+ * Export the dependency graph as a Graphviz DOT string
100
+ */
101
+ export declare function exportGraphAsDot(): string;
102
+
103
+ /**
104
+ * Create a tracked pulse with automatic snapshot on change.
105
+ * Integrates with time-travel debugging.
106
+ *
107
+ * @param initialValue - Initial value for the pulse
108
+ * @param name - Display name for debugging
109
+ * @returns A tracked pulse instance
110
+ */
111
+ export declare function trackedPulse<T>(initialValue: T, name?: string): Pulse<T>;
112
+
113
+ /**
114
+ * Create a tracked effect with performance monitoring.
115
+ * Execution time and run count are recorded.
116
+ *
117
+ * @param fn - Effect function (may return a cleanup function)
118
+ * @param name - Display name for debugging
119
+ * @returns Dispose function to stop the effect
120
+ */
121
+ export declare function trackedEffect(fn: () => void | (() => void), name?: string): () => void;
122
+
123
+ // =============================================================================
124
+ // PROFILING
125
+ // =============================================================================
126
+
127
+ /** Result of a profiled operation */
128
+ export interface ProfileResult {
129
+ /** Name of the profiled operation */
130
+ name: string;
131
+ /** Duration in ms */
132
+ duration: number;
133
+ /** Return value of the profiled function */
134
+ result: unknown;
135
+ }
136
+
137
+ /** Handle returned by mark() to end a timing measurement */
138
+ export interface MarkResult {
139
+ /** End the mark and return duration in ms */
140
+ end(): number;
141
+ }
142
+
143
+ /**
144
+ * Profile a synchronous function, logging its execution time
145
+ *
146
+ * @param name - Name for the profiling entry
147
+ * @param fn - Function to profile
148
+ * @returns Profile result with duration and return value
149
+ */
150
+ export declare function profile<T>(name: string, fn: () => T): ProfileResult;
151
+
152
+ /**
153
+ * Start a timing mark for manual profiling
154
+ *
155
+ * @param name - Name for the mark
156
+ * @returns A mark handle with an end() method
157
+ */
158
+ export declare function mark(name: string): MarkResult;
159
+
160
+ // =============================================================================
161
+ // TIME-TRAVEL
162
+ // =============================================================================
163
+
164
+ /** A state snapshot for time-travel debugging */
165
+ export interface Snapshot {
166
+ /** Description of the action that triggered this snapshot */
167
+ label: string;
168
+ /** Unix timestamp in ms when the snapshot was taken */
169
+ timestamp: number;
170
+ /** Serialized state of all tracked pulses */
171
+ state: Record<string, unknown>;
172
+ }
173
+
174
+ /**
175
+ * Take a snapshot of the current state of all tracked pulses
176
+ *
177
+ * @param label - Description of the action (default: 'manual')
178
+ */
179
+ export declare function takeSnapshot(label?: string): void;
180
+
181
+ /**
182
+ * Get all state snapshots in the history
183
+ */
184
+ export declare function getHistory(): Snapshot[];
185
+
186
+ /**
187
+ * Get the current position in history
188
+ */
189
+ export declare function getHistoryIndex(): number;
190
+
191
+ /**
192
+ * Restore state to a specific snapshot index
193
+ *
194
+ * @param index - History index to travel to
195
+ */
196
+ export declare function travelTo(index: number): void;
197
+
198
+ /**
199
+ * Go back one step in history
200
+ */
201
+ export declare function back(): void;
202
+
203
+ /**
204
+ * Go forward one step in history
205
+ */
206
+ export declare function forward(): void;
207
+
208
+ /**
209
+ * Clear all snapshots from history
210
+ */
211
+ export declare function clearHistory(): void;
212
+
213
+ // =============================================================================
214
+ // AUTO-TIMELINE
215
+ // =============================================================================
216
+
217
+ /**
218
+ * Enable automatic timeline recording.
219
+ * Records all pulse changes to the timeline with debouncing.
220
+ *
221
+ * @param options - Configuration options
222
+ */
223
+ export declare function enableAutoTimeline(options?: { debounce?: number }): void;
224
+
225
+ /**
226
+ * Disable automatic timeline recording
227
+ */
228
+ export declare function disableAutoTimeline(): void;
229
+
230
+ /**
231
+ * Check if auto-timeline recording is enabled
232
+ */
233
+ export declare function isAutoTimelineEnabled(): boolean;
234
+
235
+ // =============================================================================
236
+ // CONFIGURATION API
237
+ // =============================================================================
238
+
239
+ /**
240
+ * Enable dev tools and expose to window.__PULSE_DEVTOOLS__
241
+ *
242
+ * @param options - Configuration options
243
+ */
244
+ export declare function enableDevTools(options?: DevToolsOptions): void;
245
+
246
+ /**
247
+ * Disable dev tools and remove window.__PULSE_DEVTOOLS__
248
+ */
249
+ export declare function disableDevTools(): void;
250
+
251
+ /**
252
+ * Check if dev tools are enabled
253
+ */
254
+ export declare function isDevToolsEnabled(): boolean;
255
+
256
+ /**
257
+ * Update dev tools configuration
258
+ *
259
+ * @param options - Configuration options to merge
260
+ */
261
+ export declare function configureDevTools(options: DevToolsOptions): void;
262
+
263
+ /**
264
+ * Reset all dev tools data (diagnostics, history, and a11y audit)
265
+ */
266
+ export declare function resetDevTools(): void;
267
+
268
+ // =============================================================================
269
+ // A11Y AUDIT
270
+ // =============================================================================
271
+
272
+ /** An accessibility issue found during audit */
273
+ export interface A11yIssue {
274
+ /** Type/rule of the issue (e.g., 'missing-alt', 'no-label') */
275
+ type: string;
276
+ /** Human-readable description of the issue */
277
+ message: string;
278
+ /** The DOM element with the issue (if available) */
279
+ element?: Element;
280
+ /** Severity level */
281
+ severity: 'error' | 'warning' | 'info';
282
+ }
283
+
284
+ /** Summary statistics from an a11y audit */
285
+ export interface A11yStats {
286
+ /** Total number of issues found */
287
+ totalIssues: number;
288
+ /** Number of error-level issues */
289
+ errorCount: number;
290
+ /** Number of warning-level issues */
291
+ warningCount: number;
292
+ /** Number of info-level issues */
293
+ infoCount: number;
294
+ }
295
+
296
+ /** Configuration options for continuous a11y auditing */
297
+ export interface A11yAuditOptions {
298
+ /** Enable periodic audits (default: false) */
299
+ autoAudit?: boolean;
300
+ /** Interval between audits in ms (default: 5000) */
301
+ auditInterval?: number;
302
+ /** Show visual overlay on elements with issues (default: true) */
303
+ highlightIssues?: boolean;
304
+ /** Log issues to browser console (default: true) */
305
+ logToConsole?: boolean;
306
+ /** Trigger debugger breakpoint on errors (default: false) */
307
+ breakOnError?: boolean;
308
+ /** Re-audit when DOM changes via MutationObserver (default: false) */
309
+ watchMutations?: boolean;
310
+ }
311
+
312
+ /** Result returned by runA11yAudit() */
313
+ export interface A11yAuditResult {
314
+ /** List of accessibility issues found */
315
+ issues: A11yIssue[];
316
+ /** Number of error-level issues */
317
+ errorCount: number;
318
+ /** Number of warning-level issues */
319
+ warningCount: number;
320
+ }
321
+
322
+ /**
323
+ * Run an accessibility audit on the document or specific element
324
+ */
325
+ export declare function runA11yAudit(): A11yAuditResult;
326
+
327
+ /**
328
+ * Get all current a11y issues from the last audit
329
+ */
330
+ export declare function getA11yIssues(): A11yIssue[];
331
+
332
+ /**
333
+ * Get summary statistics of a11y issues
334
+ */
335
+ export declare function getA11yStats(): A11yStats;
336
+
337
+ /**
338
+ * Enable continuous a11y auditing with optional configuration
339
+ *
340
+ * @param options - Audit configuration options
341
+ */
342
+ export declare function enableA11yAudit(options?: A11yAuditOptions): void;
343
+
344
+ /**
345
+ * Disable continuous a11y auditing and clean up resources
346
+ */
347
+ export declare function disableA11yAudit(): void;
348
+
349
+ /**
350
+ * Toggle visual highlighting of a11y issues in the DOM
351
+ *
352
+ * @param show - Force show/hide, or toggle if omitted
353
+ */
354
+ export declare function toggleA11yHighlights(show?: boolean): void;
355
+
356
+ /**
357
+ * Export the a11y audit report in the specified format
358
+ *
359
+ * @param format - Output format
360
+ * @returns Formatted report string
361
+ */
362
+ export declare function exportA11yReport(format: 'json' | 'csv' | 'html'): string;
363
+
364
+ /**
365
+ * Reset a11y audit state (clear issues, stop observers)
366
+ */
367
+ export declare function resetA11yAudit(): void;
368
+
369
+ // =============================================================================
370
+ // DEFAULT EXPORT
371
+ // =============================================================================
372
+
373
+ export interface PulseDevTools {
374
+ // Diagnostics
375
+ getDiagnostics: typeof getDiagnostics;
376
+ getEffectStats: typeof getEffectStats;
377
+ getPulseList: typeof getPulseList;
378
+ getDependencyGraph: typeof getDependencyGraph;
379
+ exportGraphAsDot: typeof exportGraphAsDot;
380
+ trackedPulse: typeof trackedPulse;
381
+ trackedEffect: typeof trackedEffect;
382
+ profile: typeof profile;
383
+ mark: typeof mark;
384
+
385
+ // Time-travel
386
+ takeSnapshot: typeof takeSnapshot;
387
+ getHistory: typeof getHistory;
388
+ getHistoryIndex: typeof getHistoryIndex;
389
+ travelTo: typeof travelTo;
390
+ back: typeof back;
391
+ forward: typeof forward;
392
+ clearHistory: typeof clearHistory;
393
+
394
+ // Auto-timeline
395
+ enableAutoTimeline: typeof enableAutoTimeline;
396
+ disableAutoTimeline: typeof disableAutoTimeline;
397
+ isAutoTimelineEnabled: typeof isAutoTimelineEnabled;
398
+
399
+ // Configuration
400
+ enableDevTools: typeof enableDevTools;
401
+ disableDevTools: typeof disableDevTools;
402
+ isDevToolsEnabled: typeof isDevToolsEnabled;
403
+ configureDevTools: typeof configureDevTools;
404
+ resetDevTools: typeof resetDevTools;
405
+
406
+ // Accessibility Audit
407
+ runA11yAudit: typeof runA11yAudit;
408
+ getA11yIssues: typeof getA11yIssues;
409
+ getA11yStats: typeof getA11yStats;
410
+ enableA11yAudit: typeof enableA11yAudit;
411
+ disableA11yAudit: typeof disableA11yAudit;
412
+ toggleA11yHighlights: typeof toggleA11yHighlights;
413
+ exportA11yReport: typeof exportA11yReport;
414
+ resetA11yAudit: typeof resetA11yAudit;
415
+ }
416
+
417
+ declare const _default: PulseDevTools;
418
+ export default _default;