ngp-accessibility 1.0.3 → 1.0.6
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/README.md +102 -5
- package/dist/AccessibilityContext.d.ts +20 -1
- package/dist/AccessibilityDropdown.d.ts +27 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +570 -55
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +570 -55
- package/dist/index.js.map +1 -1
- package/dist/styles.css +532 -1
- package/dist/translations.d.ts +26 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -4,50 +4,165 @@ var React = require('react');
|
|
|
4
4
|
|
|
5
5
|
const translations = {
|
|
6
6
|
en: {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
language: "Language",
|
|
8
|
+
increaseText: "Increase Text",
|
|
9
|
+
decreaseText: "Decrease Text",
|
|
10
|
+
textMagnifier: "Text Magnifier",
|
|
11
|
+
highContrast: "High Contrast",
|
|
12
|
+
negativeContrast: "Negative Contrast",
|
|
13
|
+
lightBackground: "Light Background",
|
|
14
|
+
underlineLinks: "Underline Links",
|
|
15
|
+
highlightTitles: "Highlight Titles",
|
|
16
|
+
readableFont: "Readable Font",
|
|
17
|
+
pauseAnimations: "Pause Animations",
|
|
18
|
+
readingGuide: "Reading Guide",
|
|
19
|
+
voiceCommand: "Voice Command",
|
|
20
|
+
readAloud: "Read Aloud",
|
|
21
|
+
colorBlindMode: "Color Blind Mode",
|
|
22
|
+
focusIndicator: "Focus Indicator",
|
|
15
23
|
},
|
|
16
24
|
tl: {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
language: "Wika",
|
|
26
|
+
increaseText: "Palakihin ang Teksto",
|
|
27
|
+
decreaseText: "Paliitin ang Teksto",
|
|
28
|
+
textMagnifier: "Text Magnifier",
|
|
29
|
+
highContrast: "Mataas na Contrast",
|
|
30
|
+
negativeContrast: "Negatibong Contrast",
|
|
31
|
+
lightBackground: "Maliwanag na Background",
|
|
32
|
+
underlineLinks: "May Guhit na Links",
|
|
33
|
+
highlightTitles: "I-highlight ang Mga Pamagat",
|
|
34
|
+
readableFont: "Madaling Basahin na Font",
|
|
35
|
+
pauseAnimations: "I-pause ang mga Animation",
|
|
36
|
+
readingGuide: "Reading Guide",
|
|
37
|
+
voiceCommand: "Voice Command",
|
|
38
|
+
readAloud: "Basahin nang Malakas",
|
|
39
|
+
colorBlindMode: "Color Blind Mode",
|
|
40
|
+
focusIndicator: "Focus Indicator",
|
|
25
41
|
},
|
|
26
42
|
ceb: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
language: "Pinulongan",
|
|
44
|
+
increaseText: "Padak-on ang Teksto",
|
|
45
|
+
decreaseText: "Pagamay-on ang Teksto",
|
|
46
|
+
textMagnifier: "Text Magnifier",
|
|
47
|
+
highContrast: "Taas nga Contrast",
|
|
48
|
+
negativeContrast: "Negatibo nga Contrast",
|
|
49
|
+
lightBackground: "Hayag nga Background",
|
|
50
|
+
underlineLinks: "Linya sa Ubos sa Links",
|
|
51
|
+
highlightTitles: "I-highlight ang mga Ulohan",
|
|
52
|
+
readableFont: "Sayon Basahon nga Font",
|
|
53
|
+
pauseAnimations: "Ihunong ang mga Animation",
|
|
54
|
+
readingGuide: "Reading Guide",
|
|
55
|
+
voiceCommand: "Voice Command",
|
|
56
|
+
readAloud: "Basaha og Kusog",
|
|
57
|
+
colorBlindMode: "Color Blind Mode",
|
|
58
|
+
focusIndicator: "Focus Indicator",
|
|
35
59
|
},
|
|
36
60
|
};
|
|
37
61
|
|
|
62
|
+
const GOOGLE_TRANSLATE_COOKIE_NAME = "googtrans";
|
|
63
|
+
const GOOGLE_TRANSLATE_SOURCE_LANGUAGE = "en";
|
|
64
|
+
const getCookieDomains = () => {
|
|
65
|
+
const domains = new Set([window.location.hostname]);
|
|
66
|
+
const hostnameParts = window.location.hostname.split(".");
|
|
67
|
+
if (hostnameParts.length > 2) {
|
|
68
|
+
domains.add(hostnameParts.slice(-2).join("."));
|
|
69
|
+
}
|
|
70
|
+
return Array.from(domains);
|
|
71
|
+
};
|
|
72
|
+
const setGoogleTranslateCookie = (targetLanguage) => {
|
|
73
|
+
const cookieValue = `/${GOOGLE_TRANSLATE_SOURCE_LANGUAGE}/${targetLanguage}`;
|
|
74
|
+
document.cookie = `${GOOGLE_TRANSLATE_COOKIE_NAME}=${cookieValue}; path=/; SameSite=Lax`;
|
|
75
|
+
for (const domain of getCookieDomains()) {
|
|
76
|
+
document.cookie = `${GOOGLE_TRANSLATE_COOKIE_NAME}=${cookieValue}; path=/; domain=${domain}; SameSite=Lax`;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const clearGoogleTranslateCookie = () => {
|
|
80
|
+
document.cookie = `${GOOGLE_TRANSLATE_COOKIE_NAME}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Lax`;
|
|
81
|
+
for (const domain of getCookieDomains()) {
|
|
82
|
+
document.cookie = `${GOOGLE_TRANSLATE_COOKIE_NAME}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}; SameSite=Lax`;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const dispatchNativeChangeEvent = (element) => {
|
|
86
|
+
element.dispatchEvent(new Event("change", { bubbles: true }));
|
|
87
|
+
};
|
|
88
|
+
const normalizeMagnifierText = (value) => value.replace(/\s+/g, " ").trim();
|
|
89
|
+
const magnifierSelector = "p, li, button, h1, h2, h3, h4, h5, h6, [role=heading]";
|
|
90
|
+
const getMagnifierElement = (target) => {
|
|
91
|
+
if (!(target instanceof HTMLElement))
|
|
92
|
+
return null;
|
|
93
|
+
if (target.closest(".a11y-root"))
|
|
94
|
+
return null;
|
|
95
|
+
const element = target.closest(magnifierSelector);
|
|
96
|
+
return element instanceof HTMLElement ? element : null;
|
|
97
|
+
};
|
|
98
|
+
const getMagnifierText = (target) => {
|
|
99
|
+
const element = getMagnifierElement(target);
|
|
100
|
+
if (!element)
|
|
101
|
+
return "";
|
|
102
|
+
const ariaLabel = normalizeMagnifierText(element.getAttribute("aria-label") || "");
|
|
103
|
+
if (ariaLabel)
|
|
104
|
+
return ariaLabel;
|
|
105
|
+
return normalizeMagnifierText(element.innerText || element.textContent || "");
|
|
106
|
+
};
|
|
38
107
|
const AccessibilityContext = React.createContext(undefined);
|
|
39
|
-
const AccessibilityProvider = ({ children, translations: customTranslations, }) => {
|
|
108
|
+
const AccessibilityProvider = ({ children, translations: customTranslations, googleTranslateTargetSelector, translationTargetSelector, }) => {
|
|
109
|
+
var _a;
|
|
40
110
|
const [state, setState] = React.useState({
|
|
41
111
|
language: "en",
|
|
42
112
|
textSize: 100,
|
|
113
|
+
textMagnifier: false,
|
|
114
|
+
pauseAnimations: false,
|
|
115
|
+
readingGuide: false,
|
|
43
116
|
highContrast: false,
|
|
44
117
|
negativeContrast: false,
|
|
45
118
|
lightBackground: false,
|
|
46
119
|
underlineLinks: false,
|
|
120
|
+
highlightTitles: false,
|
|
47
121
|
readableFont: false,
|
|
48
122
|
voiceEnabled: false,
|
|
123
|
+
readAloud: false,
|
|
124
|
+
colorBlindMode: "none",
|
|
125
|
+
focusIndicator: false,
|
|
49
126
|
});
|
|
50
127
|
const allTranslations = customTranslations || translations;
|
|
128
|
+
const defaultUiTranslations = translations.en;
|
|
129
|
+
const manualTranslationsForLanguage = translations[state.language];
|
|
130
|
+
const hasManualTranslations = Boolean(manualTranslationsForLanguage);
|
|
131
|
+
const resolvedTranslationTargetSelector = (_a = googleTranslateTargetSelector !== null && googleTranslateTargetSelector !== void 0 ? googleTranslateTargetSelector : translationTargetSelector) !== null && _a !== void 0 ? _a : "main";
|
|
132
|
+
React.useEffect(() => {
|
|
133
|
+
const target = document.querySelector(resolvedTranslationTargetSelector);
|
|
134
|
+
if (!target) {
|
|
135
|
+
console.warn(`[NGP Accessibility] Google translation target selector "${resolvedTranslationTargetSelector}" did not match any element. Falling back to page-wide translation behavior.`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const markedElements = new Set();
|
|
139
|
+
let current = target;
|
|
140
|
+
while (current && current !== document.body) {
|
|
141
|
+
const parentElement = current.parentElement;
|
|
142
|
+
if (!parentElement)
|
|
143
|
+
break;
|
|
144
|
+
for (const sibling of Array.from(parentElement.children)) {
|
|
145
|
+
if (sibling === current || !(sibling instanceof HTMLElement))
|
|
146
|
+
continue;
|
|
147
|
+
if (sibling.id === "a11y-google-translate-element")
|
|
148
|
+
continue;
|
|
149
|
+
sibling.classList.add("notranslate");
|
|
150
|
+
sibling.setAttribute("translate", "no");
|
|
151
|
+
sibling.dataset.a11yTranslationScoped = "true";
|
|
152
|
+
markedElements.add(sibling);
|
|
153
|
+
}
|
|
154
|
+
current = parentElement;
|
|
155
|
+
}
|
|
156
|
+
return () => {
|
|
157
|
+
for (const element of markedElements) {
|
|
158
|
+
if (element.dataset.a11yTranslationScoped !== "true")
|
|
159
|
+
continue;
|
|
160
|
+
element.classList.remove("notranslate");
|
|
161
|
+
element.removeAttribute("translate");
|
|
162
|
+
delete element.dataset.a11yTranslationScoped;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}, [resolvedTranslationTargetSelector]);
|
|
51
166
|
React.useEffect(() => {
|
|
52
167
|
const root = document.documentElement;
|
|
53
168
|
root.style.fontSize = `${state.textSize}%`;
|
|
@@ -55,8 +170,276 @@ const AccessibilityProvider = ({ children, translations: customTranslations, })
|
|
|
55
170
|
root.classList.toggle("negative-contrast", state.negativeContrast);
|
|
56
171
|
root.classList.toggle("light-background", state.lightBackground);
|
|
57
172
|
root.classList.toggle("underline-links", state.underlineLinks);
|
|
173
|
+
root.classList.toggle("highlight-titles", state.highlightTitles);
|
|
58
174
|
root.classList.toggle("readable-font", state.readableFont);
|
|
175
|
+
root.classList.toggle("pause-animations", state.pauseAnimations);
|
|
176
|
+
root.classList.toggle("focus-indicator", state.focusIndicator);
|
|
177
|
+
const body = document.body;
|
|
178
|
+
if (state.colorBlindMode !== "none") {
|
|
179
|
+
body.style.filter = `url(#a11y-${state.colorBlindMode})`;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
body.style.filter = "";
|
|
183
|
+
}
|
|
59
184
|
}, [state]);
|
|
185
|
+
React.useEffect(() => {
|
|
186
|
+
const svgId = "a11y-colorblind-filters";
|
|
187
|
+
if (document.getElementById(svgId))
|
|
188
|
+
return;
|
|
189
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
190
|
+
svg.id = svgId;
|
|
191
|
+
svg.setAttribute("aria-hidden", "true");
|
|
192
|
+
svg.style.cssText = "position:absolute;width:0;height:0;overflow:hidden;";
|
|
193
|
+
svg.innerHTML = `
|
|
194
|
+
<defs>
|
|
195
|
+
<filter id="a11y-protanopia">
|
|
196
|
+
<feColorMatrix type="matrix" values="
|
|
197
|
+
0.567 0.433 0 0 0
|
|
198
|
+
0.558 0.442 0 0 0
|
|
199
|
+
0 0.242 0.758 0 0
|
|
200
|
+
0 0 0 1 0"/>
|
|
201
|
+
</filter>
|
|
202
|
+
<filter id="a11y-deuteranopia">
|
|
203
|
+
<feColorMatrix type="matrix" values="
|
|
204
|
+
0.625 0.375 0 0 0
|
|
205
|
+
0.7 0.3 0 0 0
|
|
206
|
+
0 0.3 0.7 0 0
|
|
207
|
+
0 0 0 1 0"/>
|
|
208
|
+
</filter>
|
|
209
|
+
<filter id="a11y-tritanopia">
|
|
210
|
+
<feColorMatrix type="matrix" values="
|
|
211
|
+
0.95 0.05 0 0 0
|
|
212
|
+
0 0.433 0.567 0 0
|
|
213
|
+
0 0.475 0.525 0 0
|
|
214
|
+
0 0 0 1 0"/>
|
|
215
|
+
</filter>
|
|
216
|
+
</defs>
|
|
217
|
+
`;
|
|
218
|
+
document.body.prepend(svg);
|
|
219
|
+
return () => {
|
|
220
|
+
var _a;
|
|
221
|
+
(_a = document.getElementById(svgId)) === null || _a === void 0 ? void 0 : _a.remove();
|
|
222
|
+
};
|
|
223
|
+
}, []);
|
|
224
|
+
React.useEffect(() => {
|
|
225
|
+
if (!state.readAloud || !("speechSynthesis" in window))
|
|
226
|
+
return;
|
|
227
|
+
const readableSelector = "p, li, button, a, h1, h2, h3, h4, h5, h6, label, td, th, [role='button'], [role='heading'], [role='link']";
|
|
228
|
+
const speak = (text) => {
|
|
229
|
+
window.speechSynthesis.cancel();
|
|
230
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
231
|
+
utterance.lang =
|
|
232
|
+
state.language === "tl"
|
|
233
|
+
? "tl-PH"
|
|
234
|
+
: state.language === "ceb"
|
|
235
|
+
? "fil-PH"
|
|
236
|
+
: "en-US";
|
|
237
|
+
utterance.rate = 0.95;
|
|
238
|
+
window.speechSynthesis.speak(utterance);
|
|
239
|
+
};
|
|
240
|
+
const getReadableText = (el) => normalizeMagnifierText(el.getAttribute("aria-label") ||
|
|
241
|
+
el.getAttribute("placeholder") ||
|
|
242
|
+
el.getAttribute("title") ||
|
|
243
|
+
el.innerText ||
|
|
244
|
+
el.textContent ||
|
|
245
|
+
"");
|
|
246
|
+
const handleMouseOver = (event) => {
|
|
247
|
+
const target = event.target;
|
|
248
|
+
if (!target)
|
|
249
|
+
return;
|
|
250
|
+
const el = target.closest(readableSelector);
|
|
251
|
+
if (!el || el.closest(".a11y-root"))
|
|
252
|
+
return;
|
|
253
|
+
const text = getReadableText(el);
|
|
254
|
+
if (text)
|
|
255
|
+
speak(text);
|
|
256
|
+
};
|
|
257
|
+
const handleFocus = (event) => {
|
|
258
|
+
const el = event.target;
|
|
259
|
+
if (!el || el.closest(".a11y-root"))
|
|
260
|
+
return;
|
|
261
|
+
const text = getReadableText(el);
|
|
262
|
+
if (text)
|
|
263
|
+
speak(text);
|
|
264
|
+
};
|
|
265
|
+
document.addEventListener("mouseover", handleMouseOver, true);
|
|
266
|
+
document.addEventListener("focusin", handleFocus, true);
|
|
267
|
+
return () => {
|
|
268
|
+
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
269
|
+
document.removeEventListener("focusin", handleFocus, true);
|
|
270
|
+
window.speechSynthesis.cancel();
|
|
271
|
+
};
|
|
272
|
+
}, [state.readAloud, state.language]);
|
|
273
|
+
React.useEffect(() => {
|
|
274
|
+
if (!state.readingGuide)
|
|
275
|
+
return;
|
|
276
|
+
const guide = document.createElement("div");
|
|
277
|
+
guide.className = "a11y-reading-guide";
|
|
278
|
+
guide.setAttribute("aria-hidden", "true");
|
|
279
|
+
guide.innerHTML = `
|
|
280
|
+
<div class="a11y-reading-guide-top"></div>
|
|
281
|
+
<div class="a11y-reading-guide-focus"></div>
|
|
282
|
+
<div class="a11y-reading-guide-line"></div>
|
|
283
|
+
<div class="a11y-reading-guide-bottom"></div>
|
|
284
|
+
`;
|
|
285
|
+
document.body.appendChild(guide);
|
|
286
|
+
const topMask = guide.querySelector(".a11y-reading-guide-top");
|
|
287
|
+
const focusBand = guide.querySelector(".a11y-reading-guide-focus");
|
|
288
|
+
const focusLine = guide.querySelector(".a11y-reading-guide-line");
|
|
289
|
+
const bottomMask = guide.querySelector(".a11y-reading-guide-bottom");
|
|
290
|
+
const bandHeight = 72;
|
|
291
|
+
const halfBandHeight = bandHeight / 2;
|
|
292
|
+
const updateGuide = (clientY) => {
|
|
293
|
+
const safeY = Math.min(Math.max(halfBandHeight + 12, clientY), window.innerHeight - halfBandHeight - 12);
|
|
294
|
+
const top = Math.max(0, safeY - halfBandHeight);
|
|
295
|
+
const bottom = Math.min(window.innerHeight, safeY + halfBandHeight);
|
|
296
|
+
topMask.style.height = `${top}px`;
|
|
297
|
+
focusBand.style.top = `${top}px`;
|
|
298
|
+
focusBand.style.height = `${bottom - top}px`;
|
|
299
|
+
focusLine.style.top = `${safeY}px`;
|
|
300
|
+
bottomMask.style.top = `${bottom}px`;
|
|
301
|
+
bottomMask.style.height = `${Math.max(0, window.innerHeight - bottom)}px`;
|
|
302
|
+
};
|
|
303
|
+
const resetGuide = () => updateGuide(window.innerHeight / 2);
|
|
304
|
+
const handleMouseMove = (event) => updateGuide(event.clientY);
|
|
305
|
+
const handleTouchStart = (event) => {
|
|
306
|
+
const touch = event.touches[0];
|
|
307
|
+
if (touch)
|
|
308
|
+
updateGuide(touch.clientY);
|
|
309
|
+
};
|
|
310
|
+
const handleTouchMove = (event) => {
|
|
311
|
+
const touch = event.touches[0];
|
|
312
|
+
if (touch)
|
|
313
|
+
updateGuide(touch.clientY);
|
|
314
|
+
};
|
|
315
|
+
resetGuide();
|
|
316
|
+
document.addEventListener("mousemove", handleMouseMove, true);
|
|
317
|
+
document.addEventListener("touchstart", handleTouchStart, true);
|
|
318
|
+
document.addEventListener("touchmove", handleTouchMove, true);
|
|
319
|
+
window.addEventListener("resize", resetGuide);
|
|
320
|
+
return () => {
|
|
321
|
+
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
322
|
+
document.removeEventListener("touchstart", handleTouchStart, true);
|
|
323
|
+
document.removeEventListener("touchmove", handleTouchMove, true);
|
|
324
|
+
window.removeEventListener("resize", resetGuide);
|
|
325
|
+
guide.remove();
|
|
326
|
+
};
|
|
327
|
+
}, [state.readingGuide]);
|
|
328
|
+
React.useEffect(() => {
|
|
329
|
+
if (!state.textMagnifier)
|
|
330
|
+
return;
|
|
331
|
+
const tooltip = document.createElement("div");
|
|
332
|
+
tooltip.className = "a11y-text-magnifier-tooltip";
|
|
333
|
+
tooltip.setAttribute("aria-hidden", "true");
|
|
334
|
+
document.body.appendChild(tooltip);
|
|
335
|
+
const hideTooltip = () => {
|
|
336
|
+
tooltip.removeAttribute("data-visible");
|
|
337
|
+
tooltip.textContent = "";
|
|
338
|
+
};
|
|
339
|
+
const showTooltip = (text) => {
|
|
340
|
+
tooltip.textContent = text;
|
|
341
|
+
tooltip.setAttribute("data-visible", "true");
|
|
342
|
+
};
|
|
343
|
+
const updateTooltipPosition = (clientX, clientY) => {
|
|
344
|
+
const tooltipWidth = tooltip.offsetWidth || 320;
|
|
345
|
+
const tooltipHeight = tooltip.offsetHeight || 56;
|
|
346
|
+
const left = Math.min(Math.max(12, clientX + 18), window.innerWidth - tooltipWidth - 12);
|
|
347
|
+
const top = clientY + tooltipHeight + 18 > window.innerHeight
|
|
348
|
+
? Math.max(12, clientY - tooltipHeight - 18)
|
|
349
|
+
: clientY + 18;
|
|
350
|
+
tooltip.style.left = `${left}px`;
|
|
351
|
+
tooltip.style.top = `${top}px`;
|
|
352
|
+
};
|
|
353
|
+
const handleMouseMove = (event) => {
|
|
354
|
+
const text = getMagnifierText(event.target);
|
|
355
|
+
if (!text) {
|
|
356
|
+
hideTooltip();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
showTooltip(text);
|
|
360
|
+
updateTooltipPosition(event.clientX, event.clientY);
|
|
361
|
+
};
|
|
362
|
+
let touchTimer = null;
|
|
363
|
+
let activeTouchId = null;
|
|
364
|
+
let activeText = "";
|
|
365
|
+
let pressPoint = null;
|
|
366
|
+
const clearTouchTimer = () => {
|
|
367
|
+
if (touchTimer !== null) {
|
|
368
|
+
window.clearTimeout(touchTimer);
|
|
369
|
+
touchTimer = null;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
const resetTouchState = () => {
|
|
373
|
+
clearTouchTimer();
|
|
374
|
+
activeTouchId = null;
|
|
375
|
+
activeText = "";
|
|
376
|
+
pressPoint = null;
|
|
377
|
+
hideTooltip();
|
|
378
|
+
};
|
|
379
|
+
const getTrackedTouch = (touches) => {
|
|
380
|
+
if (activeTouchId === null)
|
|
381
|
+
return null;
|
|
382
|
+
for (const touch of Array.from(touches)) {
|
|
383
|
+
if (touch.identifier === activeTouchId)
|
|
384
|
+
return touch;
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
};
|
|
388
|
+
const handleTouchStart = (event) => {
|
|
389
|
+
const touch = event.changedTouches[0];
|
|
390
|
+
if (!touch)
|
|
391
|
+
return;
|
|
392
|
+
const text = getMagnifierText(event.target);
|
|
393
|
+
if (!text) {
|
|
394
|
+
resetTouchState();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
clearTouchTimer();
|
|
398
|
+
activeTouchId = touch.identifier;
|
|
399
|
+
activeText = text;
|
|
400
|
+
pressPoint = { x: touch.clientX, y: touch.clientY };
|
|
401
|
+
touchTimer = window.setTimeout(() => {
|
|
402
|
+
showTooltip(activeText);
|
|
403
|
+
updateTooltipPosition(touch.clientX, touch.clientY);
|
|
404
|
+
touchTimer = null;
|
|
405
|
+
}, 450);
|
|
406
|
+
};
|
|
407
|
+
const handleTouchMove = (event) => {
|
|
408
|
+
const touch = getTrackedTouch(event.touches);
|
|
409
|
+
if (!touch)
|
|
410
|
+
return;
|
|
411
|
+
if (!tooltip.hasAttribute("data-visible")) {
|
|
412
|
+
if (pressPoint &&
|
|
413
|
+
(Math.abs(touch.clientX - pressPoint.x) > 10 ||
|
|
414
|
+
Math.abs(touch.clientY - pressPoint.y) > 10)) {
|
|
415
|
+
resetTouchState();
|
|
416
|
+
}
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
updateTooltipPosition(touch.clientX, touch.clientY);
|
|
420
|
+
};
|
|
421
|
+
const handleTouchEnd = () => resetTouchState();
|
|
422
|
+
const handleTouchCancel = () => resetTouchState();
|
|
423
|
+
const handlePointerLeave = () => hideTooltip();
|
|
424
|
+
document.addEventListener("mousemove", handleMouseMove, true);
|
|
425
|
+
document.addEventListener("touchstart", handleTouchStart, true);
|
|
426
|
+
document.addEventListener("touchmove", handleTouchMove, true);
|
|
427
|
+
document.addEventListener("touchend", handleTouchEnd, true);
|
|
428
|
+
document.addEventListener("touchcancel", handleTouchCancel, true);
|
|
429
|
+
document.addEventListener("scroll", hideTooltip, true);
|
|
430
|
+
window.addEventListener("blur", handlePointerLeave);
|
|
431
|
+
return () => {
|
|
432
|
+
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
433
|
+
document.removeEventListener("touchstart", handleTouchStart, true);
|
|
434
|
+
document.removeEventListener("touchmove", handleTouchMove, true);
|
|
435
|
+
document.removeEventListener("touchend", handleTouchEnd, true);
|
|
436
|
+
document.removeEventListener("touchcancel", handleTouchCancel, true);
|
|
437
|
+
document.removeEventListener("scroll", hideTooltip, true);
|
|
438
|
+
window.removeEventListener("blur", handlePointerLeave);
|
|
439
|
+
clearTouchTimer();
|
|
440
|
+
tooltip.remove();
|
|
441
|
+
};
|
|
442
|
+
}, [state.textMagnifier]);
|
|
60
443
|
React.useEffect(() => {
|
|
61
444
|
if (!state.voiceEnabled ||
|
|
62
445
|
!("webkitSpeechRecognition" in window || "SpeechRecognition" in window))
|
|
@@ -89,6 +472,15 @@ const AccessibilityProvider = ({ children, translations: customTranslations, })
|
|
|
89
472
|
toggleLightBackground();
|
|
90
473
|
if (transcript.includes("underline") || transcript.includes("guhit"))
|
|
91
474
|
toggleUnderlineLinks();
|
|
475
|
+
if (transcript.includes("highlight titles") ||
|
|
476
|
+
transcript.includes("title highlight"))
|
|
477
|
+
toggleHighlightTitles();
|
|
478
|
+
if (transcript.includes("pause animations") ||
|
|
479
|
+
transcript.includes("stop animations"))
|
|
480
|
+
togglePauseAnimations();
|
|
481
|
+
if (transcript.includes("reading guide") ||
|
|
482
|
+
transcript.includes("reading line"))
|
|
483
|
+
toggleReadingGuide();
|
|
92
484
|
if (transcript.includes("readable font") ||
|
|
93
485
|
transcript.includes("madaling"))
|
|
94
486
|
toggleReadableFont();
|
|
@@ -99,23 +491,108 @@ const AccessibilityProvider = ({ children, translations: customTranslations, })
|
|
|
99
491
|
const setLanguage = (lang) => setState((s) => (Object.assign(Object.assign({}, s), { language: lang })));
|
|
100
492
|
const increaseText = () => setState((s) => (Object.assign(Object.assign({}, s), { textSize: Math.min(s.textSize + 10, 200) })));
|
|
101
493
|
const decreaseText = () => setState((s) => (Object.assign(Object.assign({}, s), { textSize: Math.max(s.textSize - 10, 80) })));
|
|
494
|
+
const toggleTextMagnifier = () => setState((s) => (Object.assign(Object.assign({}, s), { textMagnifier: !s.textMagnifier })));
|
|
495
|
+
const togglePauseAnimations = () => setState((s) => (Object.assign(Object.assign({}, s), { pauseAnimations: !s.pauseAnimations })));
|
|
496
|
+
const toggleReadingGuide = () => setState((s) => (Object.assign(Object.assign({}, s), { readingGuide: !s.readingGuide })));
|
|
102
497
|
const toggleHighContrast = () => setState((s) => (Object.assign(Object.assign({}, s), { highContrast: !s.highContrast, negativeContrast: false })));
|
|
103
498
|
const toggleNegativeContrast = () => setState((s) => (Object.assign(Object.assign({}, s), { negativeContrast: !s.negativeContrast, highContrast: false })));
|
|
104
499
|
const toggleLightBackground = () => setState((s) => (Object.assign(Object.assign({}, s), { lightBackground: !s.lightBackground })));
|
|
105
500
|
const toggleUnderlineLinks = () => setState((s) => (Object.assign(Object.assign({}, s), { underlineLinks: !s.underlineLinks })));
|
|
501
|
+
const toggleHighlightTitles = () => setState((s) => (Object.assign(Object.assign({}, s), { highlightTitles: !s.highlightTitles })));
|
|
106
502
|
const toggleReadableFont = () => setState((s) => (Object.assign(Object.assign({}, s), { readableFont: !s.readableFont })));
|
|
107
503
|
const toggleVoice = () => setState((s) => (Object.assign(Object.assign({}, s), { voiceEnabled: !s.voiceEnabled })));
|
|
108
|
-
const
|
|
109
|
-
const
|
|
504
|
+
const toggleReadAloud = () => setState((s) => (Object.assign(Object.assign({}, s), { readAloud: !s.readAloud })));
|
|
505
|
+
const setColorBlindMode = (mode) => setState((s) => (Object.assign(Object.assign({}, s), { colorBlindMode: mode })));
|
|
506
|
+
const toggleFocusIndicator = () => setState((s) => (Object.assign(Object.assign({}, s), { focusIndicator: !s.focusIndicator })));
|
|
507
|
+
// Google Translate: auto-translate page content when language changes
|
|
508
|
+
React.useEffect(() => {
|
|
509
|
+
const GTRANSLATE_SCRIPT_ID = "a11y-google-translate-script";
|
|
510
|
+
const GTRANSLATE_CONTAINER_ID = "a11y-google-translate-element";
|
|
511
|
+
const loadGoogleTranslateScript = () => {
|
|
512
|
+
if (document.getElementById(GTRANSLATE_SCRIPT_ID))
|
|
513
|
+
return;
|
|
514
|
+
// Create hidden container for the widget
|
|
515
|
+
const container = document.createElement("div");
|
|
516
|
+
container.id = GTRANSLATE_CONTAINER_ID;
|
|
517
|
+
container.style.display = "none";
|
|
518
|
+
document.body.appendChild(container);
|
|
519
|
+
// Define the init callback
|
|
520
|
+
window.googleTranslateElementInit = () => {
|
|
521
|
+
new window.google.translate.TranslateElement({
|
|
522
|
+
pageLanguage: "en",
|
|
523
|
+
autoDisplay: false,
|
|
524
|
+
}, GTRANSLATE_CONTAINER_ID);
|
|
525
|
+
};
|
|
526
|
+
const script = document.createElement("script");
|
|
527
|
+
script.id = GTRANSLATE_SCRIPT_ID;
|
|
528
|
+
script.src =
|
|
529
|
+
"//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
|
|
530
|
+
script.async = true;
|
|
531
|
+
document.body.appendChild(script);
|
|
532
|
+
};
|
|
533
|
+
const triggerTranslation = (langCode) => {
|
|
534
|
+
setGoogleTranslateCookie(langCode);
|
|
535
|
+
const select = document.querySelector(".goog-te-combo");
|
|
536
|
+
if (select) {
|
|
537
|
+
select.value = langCode;
|
|
538
|
+
dispatchNativeChangeEvent(select);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
const resetTranslation = () => {
|
|
542
|
+
const select = document.querySelector(".goog-te-combo");
|
|
543
|
+
if (select) {
|
|
544
|
+
select.value = GOOGLE_TRANSLATE_SOURCE_LANGUAGE;
|
|
545
|
+
dispatchNativeChangeEvent(select);
|
|
546
|
+
}
|
|
547
|
+
clearGoogleTranslateCookie();
|
|
548
|
+
};
|
|
549
|
+
const langMap = {
|
|
550
|
+
en: GOOGLE_TRANSLATE_SOURCE_LANGUAGE,
|
|
551
|
+
tl: "tl",
|
|
552
|
+
ceb: "ceb",
|
|
553
|
+
ja: "ja",
|
|
554
|
+
es: "es",
|
|
555
|
+
fr: "fr",
|
|
556
|
+
de: "de",
|
|
557
|
+
zh: "zh-CN",
|
|
558
|
+
ar: "ar",
|
|
559
|
+
};
|
|
560
|
+
const googleLang = langMap[state.language] || state.language;
|
|
561
|
+
if (googleLang === GOOGLE_TRANSLATE_SOURCE_LANGUAGE) {
|
|
562
|
+
resetTranslation();
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
loadGoogleTranslateScript();
|
|
566
|
+
setGoogleTranslateCookie(googleLang);
|
|
567
|
+
// Wait for Google Translate widget to be ready, then trigger
|
|
568
|
+
const interval = window.setInterval(() => {
|
|
569
|
+
const select = document.querySelector(".goog-te-combo");
|
|
570
|
+
if (select) {
|
|
571
|
+
window.clearInterval(interval);
|
|
572
|
+
triggerTranslation(googleLang);
|
|
573
|
+
}
|
|
574
|
+
}, 300);
|
|
575
|
+
return () => window.clearInterval(interval);
|
|
576
|
+
}, [state.language]);
|
|
577
|
+
const translate = (key) => (manualTranslationsForLanguage === null || manualTranslationsForLanguage === void 0 ? void 0 : manualTranslationsForLanguage[key]) || defaultUiTranslations[key];
|
|
578
|
+
const t = (key) => { var _a, _b; return ((_a = allTranslations[state.language]) === null || _a === void 0 ? void 0 : _a[key]) || ((_b = allTranslations.en) === null || _b === void 0 ? void 0 : _b[key]) || key; };
|
|
110
579
|
return (React.createElement(AccessibilityContext.Provider, { value: Object.assign(Object.assign({}, state), { setLanguage,
|
|
111
580
|
increaseText,
|
|
112
581
|
decreaseText,
|
|
582
|
+
toggleTextMagnifier,
|
|
583
|
+
togglePauseAnimations,
|
|
584
|
+
toggleReadingGuide,
|
|
113
585
|
toggleHighContrast,
|
|
114
586
|
toggleNegativeContrast,
|
|
115
587
|
toggleLightBackground,
|
|
116
588
|
toggleUnderlineLinks,
|
|
589
|
+
toggleHighlightTitles,
|
|
117
590
|
toggleReadableFont,
|
|
118
591
|
toggleVoice,
|
|
592
|
+
toggleReadAloud,
|
|
593
|
+
setColorBlindMode,
|
|
594
|
+
toggleFocusIndicator,
|
|
595
|
+
hasManualTranslations,
|
|
119
596
|
translate,
|
|
120
597
|
t }) }, children));
|
|
121
598
|
};
|
|
@@ -128,8 +605,8 @@ const useAccessibility = () => {
|
|
|
128
605
|
|
|
129
606
|
const cn$1 = (...parts) => parts.filter(Boolean).join(" ");
|
|
130
607
|
const AccessibilityToolbar = ({ className, style, classes, }) => {
|
|
131
|
-
const { language, setLanguage, increaseText, decreaseText, toggleHighContrast, toggleNegativeContrast, toggleLightBackground, toggleUnderlineLinks, toggleReadableFont, toggleVoice, translate, highContrast, negativeContrast, lightBackground, underlineLinks, readableFont, voiceEnabled, } = useAccessibility();
|
|
132
|
-
return (React.createElement("div", { className: cn$1("accessibility-toolbar", classes === null || classes === void 0 ? void 0 : classes.root, className), style: style },
|
|
608
|
+
const { language, setLanguage, increaseText, decreaseText, toggleTextMagnifier, togglePauseAnimations, toggleReadingGuide, toggleHighContrast, toggleNegativeContrast, toggleLightBackground, toggleUnderlineLinks, toggleHighlightTitles, toggleReadableFont, toggleVoice, toggleReadAloud, setColorBlindMode, toggleFocusIndicator, translate, textMagnifier, pauseAnimations, readingGuide, highContrast, negativeContrast, lightBackground, underlineLinks, highlightTitles, readableFont, voiceEnabled, readAloud, colorBlindMode, focusIndicator, } = useAccessibility();
|
|
609
|
+
return (React.createElement("div", { className: cn$1("accessibility-toolbar notranslate", classes === null || classes === void 0 ? void 0 : classes.root, className), style: style, translate: "no" },
|
|
133
610
|
React.createElement("select", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.select), value: language, onChange: (e) => setLanguage(e.target.value) },
|
|
134
611
|
React.createElement("option", { value: "en" }, "English"),
|
|
135
612
|
React.createElement("option", { value: "tl" }, "Tagalog"),
|
|
@@ -140,50 +617,88 @@ const AccessibilityToolbar = ({ className, style, classes, }) => {
|
|
|
140
617
|
React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button), onClick: decreaseText },
|
|
141
618
|
"- ",
|
|
142
619
|
translate("decreaseText")),
|
|
620
|
+
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")),
|
|
143
621
|
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")),
|
|
144
622
|
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")),
|
|
145
623
|
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")),
|
|
146
624
|
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")),
|
|
625
|
+
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")),
|
|
147
626
|
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")),
|
|
627
|
+
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")),
|
|
628
|
+
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")),
|
|
148
629
|
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 },
|
|
149
630
|
"\uD83C\uDFA4 ",
|
|
150
|
-
translate("voiceCommand"))
|
|
631
|
+
translate("voiceCommand")),
|
|
632
|
+
React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, readAloud && "active", readAloud && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": readAloud, onClick: toggleReadAloud },
|
|
633
|
+
"\uD83D\uDD0A ",
|
|
634
|
+
translate("readAloud")),
|
|
635
|
+
React.createElement("button", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.button, focusIndicator && "active", focusIndicator && (classes === null || classes === void 0 ? void 0 : classes.activeButton)), "data-active": focusIndicator, onClick: toggleFocusIndicator }, translate("focusIndicator")),
|
|
636
|
+
React.createElement("select", { className: cn$1(classes === null || classes === void 0 ? void 0 : classes.select), value: colorBlindMode, onChange: (e) => setColorBlindMode(e.target.value), "aria-label": translate("colorBlindMode") },
|
|
637
|
+
React.createElement("option", { value: "none" }, translate("colorBlindMode")),
|
|
638
|
+
React.createElement("option", { value: "protanopia" }, "Protanopia (Red)"),
|
|
639
|
+
React.createElement("option", { value: "deuteranopia" }, "Deuteranopia (Green)"),
|
|
640
|
+
React.createElement("option", { value: "tritanopia" }, "Tritanopia (Blue)"))));
|
|
151
641
|
};
|
|
152
642
|
|
|
153
643
|
const cn = (...parts) => parts.filter(Boolean).join(" ");
|
|
154
644
|
const AccessibilityDropdown = ({ className, style, classes, triggerLabel = "♿ Accessibility", renderTrigger, }) => {
|
|
155
645
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
156
|
-
const { language, setLanguage, increaseText, decreaseText, toggleHighContrast, toggleNegativeContrast, toggleLightBackground, toggleUnderlineLinks, toggleReadableFont, toggleVoice, translate, highContrast, negativeContrast, lightBackground, underlineLinks, readableFont, voiceEnabled, } = useAccessibility();
|
|
646
|
+
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();
|
|
157
647
|
const toggle = () => setIsOpen(!isOpen);
|
|
158
|
-
|
|
648
|
+
const closePanel = () => setIsOpen(false);
|
|
649
|
+
const textScaleDelta = textSize - 100;
|
|
650
|
+
const textScaleLabel = textScaleDelta === 0
|
|
651
|
+
? "Default"
|
|
652
|
+
: `${textScaleDelta > 0 ? "+" : ""}${textScaleDelta}%`;
|
|
653
|
+
return (React.createElement("div", { className: cn("a11y-root", classes === null || classes === void 0 ? void 0 : classes.root, className), style: style },
|
|
159
654
|
renderTrigger ? (renderTrigger({
|
|
160
655
|
isOpen,
|
|
161
656
|
toggle,
|
|
162
|
-
className: cn("
|
|
163
|
-
})) : (React.createElement("button", { className: cn("
|
|
164
|
-
isOpen && (React.createElement("div", { className: cn("
|
|
165
|
-
React.createElement("div", { className: cn("
|
|
166
|
-
React.createElement("
|
|
167
|
-
|
|
657
|
+
className: cn("a11y-trigger", classes === null || classes === void 0 ? void 0 : classes.trigger),
|
|
658
|
+
})) : (React.createElement("button", { className: cn("a11y-trigger", classes === null || classes === void 0 ? void 0 : classes.trigger), onClick: toggle }, triggerLabel)),
|
|
659
|
+
isOpen && (React.createElement("div", { className: cn("a11y-panel", classes === null || classes === void 0 ? void 0 : classes.panel) },
|
|
660
|
+
React.createElement("div", { className: cn("a11y-panel-header", classes === null || classes === void 0 ? void 0 : classes.panelHeader) },
|
|
661
|
+
React.createElement("div", { className: "a11y-panel-heading" },
|
|
662
|
+
React.createElement("span", { className: "a11y-panel-eyebrow" }, "NGP"),
|
|
663
|
+
React.createElement("label", { className: cn("a11y-panel-title", classes === null || classes === void 0 ? void 0 : classes.title) }, "Accessibility Options")),
|
|
664
|
+
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")),
|
|
665
|
+
React.createElement("div", { className: cn("a11y-language", classes === null || classes === void 0 ? void 0 : classes.section) },
|
|
666
|
+
React.createElement("label", { htmlFor: "a11y-language-select", className: cn("a11y-language-label", classes === null || classes === void 0 ? void 0 : classes.title) }, translate("language")),
|
|
667
|
+
React.createElement("select", { id: "a11y-language-select", value: language, onChange: (e) => setLanguage(e.target.value) },
|
|
168
668
|
React.createElement("option", { value: "en" }, "English"),
|
|
169
669
|
React.createElement("option", { value: "tl" }, "Tagalog"),
|
|
170
|
-
React.createElement("option", { value: "ceb" }, "Cebuano")
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
"
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
React.createElement("
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
translate("
|
|
670
|
+
React.createElement("option", { value: "ceb" }, "Cebuano"),
|
|
671
|
+
React.createElement("option", { value: "ja" }, "Japanese"),
|
|
672
|
+
React.createElement("option", { value: "es" }, "Spanish"),
|
|
673
|
+
React.createElement("option", { value: "fr" }, "French"),
|
|
674
|
+
React.createElement("option", { value: "de" }, "German"),
|
|
675
|
+
React.createElement("option", { value: "zh" }, "Chinese"),
|
|
676
|
+
React.createElement("option", { value: "ar" }, "Arabic"))),
|
|
677
|
+
React.createElement("section", { className: cn("a11y-section", classes === null || classes === void 0 ? void 0 : classes.section) },
|
|
678
|
+
React.createElement("h3", { className: cn("a11y-section-title", classes === null || classes === void 0 ? void 0 : classes.title) }, "Content Adjustments"),
|
|
679
|
+
React.createElement("div", { className: "a11y-card" },
|
|
680
|
+
React.createElement("span", { className: cn("a11y-card-title", classes === null || classes === void 0 ? void 0 : classes.title) }, "Content Scaling"),
|
|
681
|
+
React.createElement("div", { className: "a11y-stepper" },
|
|
682
|
+
React.createElement("button", { onClick: decreaseText }, "\u2212"),
|
|
683
|
+
React.createElement("span", { className: "a11y-stepper-value" }, textScaleLabel),
|
|
684
|
+
React.createElement("button", { onClick: increaseText }, "+"))),
|
|
685
|
+
React.createElement("div", { className: cn("a11y-grid", classes === null || classes === void 0 ? void 0 : classes.section) },
|
|
686
|
+
React.createElement("button", { className: cn("a11y-card", textMagnifier && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleTextMagnifier }, translate("textMagnifier")),
|
|
687
|
+
React.createElement("button", { className: cn("a11y-card", readableFont && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleReadableFont }, "Readable Font"),
|
|
688
|
+
React.createElement("button", { className: cn("a11y-card", underlineLinks && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleUnderlineLinks }, "Highlight Links"),
|
|
689
|
+
React.createElement("button", { className: cn("a11y-card", highlightTitles && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleHighlightTitles }, "Highlight Titles"))),
|
|
690
|
+
React.createElement("section", { className: cn("a11y-section", classes === null || classes === void 0 ? void 0 : classes.section) },
|
|
691
|
+
React.createElement("h3", { className: cn("a11y-section-title", classes === null || classes === void 0 ? void 0 : classes.title) }, "Color Adjustments"),
|
|
692
|
+
React.createElement("div", { className: cn("a11y-grid", classes === null || classes === void 0 ? void 0 : classes.section) },
|
|
693
|
+
React.createElement("button", { className: cn("a11y-card", highContrast && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleHighContrast }, translate("highContrast")),
|
|
694
|
+
React.createElement("button", { className: cn("a11y-card", negativeContrast && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleNegativeContrast }, translate("negativeContrast")),
|
|
695
|
+
React.createElement("button", { className: cn("a11y-card", lightBackground && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleLightBackground }, translate("lightBackground")))),
|
|
696
|
+
React.createElement("section", { className: cn("a11y-section", classes === null || classes === void 0 ? void 0 : classes.section) },
|
|
697
|
+
React.createElement("h3", { className: cn("a11y-section-title", classes === null || classes === void 0 ? void 0 : classes.title) }, "Accessibility Tools"),
|
|
698
|
+
React.createElement("div", { className: cn("a11y-grid", classes === null || classes === void 0 ? void 0 : classes.section) },
|
|
699
|
+
React.createElement("button", { className: cn("a11y-card", pauseAnimations && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: togglePauseAnimations }, translate("pauseAnimations")),
|
|
700
|
+
React.createElement("button", { className: cn("a11y-card", readingGuide && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleReadingGuide }, translate("readingGuide")),
|
|
701
|
+
React.createElement("button", { className: cn("a11y-card", voiceEnabled && "active", classes === null || classes === void 0 ? void 0 : classes.button), onClick: toggleVoice }, translate("voiceCommand"))))))));
|
|
187
702
|
};
|
|
188
703
|
|
|
189
704
|
const T = ({ k, children }) => {
|