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