ngp-accessibility 1.0.3 → 1.0.5

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.
@@ -3,10 +3,14 @@ import { Language, TranslationKey } from "./translations";
3
3
  interface AccessibilityState {
4
4
  language: Language;
5
5
  textSize: number;
6
+ textMagnifier: boolean;
7
+ pauseAnimations: boolean;
8
+ readingGuide: boolean;
6
9
  highContrast: boolean;
7
10
  negativeContrast: boolean;
8
11
  lightBackground: boolean;
9
12
  underlineLinks: boolean;
13
+ highlightTitles: boolean;
10
14
  readableFont: boolean;
11
15
  voiceEnabled: boolean;
12
16
  }
@@ -14,10 +18,14 @@ interface AccessibilityContextType extends AccessibilityState {
14
18
  setLanguage: (lang: Language) => void;
15
19
  increaseText: () => void;
16
20
  decreaseText: () => void;
21
+ toggleTextMagnifier: () => void;
22
+ togglePauseAnimations: () => void;
23
+ toggleReadingGuide: () => void;
17
24
  toggleHighContrast: () => void;
18
25
  toggleNegativeContrast: () => void;
19
26
  toggleLightBackground: () => void;
20
27
  toggleUnderlineLinks: () => void;
28
+ toggleHighlightTitles: () => void;
21
29
  toggleReadableFont: () => void;
22
30
  toggleVoice: () => void;
23
31
  translate: (key: TranslationKey) => string;
@@ -1,24 +1,21 @@
1
1
  import React from "react";
2
2
  export interface AccessibilityDropdownClasses {
3
3
  root?: string;
4
- toggle?: string;
5
- menu?: string;
6
- section?: string;
7
- label?: string;
8
- select?: string;
9
- button?: string;
10
- activeButton?: string;
11
- voiceButton?: string;
4
+ trigger?: string;
5
+ panel?: string;
6
+ panelHeader?: string;
7
+ closeButton?: string;
8
+ }
9
+ export interface AccessibilityDropdownRenderTriggerProps {
10
+ isOpen: boolean;
11
+ toggle: () => void;
12
+ className: string;
12
13
  }
13
14
  export interface AccessibilityDropdownProps {
14
15
  className?: string;
15
16
  style?: React.CSSProperties;
16
17
  classes?: AccessibilityDropdownClasses;
17
- triggerLabel?: React.ReactNode;
18
- renderTrigger?: (params: {
19
- isOpen: boolean;
20
- toggle: () => void;
21
- className: string;
22
- }) => React.ReactNode;
18
+ triggerLabel?: string;
19
+ renderTrigger?: (props: AccessibilityDropdownRenderTriggerProps) => React.ReactNode;
23
20
  }
24
21
  export declare const AccessibilityDropdown: React.FC<AccessibilityDropdownProps>;
package/dist/index.esm.js CHANGED
@@ -2,46 +2,81 @@ import React, { createContext, useState, useEffect, useContext } from 'react';
2
2
 
3
3
  const translations = {
4
4
  en: {
5
- increaseText: 'Increase Text',
6
- decreaseText: 'Decrease Text',
7
- highContrast: 'High Contrast',
8
- negativeContrast: 'Negative Contrast',
9
- lightBackground: 'Light Background',
10
- underlineLinks: 'Underline Links',
11
- readableFont: 'Readable Font',
12
- voiceCommand: 'Voice Command',
5
+ increaseText: "Increase Text",
6
+ decreaseText: "Decrease Text",
7
+ textMagnifier: "Text Magnifier",
8
+ highContrast: "High Contrast",
9
+ negativeContrast: "Negative Contrast",
10
+ lightBackground: "Light Background",
11
+ underlineLinks: "Underline Links",
12
+ highlightTitles: "Highlight Titles",
13
+ readableFont: "Readable Font",
14
+ pauseAnimations: "Pause Animations",
15
+ readingGuide: "Reading Guide",
16
+ voiceCommand: "Voice Command",
13
17
  },
14
18
  tl: {
15
- increaseText: 'Palakihin ang Teksto',
16
- decreaseText: 'Paliitin ang Teksto',
17
- highContrast: 'Mataas na Contrast',
18
- negativeContrast: 'Negatibong Contrast',
19
- lightBackground: 'Maliwanag na Background',
20
- underlineLinks: 'May Guhit na Links',
21
- readableFont: 'Madaling Basahin na Font',
22
- voiceCommand: 'Voice Command',
19
+ increaseText: "Palakihin ang Teksto",
20
+ decreaseText: "Paliitin ang Teksto",
21
+ textMagnifier: "Text Magnifier",
22
+ highContrast: "Mataas na Contrast",
23
+ negativeContrast: "Negatibong Contrast",
24
+ lightBackground: "Maliwanag na Background",
25
+ underlineLinks: "May Guhit na Links",
26
+ highlightTitles: "I-highlight ang Mga Pamagat",
27
+ readableFont: "Madaling Basahin na Font",
28
+ pauseAnimations: "I-pause ang mga Animation",
29
+ readingGuide: "Reading Guide",
30
+ voiceCommand: "Voice Command",
23
31
  },
24
32
  ceb: {
25
- increaseText: 'Padak-on ang Teksto',
26
- decreaseText: 'Pagamay-on ang Teksto',
27
- highContrast: 'Taas nga Contrast',
28
- negativeContrast: 'Negatibo nga Contrast',
29
- lightBackground: 'Hayag nga Background',
30
- underlineLinks: 'Linya sa Ubos sa Links',
31
- readableFont: 'Sayon Basahon nga Font',
32
- voiceCommand: 'Voice Command',
33
+ increaseText: "Padak-on ang Teksto",
34
+ decreaseText: "Pagamay-on ang Teksto",
35
+ textMagnifier: "Text Magnifier",
36
+ highContrast: "Taas nga Contrast",
37
+ negativeContrast: "Negatibo nga Contrast",
38
+ lightBackground: "Hayag nga Background",
39
+ underlineLinks: "Linya sa Ubos sa Links",
40
+ highlightTitles: "I-highlight ang mga Ulohan",
41
+ readableFont: "Sayon Basahon nga Font",
42
+ pauseAnimations: "Ihunong ang mga Animation",
43
+ readingGuide: "Reading Guide",
44
+ voiceCommand: "Voice Command",
33
45
  },
34
46
  };
35
47
 
48
+ const normalizeMagnifierText = (value) => value.replace(/\s+/g, " ").trim();
49
+ const magnifierSelector = "p, li, button, h1, h2, h3, h4, h5, h6, [role=heading]";
50
+ const getMagnifierElement = (target) => {
51
+ if (!(target instanceof HTMLElement))
52
+ return null;
53
+ if (target.closest(".a11y-root"))
54
+ return null;
55
+ const element = target.closest(magnifierSelector);
56
+ return element instanceof HTMLElement ? element : null;
57
+ };
58
+ const getMagnifierText = (target) => {
59
+ const element = getMagnifierElement(target);
60
+ if (!element)
61
+ return "";
62
+ const ariaLabel = normalizeMagnifierText(element.getAttribute("aria-label") || "");
63
+ if (ariaLabel)
64
+ return ariaLabel;
65
+ return normalizeMagnifierText(element.innerText || element.textContent || "");
66
+ };
36
67
  const AccessibilityContext = createContext(undefined);
37
68
  const AccessibilityProvider = ({ children, translations: customTranslations, }) => {
38
69
  const [state, setState] = useState({
39
70
  language: "en",
40
71
  textSize: 100,
72
+ textMagnifier: false,
73
+ pauseAnimations: false,
74
+ readingGuide: false,
41
75
  highContrast: false,
42
76
  negativeContrast: false,
43
77
  lightBackground: false,
44
78
  underlineLinks: false,
79
+ highlightTitles: false,
45
80
  readableFont: false,
46
81
  voiceEnabled: false,
47
82
  });
@@ -53,8 +88,180 @@ const AccessibilityProvider = ({ children, translations: customTranslations, })
53
88
  root.classList.toggle("negative-contrast", state.negativeContrast);
54
89
  root.classList.toggle("light-background", state.lightBackground);
55
90
  root.classList.toggle("underline-links", state.underlineLinks);
91
+ root.classList.toggle("highlight-titles", state.highlightTitles);
56
92
  root.classList.toggle("readable-font", state.readableFont);
93
+ root.classList.toggle("pause-animations", state.pauseAnimations);
57
94
  }, [state]);
