@swalha1999/a11y-react 1.0.2

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,1144 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AccessibilityIcon: () => AccessibilityIcon,
24
+ AccessibilityWidget: () => AccessibilityWidget,
25
+ CloseIcon: () => CloseIcon,
26
+ CursorIcon: () => CursorIcon,
27
+ GrayscaleIcon: () => GrayscaleIcon,
28
+ ImageIcon: () => ImageIcon,
29
+ InvertIcon: () => InvertIcon,
30
+ LetterSpacingIcon: () => LetterSpacingIcon,
31
+ LineHeightIcon: () => LineHeightIcon,
32
+ LinkIcon: () => LinkIcon,
33
+ ReadingGuideIcon: () => ReadingGuideIcon,
34
+ ResetIcon: () => ResetIcon,
35
+ TextSizeIcon: () => TextSizeIcon,
36
+ accessibilityStylesCSS: () => accessibilityStylesCSS,
37
+ ar: () => ar,
38
+ en: () => en,
39
+ injectAccessibilityStyles: () => injectAccessibilityStyles,
40
+ removeAccessibilityStyles: () => removeAccessibilityStyles,
41
+ useAccessibilitySettings: () => useAccessibilitySettings,
42
+ useBackgroundContrast: () => useBackgroundContrast,
43
+ useReadingGuide: () => useReadingGuide
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/AccessibilityWidget.tsx
48
+ var import_react4 = require("react");
49
+ var import_react_dom = require("react-dom");
50
+
51
+ // src/hooks/useAccessibilitySettings.ts
52
+ var import_react = require("react");
53
+ var DEFAULT_SETTINGS = {
54
+ textSize: 0,
55
+ lineHeight: 0,
56
+ letterSpacing: 0,
57
+ invertColors: false,
58
+ grayscale: false,
59
+ underlineLinks: false,
60
+ bigCursor: false,
61
+ readingGuide: false,
62
+ hideImages: false
63
+ };
64
+ function useAccessibilitySettings({
65
+ storageKey = "accessibility-settings",
66
+ defaultSettings,
67
+ onSettingsChange,
68
+ disablePersistence = false
69
+ } = {}) {
70
+ const [settings, setSettings] = (0, import_react.useState)(() => {
71
+ const initial = { ...DEFAULT_SETTINGS, ...defaultSettings };
72
+ if (!disablePersistence && typeof window !== "undefined") {
73
+ try {
74
+ const saved = localStorage.getItem(storageKey);
75
+ if (saved) {
76
+ return { ...initial, ...JSON.parse(saved) };
77
+ }
78
+ } catch {
79
+ }
80
+ }
81
+ return initial;
82
+ });
83
+ (0, import_react.useEffect)(() => {
84
+ if (!disablePersistence && typeof window !== "undefined") {
85
+ try {
86
+ localStorage.setItem(storageKey, JSON.stringify(settings));
87
+ } catch {
88
+ }
89
+ }
90
+ onSettingsChange?.(settings);
91
+ }, [settings, storageKey, onSettingsChange, disablePersistence]);
92
+ (0, import_react.useEffect)(() => {
93
+ const root = document.documentElement;
94
+ const body = document.body;
95
+ const WRAPPER_ID = "a11y-content-wrapper";
96
+ const PORTAL_ID = "a11y-widget-portal";
97
+ let wrapper = document.getElementById(WRAPPER_ID);
98
+ if (!wrapper) {
99
+ wrapper = document.createElement("div");
100
+ wrapper.id = WRAPPER_ID;
101
+ wrapper.style.minHeight = "100vh";
102
+ wrapper.style.background = "inherit";
103
+ const children = Array.from(body.children);
104
+ children.forEach((child) => {
105
+ if (child.id !== PORTAL_ID && child.id !== WRAPPER_ID) {
106
+ wrapper.appendChild(child);
107
+ }
108
+ });
109
+ body.insertBefore(wrapper, body.firstChild);
110
+ }
111
+ const textScale = 1 + settings.textSize * 0.05;
112
+ root.style.setProperty("--a11y-text-scale", String(textScale));
113
+ body.classList.toggle("a11y-text-scaled", settings.textSize !== 0);
114
+ const lineHeight = 1.5 + settings.lineHeight * 0.2;
115
+ root.style.setProperty("--a11y-line-height", String(lineHeight));
116
+ body.classList.toggle("a11y-line-height-active", settings.lineHeight !== 0);
117
+ const letterSpacing = settings.letterSpacing * 0.05;
118
+ root.style.setProperty("--a11y-letter-spacing", `${letterSpacing}em`);
119
+ body.classList.toggle("a11y-letter-spacing-active", settings.letterSpacing !== 0);
120
+ wrapper.classList.toggle("a11y-invert", settings.invertColors);
121
+ wrapper.classList.toggle("a11y-grayscale", settings.grayscale);
122
+ body.classList.toggle("a11y-underline-links", settings.underlineLinks);
123
+ body.classList.toggle("a11y-big-cursor", settings.bigCursor);
124
+ body.classList.toggle("a11y-reading-guide", settings.readingGuide);
125
+ body.classList.toggle("a11y-hide-images", settings.hideImages);
126
+ return () => {
127
+ root.style.removeProperty("--a11y-text-scale");
128
+ root.style.removeProperty("--a11y-line-height");
129
+ root.style.removeProperty("--a11y-letter-spacing");
130
+ body.classList.remove(
131
+ "a11y-text-scaled",
132
+ "a11y-line-height-active",
133
+ "a11y-letter-spacing-active",
134
+ "a11y-underline-links",
135
+ "a11y-big-cursor",
136
+ "a11y-reading-guide",
137
+ "a11y-hide-images"
138
+ );
139
+ if (wrapper) {
140
+ wrapper.classList.remove("a11y-invert", "a11y-grayscale");
141
+ }
142
+ };
143
+ }, [settings]);
144
+ const updateSetting = (0, import_react.useCallback)((key, value) => {
145
+ setSettings((prev) => ({ ...prev, [key]: value }));
146
+ }, []);
147
+ const toggleSetting = (0, import_react.useCallback)((key) => {
148
+ setSettings((prev) => {
149
+ const current = prev[key];
150
+ if (typeof current === "boolean") {
151
+ return { ...prev, [key]: !current };
152
+ }
153
+ return prev;
154
+ });
155
+ }, []);
156
+ const resetSettings = (0, import_react.useCallback)(() => {
157
+ setSettings({ ...DEFAULT_SETTINGS, ...defaultSettings });
158
+ }, [defaultSettings]);
159
+ const incrementSetting = (0, import_react.useCallback)((key, min = -2, max = 2) => {
160
+ setSettings((prev) => ({
161
+ ...prev,
162
+ [key]: Math.min(max, prev[key] + 1)
163
+ }));
164
+ }, []);
165
+ const decrementSetting = (0, import_react.useCallback)((key, min = -2, max = 2) => {
166
+ setSettings((prev) => ({
167
+ ...prev,
168
+ [key]: Math.max(min, prev[key] - 1)
169
+ }));
170
+ }, []);
171
+ return {
172
+ settings,
173
+ updateSetting,
174
+ toggleSetting,
175
+ resetSettings,
176
+ incrementSetting,
177
+ decrementSetting
178
+ };
179
+ }
180
+
181
+ // src/hooks/useReadingGuide.ts
182
+ var import_react2 = require("react");
183
+ function useReadingGuide(enabled, primaryColor = "#2d2d2d") {
184
+ const lineRef = (0, import_react2.useRef)(null);
185
+ (0, import_react2.useEffect)(() => {
186
+ if (!enabled) {
187
+ if (lineRef.current) {
188
+ lineRef.current.remove();
189
+ lineRef.current = null;
190
+ }
191
+ return;
192
+ }
193
+ const line = document.createElement("div");
194
+ line.className = "a11y-reading-guide-line";
195
+ line.setAttribute("aria-hidden", "true");
196
+ line.style.cssText = `
197
+ position: fixed;
198
+ left: 0;
199
+ right: 0;
200
+ height: 2px;
201
+ background: ${primaryColor};
202
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
203
+ pointer-events: none;
204
+ z-index: 9997;
205
+ transition: top 0.1s ease-out;
206
+ `;
207
+ document.body.appendChild(line);
208
+ lineRef.current = line;
209
+ const handleMouseMove = (e) => {
210
+ if (lineRef.current) {
211
+ lineRef.current.style.top = `${e.clientY}px`;
212
+ }
213
+ };
214
+ document.addEventListener("mousemove", handleMouseMove);
215
+ return () => {
216
+ document.removeEventListener("mousemove", handleMouseMove);
217
+ if (lineRef.current) {
218
+ lineRef.current.remove();
219
+ lineRef.current = null;
220
+ }
221
+ };
222
+ }, [enabled, primaryColor]);
223
+ }
224
+
225
+ // src/hooks/useBackgroundContrast.ts
226
+ var import_react3 = require("react");
227
+ function useBackgroundContrast(buttonRef) {
228
+ const [isDarkBackground, setIsDarkBackground] = (0, import_react3.useState)(false);
229
+ const detectBackground = (0, import_react3.useCallback)(() => {
230
+ const button = buttonRef.current;
231
+ if (!button) return;
232
+ const rect = button.getBoundingClientRect();
233
+ const x = rect.left + rect.width / 2;
234
+ const y = rect.top + rect.height / 2;
235
+ const originalPointerEvents = button.style.pointerEvents;
236
+ button.style.pointerEvents = "none";
237
+ const elementBehind = document.elementFromPoint(x, y);
238
+ button.style.pointerEvents = originalPointerEvents;
239
+ if (elementBehind) {
240
+ const bgColor = window.getComputedStyle(elementBehind).backgroundColor;
241
+ const rgb = bgColor.match(/\d+/g);
242
+ if (rgb && rgb.length >= 3) {
243
+ const luminance = (0.299 * parseInt(rgb[0], 10) + 0.587 * parseInt(rgb[1], 10) + 0.114 * parseInt(rgb[2], 10)) / 255;
244
+ setIsDarkBackground(luminance < 0.5);
245
+ }
246
+ }
247
+ }, [buttonRef]);
248
+ (0, import_react3.useEffect)(() => {
249
+ detectBackground();
250
+ window.addEventListener("scroll", detectBackground);
251
+ window.addEventListener("resize", detectBackground);
252
+ return () => {
253
+ window.removeEventListener("scroll", detectBackground);
254
+ window.removeEventListener("resize", detectBackground);
255
+ };
256
+ }, [detectBackground]);
257
+ return isDarkBackground;
258
+ }
259
+
260
+ // src/icons.tsx
261
+ var import_jsx_runtime = require("react/jsx-runtime");
262
+ var AccessibilityIcon = ({
263
+ size = 24,
264
+ className,
265
+ "aria-hidden": ariaHidden = true
266
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
267
+ "svg",
268
+ {
269
+ viewBox: "0 0 24 24",
270
+ fill: "currentColor",
271
+ width: size,
272
+ height: size,
273
+ className: `a11y-widget-icon ${className || ""}`,
274
+ "aria-hidden": ariaHidden,
275
+ role: "img",
276
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2C13.1 2 14 2.9 14 4S13.1 6 12 6 10 5.1 10 4 10.9 2 12 2M21 9H15V22H13V16H11V22H9V9H3V7H21V9Z" })
277
+ }
278
+ );
279
+ var TextSizeIcon = ({
280
+ size = 24,
281
+ className,
282
+ "aria-hidden": ariaHidden = true
283
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
284
+ "svg",
285
+ {
286
+ viewBox: "0 0 24 24",
287
+ fill: "currentColor",
288
+ width: size,
289
+ height: size,
290
+ className: `a11y-widget-icon ${className || ""}`,
291
+ "aria-hidden": ariaHidden,
292
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 7V5H21V7H3M10 17V9H14V17H10M8 19H16V21H8V19Z" })
293
+ }
294
+ );
295
+ var LineHeightIcon = ({
296
+ size = 24,
297
+ className,
298
+ "aria-hidden": ariaHidden = true
299
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
300
+ "svg",
301
+ {
302
+ viewBox: "0 0 24 24",
303
+ fill: "currentColor",
304
+ width: size,
305
+ height: size,
306
+ className: `a11y-widget-icon ${className || ""}`,
307
+ "aria-hidden": ariaHidden,
308
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 13H22V11H10M10 19H22V17H10M10 7H22V5H10M6 7H8.5L5 3.5L1.5 7H4V17H1.5L5 20.5L8.5 17H6V7Z" })
309
+ }
310
+ );
311
+ var LetterSpacingIcon = ({
312
+ size = 24,
313
+ className,
314
+ "aria-hidden": ariaHidden = true
315
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
316
+ "svg",
317
+ {
318
+ viewBox: "0 0 24 24",
319
+ fill: "currentColor",
320
+ width: size,
321
+ height: size,
322
+ className: `a11y-widget-icon ${className || ""}`,
323
+ "aria-hidden": ariaHidden,
324
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M11 3L5.5 17H7.75L8.85 14H15.15L16.25 17H18.5L13 3H11M9.55 12L12 5.67L14.45 12H9.55M2 20H22V22H2V20Z" })
325
+ }
326
+ );
327
+ var InvertIcon = ({
328
+ size = 24,
329
+ className,
330
+ "aria-hidden": ariaHidden = true
331
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
332
+ "svg",
333
+ {
334
+ viewBox: "0 0 24 24",
335
+ fill: "currentColor",
336
+ width: size,
337
+ height: size,
338
+ className: `a11y-widget-icon ${className || ""}`,
339
+ "aria-hidden": ariaHidden,
340
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12,18C11.11,18 10.26,17.8 9.5,17.45C11.56,16.5 13,14.42 13,12C13,9.58 11.56,7.5 9.5,6.55C10.26,6.2 11.11,6 12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18M20,8.69V4H15.31L12,0.69L8.69,4H4V8.69L0.69,12L4,15.31V20H8.69L12,23.31L15.31,20H20V15.31L23.31,12L20,8.69Z" })
341
+ }
342
+ );
343
+ var GrayscaleIcon = ({
344
+ size = 24,
345
+ className,
346
+ "aria-hidden": ariaHidden = true
347
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
348
+ "svg",
349
+ {
350
+ viewBox: "0 0 24 24",
351
+ fill: "currentColor",
352
+ width: size,
353
+ height: size,
354
+ className: `a11y-widget-icon ${className || ""}`,
355
+ "aria-hidden": ariaHidden,
356
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12,18.54L19.37,12.8L21,14.07L12,21.07L3,14.07L4.62,12.81L12,18.54M12,16L3,9L12,2L21,9L12,16M12,4.53L6.26,9L12,13.47L17.74,9L12,4.53Z" })
357
+ }
358
+ );
359
+ var LinkIcon = ({
360
+ size = 24,
361
+ className,
362
+ "aria-hidden": ariaHidden = true
363
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
364
+ "svg",
365
+ {
366
+ viewBox: "0 0 24 24",
367
+ fill: "currentColor",
368
+ width: size,
369
+ height: size,
370
+ className: `a11y-widget-icon ${className || ""}`,
371
+ "aria-hidden": ariaHidden,
372
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z" })
373
+ }
374
+ );
375
+ var CursorIcon = ({
376
+ size = 24,
377
+ className,
378
+ "aria-hidden": ariaHidden = true
379
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
380
+ "svg",
381
+ {
382
+ viewBox: "0 0 24 24",
383
+ fill: "currentColor",
384
+ width: size,
385
+ height: size,
386
+ className: `a11y-widget-icon ${className || ""}`,
387
+ "aria-hidden": ariaHidden,
388
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13.64,21.97C13.14,22.21 12.54,22 12.31,21.5L10.13,16.76L7.62,18.78C7.45,18.92 7.24,19 7,19A1,1 0 0,1 6,18V3A1,1 0 0,1 7,2C7.24,2 7.47,2.09 7.64,2.23L7.65,2.22L19.14,11.86C19.57,12.22 19.62,12.85 19.27,13.27C19.12,13.45 18.91,13.57 18.7,13.61L15.54,14.23L17.74,18.96C17.97,19.46 17.76,20.06 17.26,20.28L13.64,21.97Z" })
389
+ }
390
+ );
391
+ var ReadingGuideIcon = ({
392
+ size = 24,
393
+ className,
394
+ "aria-hidden": ariaHidden = true
395
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
396
+ "svg",
397
+ {
398
+ viewBox: "0 0 24 24",
399
+ fill: "currentColor",
400
+ width: size,
401
+ height: size,
402
+ className: `a11y-widget-icon ${className || ""}`,
403
+ "aria-hidden": ariaHidden,
404
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21,5C19.89,4.65 18.67,4.5 17.5,4.5C15.55,4.5 13.45,4.9 12,6C10.55,4.9 8.45,4.5 6.5,4.5C4.55,4.5 2.45,4.9 1,6V20.65C1,20.9 1.25,21.15 1.5,21.15C1.6,21.15 1.65,21.1 1.75,21.1C3.1,20.45 5.05,20 6.5,20C8.45,20 10.55,20.4 12,21.5C13.35,20.65 15.8,20 17.5,20C19.15,20 20.85,20.3 22.25,21.05C22.35,21.1 22.4,21.1 22.5,21.1C22.75,21.1 23,20.85 23,20.6V6C22.4,5.55 21.75,5.25 21,5M21,18.5C19.9,18.15 18.7,18 17.5,18C15.8,18 13.35,18.65 12,19.5V8C13.35,7.15 15.8,6.5 17.5,6.5C18.7,6.5 19.9,6.65 21,7V18.5Z" })
405
+ }
406
+ );
407
+ var ImageIcon = ({
408
+ size = 24,
409
+ className,
410
+ "aria-hidden": ariaHidden = true
411
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
412
+ "svg",
413
+ {
414
+ viewBox: "0 0 24 24",
415
+ fill: "currentColor",
416
+ width: size,
417
+ height: size,
418
+ className: `a11y-widget-icon ${className || ""}`,
419
+ "aria-hidden": ariaHidden,
420
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z" })
421
+ }
422
+ );
423
+ var ResetIcon = ({
424
+ size = 24,
425
+ className,
426
+ "aria-hidden": ariaHidden = true
427
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
428
+ "svg",
429
+ {
430
+ viewBox: "0 0 24 24",
431
+ fill: "currentColor",
432
+ width: size,
433
+ height: size,
434
+ className: `a11y-widget-icon ${className || ""}`,
435
+ "aria-hidden": ariaHidden,
436
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12.5,8C9.85,8 7.45,9 5.6,10.6L2,7V16H11L7.38,12.38C8.77,11.22 10.54,10.5 12.5,10.5C16.04,10.5 19.05,12.81 20.1,16L22.47,15.22C21.08,11.03 17.15,8 12.5,8Z" })
437
+ }
438
+ );
439
+ var CloseIcon = ({
440
+ size = 24,
441
+ className,
442
+ "aria-hidden": ariaHidden = true
443
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
444
+ "svg",
445
+ {
446
+ viewBox: "0 0 24 24",
447
+ fill: "currentColor",
448
+ width: size,
449
+ height: size,
450
+ className: `a11y-widget-icon ${className || ""}`,
451
+ "aria-hidden": ariaHidden,
452
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" })
453
+ }
454
+ );
455
+
456
+ // src/AccessibilityWidget.tsx
457
+ var import_jsx_runtime2 = require("react/jsx-runtime");
458
+ var getPortalContainer = () => {
459
+ const PORTAL_ID = "a11y-widget-portal";
460
+ let container = document.getElementById(PORTAL_ID);
461
+ if (!container) {
462
+ container = document.createElement("div");
463
+ container.id = PORTAL_ID;
464
+ document.body.appendChild(container);
465
+ }
466
+ return container;
467
+ };
468
+ var AccessibilityWidget = ({
469
+ translations,
470
+ dir = "ltr",
471
+ styles = {},
472
+ classNames = {},
473
+ position = "bottom-right",
474
+ storageKey = "accessibility-settings",
475
+ onSettingsChange,
476
+ defaultSettings,
477
+ zIndex = 9999,
478
+ disablePersistence = false,
479
+ buttonIcon,
480
+ primaryColor = "#6366f1",
481
+ buttonAriaLabel
482
+ }) => {
483
+ const [isOpen, setIsOpen] = (0, import_react4.useState)(false);
484
+ const [portalContainer, setPortalContainer] = (0, import_react4.useState)(null);
485
+ const buttonRef = (0, import_react4.useRef)(null);
486
+ const panelRef = (0, import_react4.useRef)(null);
487
+ const uniqueId = (0, import_react4.useId)();
488
+ (0, import_react4.useEffect)(() => {
489
+ setPortalContainer(getPortalContainer());
490
+ }, []);
491
+ const isDarkBackground = useBackgroundContrast(buttonRef);
492
+ const {
493
+ settings,
494
+ toggleSetting,
495
+ resetSettings,
496
+ incrementSetting,
497
+ decrementSetting
498
+ } = useAccessibilitySettings({
499
+ storageKey,
500
+ defaultSettings,
501
+ onSettingsChange,
502
+ disablePersistence
503
+ });
504
+ useReadingGuide(settings.readingGuide, primaryColor);
505
+ const handleOpen = () => {
506
+ setIsOpen(true);
507
+ };
508
+ const handleClose = () => {
509
+ setIsOpen(false);
510
+ };
511
+ (0, import_react4.useEffect)(() => {
512
+ const handleKeyDown = (e) => {
513
+ if (e.key === "Escape" && isOpen) {
514
+ handleClose();
515
+ buttonRef.current?.focus();
516
+ }
517
+ };
518
+ document.addEventListener("keydown", handleKeyDown);
519
+ return () => document.removeEventListener("keydown", handleKeyDown);
520
+ }, [isOpen]);
521
+ (0, import_react4.useEffect)(() => {
522
+ if (!isOpen || !panelRef.current) return;
523
+ const panel = panelRef.current;
524
+ const focusableElements = panel.querySelectorAll(
525
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
526
+ );
527
+ const firstElement = focusableElements[0];
528
+ const lastElement = focusableElements[focusableElements.length - 1];
529
+ const handleTabKey = (e) => {
530
+ if (e.key !== "Tab") return;
531
+ if (e.shiftKey && document.activeElement === firstElement) {
532
+ e.preventDefault();
533
+ lastElement?.focus();
534
+ } else if (!e.shiftKey && document.activeElement === lastElement) {
535
+ e.preventDefault();
536
+ firstElement?.focus();
537
+ }
538
+ };
539
+ panel.addEventListener("keydown", handleTabKey);
540
+ firstElement?.focus();
541
+ return () => panel.removeEventListener("keydown", handleTabKey);
542
+ }, [isOpen]);
543
+ const getPositionStyles = () => {
544
+ const base = { position: "fixed" };
545
+ const offset = 24;
546
+ switch (position) {
547
+ case "bottom-left":
548
+ return { ...base, bottom: offset, left: offset };
549
+ case "bottom-right":
550
+ return { ...base, bottom: offset, right: offset };
551
+ case "top-left":
552
+ return { ...base, top: offset, left: offset };
553
+ case "top-right":
554
+ return { ...base, top: offset, right: offset };
555
+ default:
556
+ return { ...base, bottom: offset, right: offset };
557
+ }
558
+ };
559
+ const getPanelPositionStyles = () => {
560
+ const base = { position: "fixed" };
561
+ if (position.includes("bottom")) {
562
+ base.bottom = 100;
563
+ } else {
564
+ base.top = 100;
565
+ }
566
+ if (position.includes("left")) {
567
+ base.left = 24;
568
+ } else {
569
+ base.right = 24;
570
+ }
571
+ return base;
572
+ };
573
+ const buttonStyle = {
574
+ ...getPositionStyles(),
575
+ width: 64,
576
+ height: 64,
577
+ border: "none",
578
+ borderRadius: "50%",
579
+ cursor: "pointer",
580
+ zIndex,
581
+ display: "flex",
582
+ alignItems: "center",
583
+ justifyContent: "center",
584
+ background: isDarkBackground ? "#ffffff" : primaryColor,
585
+ color: isDarkBackground ? primaryColor : "white",
586
+ boxShadow: isDarkBackground ? "0 4px 20px rgba(0, 0, 0, 0.1), 0 2px 8px rgba(0, 0, 0, 0.05)" : `0 4px 20px ${primaryColor}40, 0 2px 8px ${primaryColor}20`,
587
+ ...styles.button,
588
+ ...isDarkBackground ? styles.buttonLight : styles.buttonDark
589
+ };
590
+ const overlayStyle = {
591
+ position: "fixed",
592
+ top: 0,
593
+ left: 0,
594
+ right: 0,
595
+ bottom: 0,
596
+ background: "rgba(0, 0, 0, 0.4)",
597
+ zIndex: zIndex - 1,
598
+ ...styles.overlay
599
+ };
600
+ const panelStyle = {
601
+ ...getPanelPositionStyles(),
602
+ width: 400,
603
+ maxWidth: "calc(100vw - 48px)",
604
+ maxHeight: "85vh",
605
+ background: "#ffffff",
606
+ borderRadius: 24,
607
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
608
+ zIndex,
609
+ overflow: "hidden",
610
+ direction: dir,
611
+ border: "1px solid #e2e8f0",
612
+ ...styles.panel
613
+ };
614
+ const headerStyle = {
615
+ display: "flex",
616
+ justifyContent: "space-between",
617
+ alignItems: "center",
618
+ padding: "24px 28px",
619
+ background: primaryColor,
620
+ color: "white",
621
+ ...styles.panelHeader
622
+ };
623
+ const headerTitleStyle = {
624
+ margin: 0,
625
+ fontSize: 22,
626
+ fontWeight: 700,
627
+ lineHeight: 1.2,
628
+ letterSpacing: "-0.02em"
629
+ };
630
+ const closeButtonStyle = {
631
+ background: "rgba(255, 255, 255, 0.15)",
632
+ border: "none",
633
+ width: 36,
634
+ height: 36,
635
+ borderRadius: 12,
636
+ color: "white",
637
+ cursor: "pointer",
638
+ display: "flex",
639
+ alignItems: "center",
640
+ justifyContent: "center"
641
+ };
642
+ const contentStyle = {
643
+ padding: "20px 24px",
644
+ maxHeight: "calc(85vh - 160px)",
645
+ overflowY: "auto",
646
+ overflowX: "hidden",
647
+ ...styles.panelContent
648
+ };
649
+ const getSettingItemStyle = (isToggle) => ({
650
+ background: "#f8fafc",
651
+ borderRadius: 16,
652
+ padding: "18px 20px",
653
+ marginBottom: 12,
654
+ border: "1px solid #e2e8f0",
655
+ cursor: "default",
656
+ ...isToggle && {
657
+ display: "flex",
658
+ justifyContent: "space-between",
659
+ alignItems: "center"
660
+ },
661
+ ...styles.settingItem
662
+ });
663
+ const itemHeaderStyle = (isToggle) => ({
664
+ display: "flex",
665
+ alignItems: "center",
666
+ gap: 14,
667
+ ...isToggle ? { flex: 1 } : { marginBottom: 14 }
668
+ });
669
+ const iconContainerStyle = {
670
+ width: 40,
671
+ height: 40,
672
+ borderRadius: 12,
673
+ background: `${primaryColor}15`,
674
+ display: "flex",
675
+ alignItems: "center",
676
+ justifyContent: "center",
677
+ flexShrink: 0
678
+ };
679
+ const iconStyle = {
680
+ width: 22,
681
+ height: 22,
682
+ color: primaryColor
683
+ };
684
+ const labelStyle = {
685
+ fontWeight: 600,
686
+ color: "#1e293b",
687
+ fontSize: 15,
688
+ lineHeight: 1.4,
689
+ letterSpacing: "-0.01em"
690
+ };
691
+ const controlContainerStyle = {
692
+ display: "flex",
693
+ gap: 10,
694
+ alignItems: "center",
695
+ justifyContent: "center",
696
+ background: "#ffffff",
697
+ padding: "8px 12px",
698
+ borderRadius: 14
699
+ };
700
+ const controlButtonStyle = (disabled) => ({
701
+ background: disabled ? "#f1f5f9" : primaryColor,
702
+ border: "none",
703
+ borderRadius: 10,
704
+ width: 42,
705
+ height: 42,
706
+ fontSize: 16,
707
+ fontWeight: 700,
708
+ color: disabled ? "#94a3b8" : "white",
709
+ cursor: disabled ? "not-allowed" : "pointer",
710
+ display: "flex",
711
+ alignItems: "center",
712
+ justifyContent: "center",
713
+ opacity: disabled ? 0.5 : 1,
714
+ ...styles.controlButton
715
+ });
716
+ const valueDisplayStyle = {
717
+ minWidth: 70,
718
+ textAlign: "center",
719
+ fontWeight: 700,
720
+ color: "#334155",
721
+ fontSize: 14,
722
+ fontFamily: "ui-monospace, monospace",
723
+ background: "#f8fafc",
724
+ padding: "8px 12px",
725
+ borderRadius: 8
726
+ };
727
+ const toggleTrackStyle = (checked) => ({
728
+ position: "relative",
729
+ width: 56,
730
+ height: 30,
731
+ flexShrink: 0,
732
+ display: "inline-block",
733
+ cursor: "pointer"
734
+ });
735
+ const toggleSliderStyle = (checked) => ({
736
+ position: "absolute",
737
+ cursor: "pointer",
738
+ top: 0,
739
+ left: 0,
740
+ right: 0,
741
+ bottom: 0,
742
+ backgroundColor: checked ? primaryColor : "#e2e8f0",
743
+ borderRadius: 30,
744
+ ...styles.toggleTrack
745
+ });
746
+ const toggleKnobStyle = (checked) => ({
747
+ position: "absolute",
748
+ height: 24,
749
+ width: 24,
750
+ left: checked ? 28 : 3,
751
+ bottom: 3,
752
+ backgroundColor: "white",
753
+ borderRadius: "50%",
754
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.1)",
755
+ ...styles.toggleThumb
756
+ });
757
+ const dividerStyle = {
758
+ height: 1,
759
+ background: "#e2e8f0",
760
+ margin: "20px 0"
761
+ };
762
+ const sectionLabelStyle = {
763
+ fontSize: 11,
764
+ fontWeight: 700,
765
+ textTransform: "uppercase",
766
+ letterSpacing: "0.1em",
767
+ color: "#94a3b8",
768
+ marginBottom: 12,
769
+ marginTop: 4,
770
+ paddingLeft: 4
771
+ };
772
+ const resetButtonStyle = {
773
+ width: "100%",
774
+ padding: "16px 20px",
775
+ background: "#fef2f2",
776
+ border: "1px solid #fecaca",
777
+ borderRadius: 14,
778
+ color: "#dc2626",
779
+ fontWeight: 700,
780
+ fontSize: 15,
781
+ cursor: "pointer",
782
+ display: "flex",
783
+ alignItems: "center",
784
+ justifyContent: "center",
785
+ gap: 10,
786
+ marginTop: 16,
787
+ ...styles.resetButton
788
+ };
789
+ const panelId = `a11y-panel-${uniqueId}`;
790
+ if (!portalContainer) {
791
+ return null;
792
+ }
793
+ const renderToggleItem = (key, icon, label) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
794
+ "div",
795
+ {
796
+ style: getSettingItemStyle(true),
797
+ className: classNames.settingItem,
798
+ children: [
799
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: itemHeaderStyle(true), children: [
800
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: iconContainerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: iconStyle, children: icon }) }),
801
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: labelStyle, children: label })
802
+ ] }),
803
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: toggleTrackStyle(settings[key]), children: [
804
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
805
+ "input",
806
+ {
807
+ type: "checkbox",
808
+ id: `${key}-${uniqueId}`,
809
+ checked: settings[key],
810
+ onChange: () => toggleSetting(key),
811
+ style: { opacity: 0, width: 0, height: 0, position: "absolute" },
812
+ "aria-label": label,
813
+ role: "switch",
814
+ "aria-checked": settings[key]
815
+ }
816
+ ),
817
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: toggleSliderStyle(settings[key]), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: toggleKnobStyle(settings[key]) }) })
818
+ ] })
819
+ ]
820
+ }
821
+ );
822
+ const renderSliderItem = (key, icon, label, decrementLabel = "\u2212", incrementLabel = "+") => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
823
+ "div",
824
+ {
825
+ style: getSettingItemStyle(false),
826
+ className: classNames.settingItem,
827
+ children: [
828
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: itemHeaderStyle(false), children: [
829
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: iconContainerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: iconStyle, children: icon }) }),
830
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: labelStyle, children: label })
831
+ ] }),
832
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: controlContainerStyle, role: "group", "aria-label": label, children: [
833
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
834
+ "button",
835
+ {
836
+ type: "button",
837
+ onClick: () => decrementSetting(key),
838
+ disabled: settings[key] === -2,
839
+ style: controlButtonStyle(settings[key] === -2),
840
+ "aria-label": `Decrease ${label}`,
841
+ children: decrementLabel
842
+ }
843
+ ),
844
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: valueDisplayStyle, "aria-live": "polite", children: settings[key] === 0 ? translations.normal : settings[key] > 0 ? `+${settings[key]}` : settings[key] }),
845
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
846
+ "button",
847
+ {
848
+ type: "button",
849
+ onClick: () => incrementSetting(key),
850
+ disabled: settings[key] === 2,
851
+ style: controlButtonStyle(settings[key] === 2),
852
+ "aria-label": `Increase ${label}`,
853
+ children: incrementLabel
854
+ }
855
+ )
856
+ ] })
857
+ ]
858
+ }
859
+ );
860
+ return (0, import_react_dom.createPortal)(
861
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
862
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
863
+ "button",
864
+ {
865
+ ref: buttonRef,
866
+ type: "button",
867
+ className: `a11y-widget-button ${classNames.button || ""}`,
868
+ style: buttonStyle,
869
+ onClick: () => isOpen ? handleClose() : handleOpen(),
870
+ "aria-label": buttonAriaLabel || translations.title,
871
+ "aria-expanded": isOpen,
872
+ "aria-controls": panelId,
873
+ "aria-haspopup": "dialog",
874
+ children: buttonIcon || /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AccessibilityIcon, { size: 32 })
875
+ }
876
+ ),
877
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
878
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
879
+ "div",
880
+ {
881
+ className: `a11y-widget-overlay ${classNames.overlay || ""}`,
882
+ style: overlayStyle,
883
+ onClick: handleClose,
884
+ "aria-hidden": "true"
885
+ }
886
+ ),
887
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
888
+ "div",
889
+ {
890
+ ref: panelRef,
891
+ id: panelId,
892
+ role: "dialog",
893
+ "aria-modal": "true",
894
+ "aria-label": translations.title,
895
+ className: `a11y-widget-panel ${classNames.panel || ""}`,
896
+ style: panelStyle,
897
+ children: [
898
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: classNames.panelHeader, style: headerStyle, children: [
899
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: headerTitleStyle, children: translations.title }),
900
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
901
+ "button",
902
+ {
903
+ type: "button",
904
+ style: closeButtonStyle,
905
+ onClick: handleClose,
906
+ "aria-label": translations.close,
907
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CloseIcon, { size: 20 })
908
+ }
909
+ )
910
+ ] }),
911
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: classNames.panelContent, style: contentStyle, children: [
912
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: sectionLabelStyle, children: translations.textAdjustments || "Text Adjustments" }),
913
+ renderSliderItem("textSize", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TextSizeIcon, {}), translations.textSize, "A\u2212", "A+"),
914
+ renderSliderItem("lineHeight", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LineHeightIcon, {}), translations.lineSpacing),
915
+ renderSliderItem("letterSpacing", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LetterSpacingIcon, {}), translations.letterSpacing),
916
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: dividerStyle, role: "separator", "aria-hidden": "true" }),
917
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: sectionLabelStyle, children: translations.visualAdjustments || "Visual Adjustments" }),
918
+ renderToggleItem("invertColors", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InvertIcon, {}), translations.invertColors),
919
+ renderToggleItem("grayscale", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GrayscaleIcon, {}), translations.grayscale),
920
+ renderToggleItem("hideImages", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ImageIcon, {}), translations.hideImages),
921
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: dividerStyle, role: "separator", "aria-hidden": "true" }),
922
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: sectionLabelStyle, children: translations.navigationAids || "Navigation Aids" }),
923
+ renderToggleItem("underlineLinks", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LinkIcon, {}), translations.underlineLinks),
924
+ renderToggleItem("bigCursor", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CursorIcon, {}), translations.bigCursor),
925
+ renderToggleItem("readingGuide", /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReadingGuideIcon, {}), translations.readingGuide),
926
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
927
+ "button",
928
+ {
929
+ type: "button",
930
+ style: resetButtonStyle,
931
+ onClick: resetSettings,
932
+ className: classNames.resetButton,
933
+ children: [
934
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ResetIcon, { size: 20 }),
935
+ translations.reset
936
+ ]
937
+ }
938
+ )
939
+ ] })
940
+ ]
941
+ }
942
+ )
943
+ ] })
944
+ ] }),
945
+ portalContainer
946
+ );
947
+ };
948
+
949
+ // src/translations/en.ts
950
+ var en = {
951
+ title: "Accessibility",
952
+ textSize: "Text Size",
953
+ lineSpacing: "Line Spacing",
954
+ letterSpacing: "Letter Spacing",
955
+ invertColors: "Invert Colors",
956
+ grayscale: "Grayscale",
957
+ underlineLinks: "Underline Links",
958
+ bigCursor: "Big Cursor",
959
+ readingGuide: "Reading Guide",
960
+ hideImages: "Hide Images",
961
+ reset: "Reset All",
962
+ normal: "Normal",
963
+ close: "Close accessibility panel",
964
+ textAdjustments: "Text Adjustments",
965
+ visualAdjustments: "Visual Adjustments",
966
+ navigationAids: "Navigation Aids"
967
+ };
968
+
969
+ // src/translations/ar.ts
970
+ var ar = {
971
+ title: "\u0625\u0645\u0643\u0627\u0646\u064A\u0629 \u0627\u0644\u0648\u0635\u0648\u0644",
972
+ textSize: "\u062D\u062C\u0645 \u0627\u0644\u0646\u0635",
973
+ lineSpacing: "\u062A\u0628\u0627\u0639\u062F \u0627\u0644\u0623\u0633\u0637\u0631",
974
+ letterSpacing: "\u062A\u0628\u0627\u0639\u062F \u0627\u0644\u0623\u062D\u0631\u0641",
975
+ invertColors: "\u0639\u0643\u0633 \u0627\u0644\u0623\u0644\u0648\u0627\u0646",
976
+ grayscale: "\u062A\u062F\u0631\u062C \u0631\u0645\u0627\u062F\u064A",
977
+ underlineLinks: "\u062A\u0633\u0637\u064A\u0631 \u0627\u0644\u0631\u0648\u0627\u0628\u0637",
978
+ bigCursor: "\u0645\u0624\u0634\u0631 \u0643\u0628\u064A\u0631",
979
+ readingGuide: "\u062F\u0644\u064A\u0644 \u0627\u0644\u0642\u0631\u0627\u0621\u0629",
980
+ hideImages: "\u0625\u062E\u0641\u0627\u0621 \u0627\u0644\u0635\u0648\u0631",
981
+ reset: "\u0625\u0639\u0627\u062F\u0629 \u062A\u0639\u064A\u064A\u0646",
982
+ normal: "\u0639\u0627\u062F\u064A",
983
+ close: "\u0625\u063A\u0644\u0627\u0642 \u0644\u0648\u062D\u0629 \u0625\u0645\u0643\u0627\u0646\u064A\u0629 \u0627\u0644\u0648\u0635\u0648\u0644",
984
+ textAdjustments: "\u062A\u0639\u062F\u064A\u0644\u0627\u062A \u0627\u0644\u0646\u0635",
985
+ visualAdjustments: "\u062A\u0639\u062F\u064A\u0644\u0627\u062A \u0628\u0635\u0631\u064A\u0629",
986
+ navigationAids: "\u0645\u0633\u0627\u0639\u062F\u0627\u062A \u0627\u0644\u062A\u0646\u0642\u0644"
987
+ };
988
+
989
+ // src/styles.ts
990
+ function injectAccessibilityStyles() {
991
+ if (typeof document === "undefined") return;
992
+ const styleId = "a11y-widget-global-styles";
993
+ if (document.getElementById(styleId)) return;
994
+ const style = document.createElement("style");
995
+ style.id = styleId;
996
+ style.textContent = `
997
+ /* Accessibility Widget Global Styles */
998
+
999
+ /* Text scaling - only when class is active */
1000
+ body.a11y-text-scaled *:not([class*="a11y-widget"]) {
1001
+ font-size: calc(1em * var(--a11y-text-scale, 1)) !important;
1002
+ }
1003
+
1004
+ /* Line height - only when class is active */
1005
+ body.a11y-line-height-active *:not([class*="a11y-widget"]) {
1006
+ line-height: var(--a11y-line-height, 1.5) !important;
1007
+ }
1008
+
1009
+ /* Letter spacing - only when class is active */
1010
+ body.a11y-letter-spacing-active *:not([class*="a11y-widget"]) {
1011
+ letter-spacing: var(--a11y-letter-spacing, normal) !important;
1012
+ }
1013
+
1014
+ /* Invert colors - applied to content wrapper */
1015
+ #a11y-content-wrapper.a11y-invert {
1016
+ filter: invert(1) hue-rotate(180deg);
1017
+ }
1018
+
1019
+ #a11y-content-wrapper.a11y-invert img:not(.a11y-widget-icon),
1020
+ #a11y-content-wrapper.a11y-invert video,
1021
+ #a11y-content-wrapper.a11y-invert [style*="background-image"],
1022
+ #a11y-content-wrapper.a11y-invert canvas,
1023
+ #a11y-content-wrapper.a11y-invert svg:not(.a11y-widget-icon) {
1024
+ filter: invert(1) hue-rotate(180deg);
1025
+ }
1026
+
1027
+ /* Grayscale - applied to content wrapper */
1028
+ #a11y-content-wrapper.a11y-grayscale {
1029
+ filter: grayscale(100%);
1030
+ }
1031
+
1032
+ /* Underline links */
1033
+ body.a11y-underline-links a {
1034
+ text-decoration: underline !important;
1035
+ text-decoration-thickness: 2px !important;
1036
+ text-underline-offset: 3px !important;
1037
+ }
1038
+
1039
+ /* Big cursor */
1040
+ body.a11y-big-cursor,
1041
+ body.a11y-big-cursor * {
1042
+ cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path fill="%232d2d2d" stroke="white" stroke-width="2" d="M10 3l20 15-8 2-4 9-5-3 4-8-7-2z"/></svg>') 8 8, auto !important;
1043
+ }
1044
+
1045
+ /* Hide images */
1046
+ body.a11y-hide-images img,
1047
+ body.a11y-hide-images [role="img"],
1048
+ body.a11y-hide-images svg:not([class*="a11y"]) {
1049
+ opacity: 0 !important;
1050
+ pointer-events: none !important;
1051
+ }
1052
+
1053
+ /* Reading guide line is created dynamically by the hook */
1054
+ `;
1055
+ document.head.appendChild(style);
1056
+ }
1057
+ function removeAccessibilityStyles() {
1058
+ if (typeof document === "undefined") return;
1059
+ const style = document.getElementById("a11y-widget-global-styles");
1060
+ if (style) {
1061
+ style.remove();
1062
+ }
1063
+ }
1064
+ var accessibilityStylesCSS = `
1065
+ /* Accessibility Widget Global Styles */
1066
+
1067
+ /* Text scaling - only when class is active */
1068
+ body.a11y-text-scaled *:not([class*="a11y-widget"]) {
1069
+ font-size: calc(1em * var(--a11y-text-scale, 1)) !important;
1070
+ }
1071
+
1072
+ /* Line height - only when class is active */
1073
+ body.a11y-line-height-active *:not([class*="a11y-widget"]) {
1074
+ line-height: var(--a11y-line-height, 1.5) !important;
1075
+ }
1076
+
1077
+ /* Letter spacing - only when class is active */
1078
+ body.a11y-letter-spacing-active *:not([class*="a11y-widget"]) {
1079
+ letter-spacing: var(--a11y-letter-spacing, normal) !important;
1080
+ }
1081
+
1082
+ /* Invert colors - applied to content wrapper */
1083
+ #a11y-content-wrapper.a11y-invert {
1084
+ filter: invert(1) hue-rotate(180deg);
1085
+ }
1086
+
1087
+ #a11y-content-wrapper.a11y-invert img:not(.a11y-widget-icon),
1088
+ #a11y-content-wrapper.a11y-invert video,
1089
+ #a11y-content-wrapper.a11y-invert [style*="background-image"],
1090
+ #a11y-content-wrapper.a11y-invert canvas,
1091
+ #a11y-content-wrapper.a11y-invert svg:not(.a11y-widget-icon) {
1092
+ filter: invert(1) hue-rotate(180deg);
1093
+ }
1094
+
1095
+ /* Grayscale - applied to content wrapper */
1096
+ #a11y-content-wrapper.a11y-grayscale {
1097
+ filter: grayscale(100%);
1098
+ }
1099
+
1100
+ /* Underline links */
1101
+ body.a11y-underline-links a {
1102
+ text-decoration: underline !important;
1103
+ text-decoration-thickness: 2px !important;
1104
+ text-underline-offset: 3px !important;
1105
+ }
1106
+
1107
+ /* Big cursor */
1108
+ body.a11y-big-cursor,
1109
+ body.a11y-big-cursor * {
1110
+ cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path fill="%232d2d2d" stroke="white" stroke-width="2" d="M10 3l20 15-8 2-4 9-5-3 4-8-7-2z"/></svg>') 8 8, auto !important;
1111
+ }
1112
+
1113
+ /* Hide images */
1114
+ body.a11y-hide-images img,
1115
+ body.a11y-hide-images [role="img"],
1116
+ body.a11y-hide-images svg:not([class*="a11y"]) {
1117
+ opacity: 0 !important;
1118
+ pointer-events: none !important;
1119
+ }
1120
+ `;
1121
+ // Annotate the CommonJS export names for ESM import in node:
1122
+ 0 && (module.exports = {
1123
+ AccessibilityIcon,
1124
+ AccessibilityWidget,
1125
+ CloseIcon,
1126
+ CursorIcon,
1127
+ GrayscaleIcon,
1128
+ ImageIcon,
1129
+ InvertIcon,
1130
+ LetterSpacingIcon,
1131
+ LineHeightIcon,
1132
+ LinkIcon,
1133
+ ReadingGuideIcon,
1134
+ ResetIcon,
1135
+ TextSizeIcon,
1136
+ accessibilityStylesCSS,
1137
+ ar,
1138
+ en,
1139
+ injectAccessibilityStyles,
1140
+ removeAccessibilityStyles,
1141
+ useAccessibilitySettings,
1142
+ useBackgroundContrast,
1143
+ useReadingGuide
1144
+ });