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