95
+ useEffect(() => {
96
+ if (!state.readingGuide)
97
+ return;
98
+ const guide = document.createElement("div");
99
+ guide.className = "a11y-reading-guide";
100
+ guide.setAttribute("aria-hidden", "true");
101
+ guide.innerHTML = `
102
+ <div class="a11y-reading-guide-top"></div>
103
+ <div class="a11y-reading-guide-focus"></div>
104
+ <div class="a11y-reading-guide-line"></div>
105
+ <div class="a11y-reading-guide-bottom"></div>
106
+ `;
107
+ document.body.appendChild(guide);
108
+ const topMask = guide.querySelector(".a11y-reading-guide-top");
109
+ const focusBand = guide.querySelector(".a11y-reading-guide-focus");
110
+ const focusLine = guide.querySelector(".a11y-reading-guide-line");
111
+ const bottomMask = guide.querySelector(".a11y-reading-guide-bottom");
112
+ const bandHeight = 72;
113
+ const halfBandHeight = bandHeight / 2;
114
+ const updateGuide = (clientY) => {
115
+ const safeY = Math.min(Math.max(halfBandHeight + 12, clientY), window.innerHeight - halfBandHeight - 12);
116
+ const top = Math.max(0, safeY - halfBandHeight);
117
+ const bottom = Math.min(window.innerHeight, safeY + halfBandHeight);
118
+ topMask.style.height = `${top}px`;
119
+ focusBand.style.top = `${top}px`;
120
+ focusBand.style.height = `${bottom - top}px`;
121
+ focusLine.style.top = `${safeY}px`;
122
+ bottomMask.style.top = `${bottom}px`;
123
+ bottomMask.style.height = `${Math.max(0, window.innerHeight - bottom)}px`;
124
+ };
125
+ const resetGuide = () => updateGuide(window.innerHeight / 2);
126
+ const handleMouseMove = (event) => updateGuide(event.clientY);
127
+ const handleTouchStart = (event) => {
128
+ const touch = event.touches[0];
129
+ if (touch)
130
+ updateGuide(touch.clientY);
131
+ };
132
+ const handleTouchMove = (event) => {
133
+ const touch = event.touches[0];
134
+ if (touch)
135
+ updateGuide(touch.clientY);
136
+ };
137
+ resetGuide();
138
+ document.addEventListener("mousemove", handleMouseMove, true);
139
+ document.addEventListener("touchstart", handleTouchStart, true);
140
+ document.addEventListener("touchmove", handleTouchMove, true);
141
+ window.addEventListener("resize", resetGuide);
142
+ return () => {
143
+ document.removeEventListener("mousemove", handleMouseMove, true);
144
+ document.removeEventListener("touchstart", handleTouchStart, true);
145
+ document.removeEventListener("touchmove", handleTouchMove, true);
146
+ window.removeEventListener("resize", resetGuide);
147
+ guide.remove();
148
+ };
149
+ }, [state.readingGuide]);
150
+ useEffect(() => {
151
+ if (!state.textMagnifier)
152
+ return;
153
+ const tooltip = document.createElement("div");
154
+ tooltip.className = "a11y-text-magnifier-tooltip";
155
+ tooltip.setAttribute("aria-hidden", "true");
156
+ document.body.appendChild(tooltip);
157
+ const hideTooltip = () => {
158
+ tooltip.removeAttribute("data-visible");
159
+ tooltip.textContent = "";
160
+ };
161
+ const showTooltip = (text) => {
162
+ tooltip.textContent = text;
163
+ tooltip.setAttribute("data-visible", "true");
164
+ };
165
+ const updateTooltipPosition = (clientX, clientY) => {
166
+ const tooltipWidth = tooltip.offsetWidth || 320;
167
+ const tooltipHeight = tooltip.offsetHeight || 56;
168
+ const left = Math.min(Math.max(12, clientX + 18), window.innerWidth - tooltipWidth - 12);
169
+ const top = clientY + tooltipHeight + 18 > window.innerHeight
170
+ ? Math.max(12, clientY - tooltipHeight - 18)
171
+ : clientY + 18;
172
+ tooltip.style.left = `${left}px`;
173
+ tooltip.style.top = `${top}px`;
174
+ };
175
+ const handleMouseMove = (event) => {
176
+ const text = getMagnifierText(event.target);
177
+ if (!text) {
178
+ hideTooltip();
179
+ return;
180
+ }
181
+ showTooltip(text);
182
+ updateTooltipPosition(event.clientX, event.clientY);
183
+ };
184
+ let touchTimer = null;
185
+ let activeTouchId = null;
186
+ let activeText = "";
187
+ let pressPoint = null;
188
+ const clearTouchTimer = () => {
189
+ if (touchTimer !== null) {
190
+ window.clearTimeout(touchTimer);
191
+ touchTimer = null;
192
+ }
193
+ };
194
+ const resetTouchState = () => {
195
+ clearTouchTimer();
196
+ activeTouchId = null;
197
+ activeText = "";
198
+ pressPoint = null;
199
+ hideTooltip();
200
+ };
201
+ const getTrackedTouch = (touches) => {
202
+ if (activeTouchId === null)
203
+ return null;
204
+ for (const touch of Array.from(touches)) {
205
+ if (touch.identifier === activeTouchId)
206
+ return touch;
207
+ }
208
+ return null;
209
+ };
210
+ const handleTouchStart = (event) => {
211
+ const touch = event.changedTouches[0];
212
+ if (!touch)
213
+ return;
214
+ const text = getMagnifierText(event.target);
215
+ if (!text) {
216
+ resetTouchState();
217
+ return;
218
+ }
219
+ clearTouchTimer();
220
+ activeTouchId = touch.identifier;
221
+ activeText = text;
222
+ pressPoint = { x: touch.clientX, y: touch.clientY };
223
+ touchTimer = window.setTimeout(() => {
224
+ showTooltip(activeText);
225
+ updateTooltipPosition(touch.clientX, touch.clientY);
226
+ touchTimer = null;
227
+ }, 450);
228
+ };
229
+ const handleTouchMove = (event) => {
230
+ const touch = getTrackedTouch(event.touches);
231
+ if (!touch)
232
+ return;
233
+ if (!tooltip.hasAttribute("data-visible")) {
234
+ if (pressPoint &&
235
+ (Math.abs(touch.clientX - pressPoint.x) > 10 ||
236
+ Math.abs(touch.clientY - pressPoint.y) > 10)) {
237
+ resetTouchState();
238
+ }
239
+ return;
240
+ }
241
+ updateTooltipPosition(touch.clientX, touch.clientY);
242
+ };
243
+ const handleTouchEnd = () => resetTouchState();
244
+ const handleTouchCancel = () => resetTouchState();
245
+ const handlePointerLeave = () => hideTooltip();
246
+ document.addEventListener("mousemove", handleMouseMove, true);
247
+ document.addEventListener("touchstart", handleTouchStart, true);
248
+ document.addEventListener("touchmove", handleTouchMove, true);
249
+ document.addEventListener("touchend", handleTouchEnd, true);
250
+ document.addEventListener("touchcancel", handleTouchCancel, true);
251
+ document.addEventListener("scroll", hideTooltip, true);
252
+ window.addEventListener("blur", handlePointerLeave);
253
+ return () => {
254
+ document.removeEventListener("mousemove", handleMouseMove, true);
255
+ document.removeEventListener("touchstart", handleTouchStart, true);
256
+ document.removeEventListener("touchmove", handleTouchMove, true);
257
+ document.removeEventListener("touchend", handleTouchEnd, true);
258
+ document.removeEventListener("touchcancel", handleTouchCancel, true);
259
+ document.removeEventListener("scroll", hideTooltip, true);
260
+ window.removeEventListener("blur", handlePointerLeave);
261
+ clearTouchTimer();
262
+ tooltip.remove();
263
+ };
264
+ }, [state.textMagnifier]);
58
265
  useEffect(() => {
59
266
  if (!state.voiceEnabled ||
60
267
  !("webkitSpeechRecognition" in window || "SpeechRecognition" in window))
@@ -87,6 +294,15 @@ const AccessibilityProvider = ({ children, translations: customTranslations, })
87
294
  toggleLightBackground();
88
295
  if (transcript.includes("underline") || transcript.includes("guhit"))
89
296
  toggleUnderlineLinks();
297
+ if (transcript.includes("highlight titles") ||
298
+ transcript.includes("title highlight"))
299
+ toggleHighlightTitles();
300
+ if (transcript.includes("pause animations") ||
301
+ transcript.includes("stop animations"))
302
+ togglePauseAnimations();
303
+ if (transcript.includes("reading guide") ||
304
+ transcript.includes("reading line"))
305
+ toggleReadingGuide();
90
306
  if (transcript.includes("readable font") ||
91
307
  transcript.includes("madaling"))
92
308
  toggleReadableFont();
@@ -97,10 +313,14 @@ const AccessibilityProvider = ({ children, translations: customTranslations, })
97
313
  const setLanguage = (lang) => setState((s) => (Object.assign(Object.assign({}, s), { language: lang })));
98
314
  const increaseText = () => setState((s) => (Object.assign(Object.assign({}, s), { textSize: Math.min(s.textSize + 10, 200) })));
99
315
  const decreaseText = () => setState((s) => (Object.assign(Object.assign({}, s), { textSize: Math.max(s.textSize - 10, 80) })));
316
+ const toggleTextMagnifier = () => setState((s) => (Object.assign(Object.assign({}, s), { textMagnifier: !s.textMagnifier })));
317
+ const togglePauseAnimations = () => setState((s) => (Object.assign(Object.assign({}, s), { pauseAnimations: !s.pauseAnimations })));
318
+ const toggleReadingGuide = () => setState((s) => (Object.assign(Object.assign({}, s), { readingGuide: !s.readingGuide })));
100
319
  const toggleHighContrast = () => setState((s) => (Object.assign(Object.assign({}, s), { highContrast: !s.highContrast, negativeContrast: false })));
101
320
  const toggleNegativeContrast = () => setState((s) => (Object.assign(Object.assign({}, s), { negativeContrast: !s.negativeContrast, highContrast: false })));
102
321
  const toggleLightBackground = () => setState((s) => (Object.assign(Object.assign({}, s), { lightBackground: !s.lightBackground })));
103
322
  const toggleUnderlineLinks = () => setState((s) => (Object.assign(Object.assign({}, s), { underlineLinks: !s.underlineLinks })));
323
+ const toggleHighlightTitles = () => setState((s) => (Object.assign(Object.assign({}, s), { highlightTitles: !s.highlightTitles })));
104
324
  const toggleReadableFont = () => setState((s) => (Object.assign(Object.assign({}, s), { readableFont: !s.readableFont })));
105
325
  const toggleVoice = () => setState((s) => (Object.assign(Object.assign({}, s), { voiceEnabled: !s.voiceEnabled })));
106
326
  const translate = (key) => translations[state.language][key];
@@ -108,10 +328,14 @@ const AccessibilityProvider = ({ children, translations: customTranslations, })
108
328
  return (React.createElement(AccessibilityContext.Provider, { value: Object.assign(Object.assign({}, state), { setLanguage,
109
329
  increaseText,
110
330
  decreaseText,
331
+ toggleTextMagnifier,
332
+ togglePauseAnimations,
333
+ toggleReadingGuide,
111
334
  toggleHighContrast,
112
335
  toggleNegativeContrast,
113
336
  toggleLightBackground,
114
337
  toggleUnderlineLinks,
338
+ toggleHighlightTitles,
115
339
  toggleReadableFont,
116
340
  toggleVoice,
117
341
  translate,
@@ -126,7 +350,7 @@ const useAccessibility = () => {
126
350
 
127
351
  const cn$1 = (...parts) => parts.filter(Boolean).join(" ");
128
352
  const AccessibilityToolbar = ({ className, style, classes, }) => {
129
- const { language, setLanguage, increaseText, decreaseText, toggleHighContrast, toggleNegativeContrast, toggleLightBackground, toggleUnderlineLinks, toggleReadableFont, toggleVoice, translate, highContrast, negativeContrast, lightBackground, underlineLinks, readableFont, voiceEnabled, } = useAccessibility();
353
+ const { language, setLanguage, increaseText, decreaseText, toggleTextMagnifier, togglePauseAnimations, toggleReadingGuide, toggleHighContrast, toggleNegativeContrast, toggleLightBackground, toggleUnderlineLinks, toggleHighlightTitles, toggleReadableFont, toggleVoice, translate, textMagnifier, pauseAnimations, readingGuide, highContrast, negativeContrast, lightBackground, underlineLinks, highlightTitles, readableFont, voiceEnabled, } = useAccessibility();
130
354
  return (React.createElement("div", { className: cn$1("accessibility-toolbar", classes === null || classes === void 0 ? void 0 : classes.root, className), style: style },
131
355
  React.createElement("select", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.select), value: language, onChange: (e) => setLanguage(e.target.value) },
132
356
  React.createElement("option", { value: "en" }, "English"),
@@ -138,11 +362,15 @@ const AccessibilityToolbar = ({ className, style, classes, }) => {
138
362
  React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button), onClick: decreaseText },
139
363
  "- ",
140
364
  translate("decreaseText")),
365
+ React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, textMagnifier && "active", textMagnifier && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": textMagnifier, onClick: toggleTextMagnifier }, translate("textMagnifier")),
141
366
  React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, highContrast && "active", highContrast && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": highContrast, onClick: toggleHighContrast }, translate("highContrast")),
142
367
  React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, negativeContrast && "active", negativeContrast && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": negativeContrast, onClick: toggleNegativeContrast }, translate("negativeContrast")),
143
368
  React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, lightBackground && "active", lightBackground && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": lightBackground, onClick: toggleLightBackground }, translate("lightBackground")),
144
369
  React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, underlineLinks && "active", underlineLinks && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": underlineLinks, onClick: toggleUnderlineLinks }, translate("underlineLinks")),
370
+ React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, highlightTitles && "active", highlightTitles && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": highlightTitles, onClick: toggleHighlightTitles }, translate("highlightTitles")),
145
371
  React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, readableFont && "active", readableFont && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": readableFont, onClick: toggleReadableFont }, translate("readableFont")),
372
+ React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, pauseAnimations && "active", pauseAnimations && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": pauseAnimations, onClick: togglePauseAnimations }, translate("pauseAnimations")),
373
+ React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, readingGuide && "active", readingGuide && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": readingGuide, onClick: toggleReadingGuide }, translate("readingGuide")),
146
374
  React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, classes === null || classes === void 0 ? void 0 : classes.voiceButton, voiceEnabled && "active", voiceEnabled && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": voiceEnabled, onClick: toggleVoice },
147
375
  "\uD83C\uDFA4 ",
148
376
  translate("voiceCommand"))));
@@ -151,37 +379,56 @@ const AccessibilityToolbar = ({ className, style, classes, }) => {
151
379
  const cn = (...parts) => parts.filter(Boolean).join(" ");
152
380
  const AccessibilityDropdown = ({ className, style, classes, triggerLabel = "♿ Accessibility", renderTrigger, }) => {
153
381
  const [isOpen, setIsOpen] = useState(false);
154
- const { language, setLanguage, increaseText, decreaseText, toggleHighContrast, toggleNegativeContrast, toggleLightBackground, toggleUnderlineLinks, toggleReadableFont, toggleVoice, translate, highContrast, negativeContrast, lightBackground, underlineLinks, readableFont, voiceEnabled, } = useAccessibility();
382
+ const { language, setLanguage, textSize, increaseText, decreaseText, toggleTextMagnifier, togglePauseAnimations, toggleReadingGuide, toggleHighContrast, toggleNegativeContrast, toggleLightBackground, toggleUnderlineLinks, toggleHighlightTitles, toggleReadableFont, toggleVoice, translate, textMagnifier, pauseAnimations, readingGuide, highContrast, negativeContrast, lightBackground, underlineLinks, highlightTitles, readableFont, voiceEnabled, } = useAccessibility();
155
383
  const toggle = () => setIsOpen(!isOpen);
156
- return (React.createElement("div", { className: cn("accessibility-dropdown", classes === null || classes === void 0 ? void 0 : classes.root, className), style: style },
384
+ const closePanel = () => setIsOpen(false);
385
+ const textScaleDelta = textSize - 100;
386
+ const textScaleLabel = textScaleDelta === 0
387
+ ? "Default"
388
+ : `${textScaleDelta > 0 ? "+" : ""}${textScaleDelta}%`;
389
+ return (React.createElement("div", { className: cn("a11y-root", classes === null || classes === void 0 ? void 0 : classes.root, className), style: style },
157
390
  renderTrigger ? (renderTrigger({
158
391
  isOpen,
159
392
  toggle,
160
- className: cn("accessibility-dropdown-toggle", classes === null || classes === void 0 ? void 0 : classes.toggle),
161
- })) : (React.createElement("button", { className: cn("accessibility-dropdown-toggle", classes === null || classes === void 0 ? void 0 : classes.toggle), onClick: toggle }, triggerLabel)),
162
- isOpen && (React.createElement("div", { className: cn("accessibility-dropdown-menu", classes === null || classes === void 0 ? void 0 : classes.menu) },
163
- React.createElement("div", { className: cn("accessibility-dropdown-section", classes === null || classes === void 0 ? void 0 : classes.section) },
164
- React.createElement("label", { className: cn(classes === null || classes === void 0 ? void 0 : classes.label) }, "Language:"),
165
- React.createElement("select", { className: cn(classes === null || classes === void 0 ? void 0 : classes.select), value: language, onChange: (e) => setLanguage(e.target.value) },
393
+ className: cn("a11y-trigger", classes === null || classes === void 0 ? void 0 : classes.trigger),
394
+ })) : (React.createElement("button", { className: cn("a11y-trigger", classes === null || classes === void 0 ? void 0 : classes.trigger), onClick: toggle }, triggerLabel)),
395
+ isOpen && (React.createElement("div", { className: cn("a11y-panel", classes === null || classes === void 0 ? void 0 : classes.panel) },
396
+ React.createElement("div", { className: cn("a11y-panel-header", classes === null || classes === void 0 ? void 0 : classes.panelHeader) },
397
+ React.createElement("div", { className: "a11y-panel-heading" },
398
+ React.createElement("span", { className: "a11y-panel-eyebrow" }, "NGP"),
399
+ React.createElement("label", { className: "a11y-panel-title" }, "Accessibility Options")),
400
+ React.createElement("button", { type: "button", className: cn("a11y-panel-close", classes === null || classes === void 0 ? void 0 : classes.closeButton), onClick: closePanel, "aria-label": "Close accessibility panel" }, "\u00D7")),
401
+ React.createElement("div", { className: "a11y-language" },
402
+ React.createElement("label", { htmlFor: "a11y-language-select" }, "Language"),
403
+ React.createElement("select", { id: "a11y-language-select", value: language, onChange: (e) => setLanguage(e.target.value) },
166
404
  React.createElement("option", { value: "en" }, "English"),
167
405
  React.createElement("option", { value: "tl" }, "Tagalog"),
168
406
  React.createElement("option", { value: "ceb" }, "Cebuano"))),
169
- React.createElement("div", { className: cn("accessibility-dropdown-section", classes === null || classes === void 0 ? void 0 : classes.section) },
170
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button), onClick: increaseText },
171
- "+ ",
172
- translate("increaseText")),
173
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button), onClick: decreaseText },
174
- "- ",
175
- translate("decreaseText"))),
176
- React.createElement("div", { className: cn("accessibility-dropdown-section", classes === null || classes === void 0 ? void 0 : classes.section) },
177
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button, highContrast && "active", highContrast && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": highContrast, onClick: toggleHighContrast }, translate("highContrast")),
178
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button, negativeContrast && "active", negativeContrast && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": negativeContrast, onClick: toggleNegativeContrast }, translate("negativeContrast")),
179
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button, lightBackground && "active", lightBackground && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": lightBackground, onClick: toggleLightBackground }, translate("lightBackground")),
180
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button, underlineLinks && "active", underlineLinks && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": underlineLinks, onClick: toggleUnderlineLinks }, translate("underlineLinks")),
181
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button, readableFont && "active", readableFont && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": readableFont, onClick: toggleReadableFont }, translate("readableFont")),
182
- React.createElement("button", { className: cn(classes === null || classes === void 0 ? void 0 : classes.button, classes === null || classes === void 0 ? void 0 : classes.voiceButton, voiceEnabled && "active", voiceEnabled && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": voiceEnabled, onClick: toggleVoice },
183
- "\uD83C\uDFA4 ",
184
- translate("voiceCommand")))))));
407
+ React.createElement("section", { className: "a11y-section" },
408
+ React.createElement("h3", { className: "a11y-section-title" }, "Content Adjustments"),
409
+ React.createElement("div", { className: "a11y-card" },
410
+ React.createElement("span", { className: "a11y-card-title" }, "Content Scaling"),
411
+ React.createElement("div", { className: "a11y-stepper" },
412
+ React.createElement("button", { onClick: decreaseText }, "\u2212"),
413
+ React.createElement("span", { className: "a11y-stepper-value" }, textScaleLabel),
414
+ React.createElement("button", { onClick: increaseText }, "+"))),
415
+ React.createElement("div", { className: "a11y-grid" },
416
+ React.createElement("button", { className: cn("a11y-card", textMagnifier && "active"), onClick: toggleTextMagnifier }, translate("textMagnifier")),
417
+ React.createElement("button", { className: cn("a11y-card", readableFont && "active"), onClick: toggleReadableFont }, "Readable Font"),
418
+ React.createElement("button", { className: cn("a11y-card", underlineLinks && "active"), onClick: toggleUnderlineLinks }, "Highlight Links"),
419
+ React.createElement("button", { className: cn("a11y-card", highlightTitles && "active"), onClick: toggleHighlightTitles }, "Highlight Titles"))),
420
+ React.createElement("section", { className: "a11y-section" },
421
+ React.createElement("h3", { className: "a11y-section-title" }, "Color Adjustments"),
422
+ React.createElement("div", { className: "a11y-grid" },
423
+ React.createElement("button", { className: cn("a11y-card", highContrast && "active"), onClick: toggleHighContrast }, translate("highContrast")),
424
+ React.createElement("button", { className: cn("a11y-card", negativeContrast && "active"), onClick: toggleNegativeContrast }, translate("negativeContrast")),
425
+ React.createElement("button", { className: cn("a11y-card", lightBackground && "active"), onClick: toggleLightBackground }, translate("lightBackground")))),
426
+ React.createElement("section", { className: "a11y-section" },
427
+ React.createElement("h3", { className: "a11y-section-title" }, "Accessibility Tools"),
428
+ React.createElement("div", { className: "a11y-grid" },
429
+ React.createElement("button", { className: cn("a11y-card", pauseAnimations && "active"), onClick: togglePauseAnimations }, translate("pauseAnimations")),
430
+ React.createElement("button", { className: cn("a11y-card", readingGuide && "active"), onClick: toggleReadingGuide }, translate("readingGuide")),
431
+ React.createElement("button", { className: cn("a11y-card", voiceEnabled && "active"), onClick: toggleVoice }, translate("voiceCommand"))))))));
185
432
  };
186
433
 
187
434
  const T = ({ k, children }) => {