ieee-atiig-accessibility-menu 0.1.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/dist/index.js ADDED
@@ -0,0 +1,801 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
+
4
+ var MOBILE_BREAKPOINT = 768;
5
+ function useIsMobile(breakpoint = MOBILE_BREAKPOINT) {
6
+ const [isMobile, setIsMobile] = useState(false);
7
+ useEffect(() => {
8
+ const check = () => setIsMobile(window.innerWidth < breakpoint);
9
+ check();
10
+ window.addEventListener("resize", check);
11
+ return () => window.removeEventListener("resize", check);
12
+ }, [breakpoint]);
13
+ return isMobile;
14
+ }
15
+ function useMousePosition(isMobile) {
16
+ const [mousePos, setMousePos] = useState({ y: 300 });
17
+ useEffect(() => {
18
+ if (isMobile) {
19
+ const handleTouch = (e) => {
20
+ if (e.touches.length > 0) setMousePos({ y: e.touches[0].clientY });
21
+ };
22
+ window.addEventListener("touchmove", handleTouch, { passive: true });
23
+ return () => window.removeEventListener("touchmove", handleTouch);
24
+ }
25
+ const handleMouseMove = (e) => setMousePos({ y: e.clientY });
26
+ window.addEventListener("mousemove", handleMouseMove);
27
+ return () => window.removeEventListener("mousemove", handleMouseMove);
28
+ }, [isMobile]);
29
+ return mousePos;
30
+ }
31
+
32
+ // src/types.ts
33
+ var DEFAULT_SETTINGS = {
34
+ fontSize: 0,
35
+ lineHeight: 0,
36
+ textAlign: "off",
37
+ dyslexicFont: false,
38
+ grayscale: false,
39
+ stopAnimations: false,
40
+ bigCursor: false,
41
+ readingAid: false,
42
+ readingAidSize: 1
43
+ };
44
+ var DEFAULT_LABELS = {
45
+ fontSize: "Font Size",
46
+ lineHeight: "Line Height",
47
+ alignment: "Alignment",
48
+ readingAid: "Reading Aid",
49
+ desaturate: "Desaturate",
50
+ dyslexicFont: "Dyslexia Friendly",
51
+ bigCursor: "Big Cursor",
52
+ stopAnimations: "Stop Animations",
53
+ reset: "Reset Settings",
54
+ menuTitle: "Accessibility",
55
+ menuButton: "Accessibility Menu",
56
+ off: "Off"
57
+ };
58
+ var DEFAULT_Z_INDEX = {
59
+ button: 60,
60
+ overlay: 65,
61
+ panel: 70,
62
+ readingAid: 9998
63
+ };
64
+ var DEFAULT_THEME = {
65
+ primary: "#023A74",
66
+ primaryHover: "#012a55",
67
+ accent: "#01A0A0",
68
+ accentOverlay: "rgba(1, 160, 160, 0.6)",
69
+ border: "#e2e8f0",
70
+ background: "#ffffff",
71
+ text: "#0f172a",
72
+ textMuted: "#94a3b8",
73
+ activeBg: "rgba(1, 160, 160, 0.05)",
74
+ activeBorder: "rgba(1, 160, 160, 0.2)",
75
+ gradientFrom: "#023A74",
76
+ gradientTo: "#01A0A0"
77
+ };
78
+ var ROOT_CLASSES = {
79
+ fontSize: (v) => `a11y-font-size-${v}`,
80
+ lineHeight: (v) => `a11y-line-height-${v}`,
81
+ textAlign: (v) => `a11y-align-${v}`,
82
+ dyslexicFont: "a11y-dyslexic-font",
83
+ grayscale: "a11y-grayscale",
84
+ stopAnimations: "a11y-stop-animations",
85
+ bigCursor: "a11y-big-cursor"
86
+ };
87
+ var ALL_ROOT_CLASSES = [
88
+ "a11y-font-size-10",
89
+ "a11y-font-size-20",
90
+ "a11y-font-size-30",
91
+ "a11y-line-height-15",
92
+ "a11y-line-height-20",
93
+ "a11y-line-height-25",
94
+ "a11y-align-left",
95
+ "a11y-align-right",
96
+ "a11y-align-center",
97
+ "a11y-align-justify",
98
+ "a11y-dyslexic-font",
99
+ "a11y-grayscale",
100
+ "a11y-stop-animations",
101
+ "a11y-big-cursor"
102
+ ];
103
+
104
+ // src/use-settings.ts
105
+ function applyRootClasses(settings) {
106
+ const root = document.documentElement;
107
+ ALL_ROOT_CLASSES.forEach((cls) => root.classList.remove(cls));
108
+ if (settings.fontSize > 0) root.classList.add(`a11y-font-size-${settings.fontSize}`);
109
+ if (settings.lineHeight > 0) root.classList.add(`a11y-line-height-${settings.lineHeight}`);
110
+ if (settings.textAlign !== "off") root.classList.add(`a11y-align-${settings.textAlign}`);
111
+ if (settings.dyslexicFont) root.classList.add("a11y-dyslexic-font");
112
+ if (settings.grayscale) root.classList.add("a11y-grayscale");
113
+ if (settings.stopAnimations) root.classList.add("a11y-stop-animations");
114
+ if (settings.bigCursor) root.classList.add("a11y-big-cursor");
115
+ }
116
+ function useSettings(storageKey, initialSettings, onSettingsChange) {
117
+ const [settings, setSettings] = useState(() => {
118
+ if (typeof window === "undefined") {
119
+ return { ...DEFAULT_SETTINGS, ...initialSettings };
120
+ }
121
+ try {
122
+ const saved = localStorage.getItem(storageKey);
123
+ if (saved) {
124
+ return { ...DEFAULT_SETTINGS, ...JSON.parse(saved), ...initialSettings };
125
+ }
126
+ } catch (error) {
127
+ console.error(`[ieee-atiig-accessibility-menu] Failed to parse stored settings:`, error);
128
+ }
129
+ return { ...DEFAULT_SETTINGS, ...initialSettings };
130
+ });
131
+ useEffect(() => {
132
+ applyRootClasses(settings);
133
+ }, [settings]);
134
+ const persist = useCallback(
135
+ (next) => {
136
+ if (typeof window !== "undefined") {
137
+ try {
138
+ localStorage.setItem(storageKey, JSON.stringify(next));
139
+ } catch (error) {
140
+ console.error(`[ieee-atiig-accessibility-menu] Failed to persist settings:`, error);
141
+ }
142
+ }
143
+ onSettingsChange?.(next);
144
+ },
145
+ [storageKey, onSettingsChange]
146
+ );
147
+ const setVal = useCallback(
148
+ (key, val) => {
149
+ setSettings((prev) => {
150
+ const next = { ...prev, [key]: val };
151
+ persist(next);
152
+ return next;
153
+ });
154
+ },
155
+ [persist]
156
+ );
157
+ const resetSettings = useCallback(() => {
158
+ const defaults = { ...DEFAULT_SETTINGS, ...initialSettings };
159
+ setSettings(defaults);
160
+ persist(defaults);
161
+ }, [initialSettings, persist]);
162
+ return { settings, setVal, resetSettings };
163
+ }
164
+ var STYLE_ID = "ieee-atiig-accessibility-menu-injected-styles";
165
+ function useInjectStyles(styles2) {
166
+ useEffect(() => {
167
+ if (typeof window === "undefined") return;
168
+ if (document.getElementById(STYLE_ID)) return;
169
+ if (styles2) {
170
+ const style = document.createElement("style");
171
+ style.id = STYLE_ID;
172
+ style.textContent = styles2;
173
+ document.head.appendChild(style);
174
+ }
175
+ }, [styles2]);
176
+ }
177
+ function ReadingAid({ mouseY, size, zIndex, theme: themeProp }) {
178
+ const theme = { ...DEFAULT_THEME, ...themeProp };
179
+ const readingAidHeight = 56 * (size || 1);
180
+ const offset = readingAidHeight / 2;
181
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
182
+ /* @__PURE__ */ jsx(
183
+ "div",
184
+ {
185
+ className: "a11y-menu-reading-aid-shade",
186
+ "data-side": "top",
187
+ style: {
188
+ height: `${Math.max(0, mouseY - offset)}px`,
189
+ zIndex,
190
+ background: `rgba(2, 58, 116, 0.62)`
191
+ }
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsx(
195
+ "div",
196
+ {
197
+ className: "a11y-menu-reading-aid-shade",
198
+ "data-side": "bottom",
199
+ style: {
200
+ top: `${mouseY + offset}px`,
201
+ zIndex,
202
+ background: `rgba(2, 58, 116, 0.62)`
203
+ }
204
+ }
205
+ ),
206
+ /* @__PURE__ */ jsx(
207
+ "div",
208
+ {
209
+ className: "a11y-menu-reading-aid-bar",
210
+ style: {
211
+ top: `${mouseY - offset}px`,
212
+ height: `${readingAidHeight}px`,
213
+ zIndex: zIndex - 1,
214
+ background: "rgba(1, 160, 160, 0.06)",
215
+ borderTop: `2px solid ${theme.accentOverlay}`,
216
+ borderBottom: `2px solid ${theme.accentOverlay}`
217
+ }
218
+ }
219
+ )
220
+ ] });
221
+ }
222
+ function AccessibilityToggle({ icon, label, isActive, onToggle, theme: themeProp }) {
223
+ const t = { ...DEFAULT_THEME, ...themeProp };
224
+ return /* @__PURE__ */ jsxs(
225
+ "button",
226
+ {
227
+ onClick: onToggle,
228
+ className: "a11y-menu-toggle",
229
+ "data-active": isActive,
230
+ type: "button",
231
+ "aria-pressed": isActive,
232
+ style: {
233
+ borderColor: isActive ? t.activeBorder : "transparent",
234
+ backgroundColor: isActive ? t.activeBg : t.background
235
+ },
236
+ children: [
237
+ /* @__PURE__ */ jsxs("div", { className: "a11y-menu-toggle-left", children: [
238
+ /* @__PURE__ */ jsx(
239
+ "div",
240
+ {
241
+ className: "a11y-menu-toggle-icon-wrap",
242
+ "data-active": isActive,
243
+ style: {
244
+ background: isActive ? `linear-gradient(135deg, ${t.gradientFrom}, ${t.gradientTo})` : void 0
245
+ },
246
+ children: icon
247
+ }
248
+ ),
249
+ /* @__PURE__ */ jsx(
250
+ "span",
251
+ {
252
+ className: "a11y-menu-toggle-label",
253
+ style: { color: isActive ? t.primary : void 0 },
254
+ children: label
255
+ }
256
+ )
257
+ ] }),
258
+ /* @__PURE__ */ jsx(
259
+ "div",
260
+ {
261
+ className: "a11y-menu-toggle-check",
262
+ "data-active": isActive,
263
+ style: {
264
+ backgroundColor: isActive ? t.accent : void 0,
265
+ borderColor: isActive ? t.accent : t.border
266
+ },
267
+ children: /* @__PURE__ */ jsx(
268
+ "svg",
269
+ {
270
+ className: "a11y-menu-check-icon",
271
+ viewBox: "0 0 24 24",
272
+ fill: "none",
273
+ stroke: "currentColor",
274
+ strokeWidth: 5,
275
+ strokeLinecap: "round",
276
+ strokeLinejoin: "round",
277
+ children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
278
+ }
279
+ )
280
+ }
281
+ )
282
+ ]
283
+ }
284
+ );
285
+ }
286
+
287
+ // src/styles.ts
288
+ var styles = `
289
+ /* ===== ieee-atiig-accessibility-menu: Core Styles ===== */
290
+
291
+ .a11y-font-size-10 { font-size: 110% !important; }
292
+ .a11y-font-size-20 { font-size: 120% !important; }
293
+ .a11y-font-size-30 { font-size: 130% !important; }
294
+
295
+ .a11y-line-height-15 { line-height: 1.5 !important; }
296
+ .a11y-line-height-20 { line-height: 2 !important; }
297
+ .a11y-line-height-25 { line-height: 2.5 !important; }
298
+
299
+ .a11y-align-left :where(h1, h2, h3, h4, h5, h6, p, li, blockquote, figcaption) { text-align: left !important; }
300
+ .a11y-align-center :where(h1, h2, h3, h4, h5, h6, p, li, blockquote, figcaption) { text-align: center !important; }
301
+ .a11y-align-right :where(h1, h2, h3, h4, h5, h6, p, li, blockquote, figcaption) { text-align: right !important; }
302
+ .a11y-align-justify :where(h1, h2, h3, h4, h5, h6, p, li, blockquote, figcaption) { text-align: justify !important; }
303
+
304
+ .a11y-dyslexic-font,
305
+ .a11y-dyslexic-font * {
306
+ font-family: "OpenDyslexic", "Comic Sans MS", "Lexie Readable", sans-serif !important;
307
+ font-style: normal !important;
308
+ }
309
+
310
+ .a11y-grayscale,
311
+ .a11y-grayscale * {
312
+ filter: grayscale(100%) !important;
313
+ -webkit-filter: grayscale(100%) !important;
314
+ }
315
+
316
+ .a11y-stop-animations,
317
+ .a11y-stop-animations *,
318
+ .a11y-stop-animations *::before,
319
+ .a11y-stop-animations *::after {
320
+ animation-duration: 0s !important;
321
+ animation-delay: 0s !important;
322
+ transition-duration: 0s !important;
323
+ transition-delay: 0s !important;
324
+ }
325
+
326
+ .a11y-big-cursor * {
327
+ cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewBox='0 0 40 48'><defs><filter id='shadow'><feDropShadow dx='1' dy='1' stdDeviation='1' flood-opacity='0.5'/></filter></defs><path d='M5 2 L5 35 L12 28 L20 44 L25 42 L17 26 L30 26 Z' fill='white' stroke='black' stroke-width='2' filter='url(%23shadow)'/></svg>") 10 0, default !important;
328
+ }
329
+
330
+ .a11y-menu-reading-aid-shade {
331
+ position: fixed; left: 0; right: 0; pointer-events: none;
332
+ }
333
+
334
+ .a11y-menu-reading-aid-bar {
335
+ position: fixed; left: 0; right: 0; pointer-events: none;
336
+ }
337
+
338
+ .a11y-menu-button {
339
+ position: fixed; z-index: 60; display: flex; align-items: center; justify-content: center;
340
+ width: 56px; height: 56px; border: none; border-radius: 50%; cursor: pointer;
341
+ color: #fff; transition: transform 0.3s ease, box-shadow 0.3s ease, background 0.3s ease;
342
+ }
343
+ .a11y-menu-button:hover { transform: scale(1.1); }
344
+ .a11y-menu-button:active { transform: scale(0.95); }
345
+ .a11y-menu-button[data-open="true"] { transform: rotate(180deg); }
346
+ .a11y-menu-button-icon { width: 24px; height: 24px; }
347
+
348
+ .a11y-menu-overlay {
349
+ position: fixed; inset: 0; z-index: 65;
350
+ background: rgba(0, 0, 0, 0.2);
351
+ backdrop-filter: blur(2px);
352
+ -webkit-backdrop-filter: blur(2px);
353
+ }
354
+
355
+ .a11y-menu-panel {
356
+ position: fixed; z-index: 70;
357
+ width: calc(100% - 32px); max-width: 320px;
358
+ padding: 20px; border: 1px solid; border-radius: 24px;
359
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25); overflow: hidden;
360
+ animation: a11y-menu-fade-in 0.3s ease;
361
+ }
362
+
363
+ @keyframes a11y-menu-fade-in {
364
+ from { opacity: 0; transform: translateY(10px); }
365
+ to { opacity: 1; transform: translateY(0); }
366
+ }
367
+
368
+ @media (min-width: 768px) {
369
+ .a11y-menu-panel { left: 20px; right: auto; }
370
+ .a11y-menu-panel[data-right="true"] { left: auto; right: 20px; }
371
+ }
372
+
373
+ .a11y-menu-header {
374
+ display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px;
375
+ }
376
+ .a11y-menu-header-left { display: flex; align-items: center; gap: 12px; }
377
+ .a11y-menu-header-icon {
378
+ width: 36px; height: 36px; border-radius: 16px;
379
+ display: flex; align-items: center; justify-content: center;
380
+ color: #fff; box-shadow: 0 4px 14px rgba(2, 58, 116, 0.15);
381
+ }
382
+ .a11y-menu-header-icon svg { width: 16px; height: 16px; }
383
+ .a11y-menu-title {
384
+ font-size: 10px; font-weight: 900; text-transform: uppercase;
385
+ letter-spacing: 0.1em; margin: 0;
386
+ }
387
+ .a11y-menu-close {
388
+ width: 28px; height: 28px; border-radius: 50%; border: none;
389
+ background: transparent; cursor: pointer; display: flex;
390
+ align-items: center; justify-content: center; color: #94a3b8;
391
+ transition: background 0.2s ease;
392
+ }
393
+ .a11y-menu-close:hover { background: #f1f5f9; }
394
+ .a11y-menu-close svg { width: 16px; height: 16px; }
395
+
396
+ .a11y-menu-body { max-height: 65vh; overflow-y: auto; padding-right: 4px; }
397
+ .a11y-menu-body::-webkit-scrollbar { width: 4px; }
398
+ .a11y-menu-body::-webkit-scrollbar-track { background: transparent; }
399
+ .a11y-menu-body::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 2px; }
400
+
401
+ .a11y-menu-section { margin-bottom: 16px; }
402
+ .a11y-menu-section-label {
403
+ font-size: 10px; font-weight: 900; text-transform: uppercase;
404
+ letter-spacing: 0.1em; color: #94a3b8;
405
+ margin-left: 4px; margin-bottom: 8px;
406
+ display: flex; align-items: center; gap: 8px;
407
+ }
408
+
409
+ .a11y-menu-btn-group {
410
+ display: flex; gap: 4px; background: #f8fafc;
411
+ padding: 4px; border-radius: 16px;
412
+ border: 1px solid rgba(226, 232, 240, 0.8); overflow-x: auto;
413
+ }
414
+ .a11y-menu-btn-group-item {
415
+ flex: 1; min-width: 32px; padding: 8px 4px; border: none; border-radius: 12px;
416
+ background: transparent; font-size: 10px; font-weight: 700; color: #94a3b8;
417
+ cursor: pointer; transition: all 0.2s ease;
418
+ display: flex; align-items: center; justify-content: center;
419
+ }
420
+ .a11y-menu-btn-group-item[data-active="true"] {
421
+ background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); transform: scale(1.02);
422
+ }
423
+ .a11y-menu-btn-group-item:hover { color: #475569; }
424
+
425
+ .a11y-menu-toggle {
426
+ width: 100%; display: flex; align-items: center; justify-content: space-between;
427
+ padding: 10px; border-radius: 16px; border: 1px solid transparent;
428
+ cursor: pointer; transition: all 0.3s ease; margin-bottom: 8px;
429
+ }
430
+ .a11y-menu-toggle:hover { background: rgba(248, 250, 252, 0.3); }
431
+ .a11y-menu-toggle-left { display: flex; align-items: center; gap: 12px; }
432
+ .a11y-menu-toggle-icon-wrap {
433
+ width: 32px; height: 32px; border-radius: 12px;
434
+ display: flex; align-items: center; justify-content: center;
435
+ background: #f8fafc; color: #94a3b8; transition: all 0.3s ease; flex-shrink: 0;
436
+ }
437
+ .a11y-menu-toggle-icon-wrap svg { width: 16px; height: 16px; }
438
+ .a11y-menu-toggle-icon-wrap[data-active="true"] { color: #fff; }
439
+ .a11y-menu-toggle-label { font-size: 11px; font-weight: 700; letter-spacing: -0.01em; color: #475569; }
440
+ .a11y-menu-toggle-check {
441
+ width: 20px; height: 20px; border-radius: 50%; border: 2px solid #e2e8f0;
442
+ display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; flex-shrink: 0;
443
+ }
444
+ .a11y-menu-toggle-check[data-active="true"] { background: #01a0a0; border-color: #01a0a0; color: #fff; }
445
+ .a11y-menu-check-icon { width: 10px; height: 10px; stroke-width: 5; }
446
+
447
+ .a11y-menu-reset {
448
+ width: 100%; margin-top: 20px; padding: 12px; border-radius: 16px;
449
+ background: #f8fafc; border: 1px solid #f1f5f9;
450
+ font-size: 9px; font-weight: 900; text-transform: uppercase;
451
+ letter-spacing: 0.1em; cursor: pointer; transition: background 0.2s ease;
452
+ }
453
+ .a11y-menu-reset:hover { background: #f1f5f9; }
454
+
455
+ @media (max-width: 767px) {
456
+ .a11y-menu-panel { left: 16px; right: 16px; }
457
+ .a11y-menu-panel[data-right="true"] { left: 16px; right: 16px; }
458
+ }
459
+ `;
460
+ var ALIGNMENT_ICONS = {
461
+ off: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 14, height: 14 }, children: [
462
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
463
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
464
+ ] }),
465
+ left: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 14, height: 14 }, children: [
466
+ /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
467
+ /* @__PURE__ */ jsx("path", { d: "M3 12h12" }),
468
+ /* @__PURE__ */ jsx("path", { d: "M3 18h6" })
469
+ ] }),
470
+ center: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 14, height: 14 }, children: [
471
+ /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
472
+ /* @__PURE__ */ jsx("path", { d: "M6 12h12" }),
473
+ /* @__PURE__ */ jsx("path", { d: "M9 18h6" })
474
+ ] }),
475
+ right: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 14, height: 14 }, children: [
476
+ /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
477
+ /* @__PURE__ */ jsx("path", { d: "M9 12h12" }),
478
+ /* @__PURE__ */ jsx("path", { d: "M15 18h6" })
479
+ ] }),
480
+ justify: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 14, height: 14 }, children: [
481
+ /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
482
+ /* @__PURE__ */ jsx("path", { d: "M3 12h18" }),
483
+ /* @__PURE__ */ jsx("path", { d: "M3 18h18" })
484
+ ] })
485
+ };
486
+ var ALIGNMENT_VALUES = ["off", "left", "center", "right", "justify"];
487
+ function AccessibilityMenu({
488
+ initialSettings,
489
+ storageKey = "ieee-atiig-accessibility-menu-settings",
490
+ position = "bottom-left",
491
+ positionOffset = 0,
492
+ labels: labelsProp,
493
+ className = "",
494
+ buttonClassName = "",
495
+ panelClassName = "",
496
+ zIndex: zIndexProp,
497
+ onSettingsChange,
498
+ onReset,
499
+ showResetButton = true,
500
+ showFontSize = true,
501
+ showLineHeight = true,
502
+ showAlignment = true,
503
+ showReadingAid = true,
504
+ showDesaturate = true,
505
+ showDyslexicFont = true,
506
+ showBigCursor = true,
507
+ showStopAnimations = true,
508
+ theme: themeProp
509
+ }) {
510
+ useInjectStyles(styles);
511
+ const [isOpen, setIsOpen] = useState(false);
512
+ const isMobile = useIsMobile();
513
+ const mousePos = useMousePosition(isMobile);
514
+ const { settings, setVal, resetSettings } = useSettings(
515
+ storageKey,
516
+ initialSettings,
517
+ onSettingsChange
518
+ );
519
+ const labels = { ...DEFAULT_LABELS, ...labelsProp };
520
+ const zIndex = { ...DEFAULT_Z_INDEX, ...zIndexProp };
521
+ const theme = { ...DEFAULT_THEME, ...themeProp };
522
+ const offsetNum = typeof positionOffset === "number" ? positionOffset : positionOffset.y;
523
+ const isRight = position === "bottom-right";
524
+ const handleReset = () => {
525
+ resetSettings();
526
+ onReset?.();
527
+ };
528
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
529
+ settings.readingAid && /* @__PURE__ */ jsx(
530
+ ReadingAid,
531
+ {
532
+ mouseY: mousePos.y,
533
+ size: settings.readingAidSize,
534
+ zIndex: zIndex.readingAid,
535
+ theme
536
+ }
537
+ ),
538
+ /* @__PURE__ */ jsx(
539
+ "button",
540
+ {
541
+ onClick: () => setIsOpen(!isOpen),
542
+ className: `a11y-menu-button ${buttonClassName}`,
543
+ "data-open": isOpen,
544
+ "data-right": isRight,
545
+ style: {
546
+ bottom: `${20 + offsetNum}px`,
547
+ left: isRight ? void 0 : `${20 + offsetNum}px`,
548
+ right: isRight ? `${20 + offsetNum}px` : void 0,
549
+ zIndex: zIndex.button,
550
+ background: isOpen ? theme.primary : `linear-gradient(135deg, ${theme.gradientFrom}, ${theme.gradientTo})`,
551
+ boxShadow: isOpen ? `0 10px 20px rgba(2, 58, 116, 0.3)` : `0 4px 30px rgba(2, 58, 116, 0.28)`
552
+ },
553
+ "aria-label": labels.menuButton,
554
+ type: "button",
555
+ children: /* @__PURE__ */ jsxs(
556
+ "svg",
557
+ {
558
+ className: "a11y-menu-button-icon",
559
+ viewBox: "0 0 24 24",
560
+ fill: "none",
561
+ stroke: "currentColor",
562
+ strokeWidth: 2,
563
+ strokeLinecap: "round",
564
+ strokeLinejoin: "round",
565
+ children: [
566
+ /* @__PURE__ */ jsx("circle", { cx: "16", cy: "4", r: "1" }),
567
+ /* @__PURE__ */ jsx("path", { d: "m18 19 1-7-6 1" }),
568
+ /* @__PURE__ */ jsx("path", { d: "m5 8 3-3 5.5 3-2.36 3.5" }),
569
+ /* @__PURE__ */ jsx("path", { d: "M4.24 14.5a5 5 0 0 0 6.88 6" }),
570
+ /* @__PURE__ */ jsx("path", { d: "M13.76 17.5a5 5 0 0 0-6.88-6" })
571
+ ]
572
+ }
573
+ )
574
+ }
575
+ ),
576
+ isOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
577
+ /* @__PURE__ */ jsx(
578
+ "div",
579
+ {
580
+ className: "a11y-menu-overlay",
581
+ onClick: () => setIsOpen(false),
582
+ style: { zIndex: zIndex.overlay }
583
+ }
584
+ ),
585
+ /* @__PURE__ */ jsxs(
586
+ "div",
587
+ {
588
+ className: `a11y-menu-panel ${panelClassName} ${className}`,
589
+ "data-right": isRight,
590
+ style: {
591
+ bottom: `${80 + offsetNum}px`,
592
+ left: isRight ? void 0 : `${20 + offsetNum}px`,
593
+ right: isRight ? `${20 + offsetNum}px` : void 0,
594
+ zIndex: zIndex.panel,
595
+ backgroundColor: theme.background,
596
+ borderColor: theme.border
597
+ },
598
+ children: [
599
+ /* @__PURE__ */ jsxs("div", { className: "a11y-menu-header", children: [
600
+ /* @__PURE__ */ jsxs("div", { className: "a11y-menu-header-left", children: [
601
+ /* @__PURE__ */ jsx(
602
+ "div",
603
+ {
604
+ className: "a11y-menu-header-icon",
605
+ style: {
606
+ background: `linear-gradient(135deg, ${theme.gradientFrom}, ${theme.gradientTo})`
607
+ },
608
+ children: /* @__PURE__ */ jsxs(
609
+ "svg",
610
+ {
611
+ viewBox: "0 0 24 24",
612
+ fill: "none",
613
+ stroke: "currentColor",
614
+ strokeWidth: 2,
615
+ strokeLinecap: "round",
616
+ strokeLinejoin: "round",
617
+ children: [
618
+ /* @__PURE__ */ jsx("circle", { cx: "16", cy: "4", r: "1" }),
619
+ /* @__PURE__ */ jsx("path", { d: "m18 19 1-7-6 1" }),
620
+ /* @__PURE__ */ jsx("path", { d: "m5 8 3-3 5.5 3-2.36 3.5" }),
621
+ /* @__PURE__ */ jsx("path", { d: "M4.24 14.5a5 5 0 0 0 6.88 6" }),
622
+ /* @__PURE__ */ jsx("path", { d: "M13.76 17.5a5 5 0 0 0-6.88-6" })
623
+ ]
624
+ }
625
+ )
626
+ }
627
+ ),
628
+ /* @__PURE__ */ jsx("h3", { className: "a11y-menu-title", style: { color: theme.text }, children: labels.menuTitle })
629
+ ] }),
630
+ /* @__PURE__ */ jsx(
631
+ "button",
632
+ {
633
+ onClick: () => setIsOpen(false),
634
+ className: "a11y-menu-close",
635
+ type: "button",
636
+ "aria-label": "Close",
637
+ children: /* @__PURE__ */ jsxs(
638
+ "svg",
639
+ {
640
+ viewBox: "0 0 24 24",
641
+ fill: "none",
642
+ stroke: "currentColor",
643
+ strokeWidth: 2,
644
+ strokeLinecap: "round",
645
+ strokeLinejoin: "round",
646
+ children: [
647
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
648
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
649
+ ]
650
+ }
651
+ )
652
+ }
653
+ )
654
+ ] }),
655
+ /* @__PURE__ */ jsxs("div", { className: "a11y-menu-body", children: [
656
+ showFontSize && /* @__PURE__ */ jsx(Section, { label: labels.fontSize, children: /* @__PURE__ */ jsx(
657
+ ButtonGroup,
658
+ {
659
+ value: settings.fontSize,
660
+ options: [0, 10, 20, 30],
661
+ renderLabel: (v) => v === 0 ? labels.off : `+${v}%`,
662
+ onChange: (v) => setVal("fontSize", v),
663
+ activeColor: theme.primary
664
+ }
665
+ ) }),
666
+ showLineHeight && /* @__PURE__ */ jsx(Section, { label: labels.lineHeight, children: /* @__PURE__ */ jsx(
667
+ ButtonGroup,
668
+ {
669
+ value: settings.lineHeight,
670
+ options: [0, 15, 20, 25],
671
+ renderLabel: (v) => v === 0 ? labels.off : `${1 + v / 100}x`,
672
+ onChange: (v) => setVal("lineHeight", v),
673
+ activeColor: theme.primary
674
+ }
675
+ ) }),
676
+ showAlignment && /* @__PURE__ */ jsx(Section, { label: labels.alignment, children: /* @__PURE__ */ jsx(
677
+ ButtonGroup,
678
+ {
679
+ value: settings.textAlign,
680
+ options: ALIGNMENT_VALUES,
681
+ renderLabel: (v) => ALIGNMENT_ICONS[v],
682
+ onChange: (v) => setVal("textAlign", v),
683
+ activeColor: theme.primary
684
+ }
685
+ ) }),
686
+ showReadingAid && /* @__PURE__ */ jsx(Section, { label: labels.readingAid, children: /* @__PURE__ */ jsx(
687
+ ButtonGroup,
688
+ {
689
+ value: settings.readingAid ? settings.readingAidSize : 0,
690
+ options: [0, 0.9, 1, 1.2],
691
+ renderLabel: (v) => v === 0 ? labels.off : `${v}x`,
692
+ onChange: (v) => {
693
+ if (v === 0) {
694
+ setVal("readingAid", false);
695
+ } else {
696
+ setVal("readingAid", true);
697
+ setVal("readingAidSize", v);
698
+ }
699
+ },
700
+ activeColor: theme.accent
701
+ }
702
+ ) }),
703
+ showDesaturate && /* @__PURE__ */ jsx(
704
+ AccessibilityToggle,
705
+ {
706
+ icon: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 16, height: 16 }, children: [
707
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "4" }),
708
+ /* @__PURE__ */ jsx("path", { d: "M12 2v2" }),
709
+ /* @__PURE__ */ jsx("path", { d: "M12 20v2" }),
710
+ /* @__PURE__ */ jsx("path", { d: "m4.93 4.93 1.41 1.41" }),
711
+ /* @__PURE__ */ jsx("path", { d: "m17.66 17.66 1.41 1.41" }),
712
+ /* @__PURE__ */ jsx("path", { d: "M2 12h2" }),
713
+ /* @__PURE__ */ jsx("path", { d: "M20 12h2" }),
714
+ /* @__PURE__ */ jsx("path", { d: "m6.34 17.66-1.41 1.41" }),
715
+ /* @__PURE__ */ jsx("path", { d: "m19.07 4.93-1.41 1.41" })
716
+ ] }),
717
+ label: labels.desaturate,
718
+ isActive: settings.grayscale,
719
+ onToggle: () => setVal("grayscale", !settings.grayscale),
720
+ theme
721
+ }
722
+ ),
723
+ showDyslexicFont && /* @__PURE__ */ jsx(
724
+ AccessibilityToggle,
725
+ {
726
+ icon: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 16, height: 16 }, children: [
727
+ /* @__PURE__ */ jsx("circle", { cx: "16", cy: "4", r: "1" }),
728
+ /* @__PURE__ */ jsx("path", { d: "m18 19 1-7-6 1" }),
729
+ /* @__PURE__ */ jsx("path", { d: "m5 8 3-3 5.5 3-2.36 3.5" }),
730
+ /* @__PURE__ */ jsx("path", { d: "M4.24 14.5a5 5 0 0 0 6.88 6" }),
731
+ /* @__PURE__ */ jsx("path", { d: "M13.76 17.5a5 5 0 0 0-6.88-6" })
732
+ ] }),
733
+ label: labels.dyslexicFont,
734
+ isActive: settings.dyslexicFont,
735
+ onToggle: () => setVal("dyslexicFont", !settings.dyslexicFont),
736
+ theme
737
+ }
738
+ ),
739
+ showBigCursor && /* @__PURE__ */ jsx(
740
+ AccessibilityToggle,
741
+ {
742
+ icon: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 16, height: 16 }, children: /* @__PURE__ */ jsx("path", { d: "M3 3 9.77 19.47a.75.75 0 0 0 1.45.05L13 14.5l3 4.5.77.77a.75.75 0 0 0 1.06 0l3.94-3.94a.75.75 0 0 0 0-1.06L21 14.5l-4.5-3 5.47-1.78a.75.75 0 0 0-.05-1.45L3 3Z" }) }),
743
+ label: labels.bigCursor,
744
+ isActive: settings.bigCursor,
745
+ onToggle: () => setVal("bigCursor", !settings.bigCursor),
746
+ theme
747
+ }
748
+ ),
749
+ showStopAnimations && /* @__PURE__ */ jsx(
750
+ AccessibilityToggle,
751
+ {
752
+ icon: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { width: 16, height: 16 }, children: [
753
+ /* @__PURE__ */ jsx("path", { d: "M12 2a10 10 0 0 1 7.38 16.75" }),
754
+ /* @__PURE__ */ jsx("path", { d: "M12 22a10 10 0 0 1-7.38-16.75" }),
755
+ /* @__PURE__ */ jsx("path", { d: "M12 22V2" }),
756
+ /* @__PURE__ */ jsx("path", { d: "M2 12h20" })
757
+ ] }),
758
+ label: labels.stopAnimations,
759
+ isActive: settings.stopAnimations,
760
+ onToggle: () => setVal("stopAnimations", !settings.stopAnimations),
761
+ theme
762
+ }
763
+ )
764
+ ] }),
765
+ showResetButton && /* @__PURE__ */ jsx("button", { onClick: handleReset, className: "a11y-menu-reset", type: "button", style: { color: theme.textMuted }, children: labels.reset })
766
+ ]
767
+ }
768
+ )
769
+ ] })
770
+ ] });
771
+ }
772
+ function Section({ label, children }) {
773
+ return /* @__PURE__ */ jsxs("div", { className: "a11y-menu-section", children: [
774
+ /* @__PURE__ */ jsx("div", { className: "a11y-menu-section-label", children: label }),
775
+ children
776
+ ] });
777
+ }
778
+ function ButtonGroup({
779
+ value,
780
+ options,
781
+ renderLabel,
782
+ onChange,
783
+ activeColor
784
+ }) {
785
+ return /* @__PURE__ */ jsx("div", { className: "a11y-menu-btn-group", children: options.map((val) => /* @__PURE__ */ jsx(
786
+ "button",
787
+ {
788
+ onClick: () => onChange(val),
789
+ className: "a11y-menu-btn-group-item",
790
+ "data-active": value === val,
791
+ type: "button",
792
+ style: { color: value === val ? activeColor : void 0 },
793
+ children: renderLabel(val)
794
+ },
795
+ String(val)
796
+ )) });
797
+ }
798
+
799
+ export { ALL_ROOT_CLASSES, AccessibilityMenu, AccessibilityToggle, DEFAULT_LABELS, DEFAULT_SETTINGS, DEFAULT_THEME, DEFAULT_Z_INDEX, ROOT_CLASSES, ReadingAid, styles, useInjectStyles, useIsMobile, useSettings };
800
+ //# sourceMappingURL=index.js.map
801
+ //# sourceMappingURL=index.js.map