@oksigenia/access-panel 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -7
- package/dist/index.d.ts +15 -2
- package/dist/index.js +133 -18
- package/dist/index.js.map +1 -1
- package/dist/web-component.js +140 -18
- package/dist/web-component.js.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
<img src="https://raw.githubusercontent.com/OksigeniaSL/oksigenia-web-libs/main/packages/access-panel/assets/icon.png" alt="" width="80" align="right" />
|
|
8
8
|
|
|
9
|
-
Accessibility panel as a web component. Drop in one tag, get
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
Accessibility panel as a web component. Drop in one tag, get 17 controls and
|
|
10
|
+
4 profile presets.
|
|
11
|
+
|
|
12
|
+
- **17 atomic controls**: text size (4 levels), line height (3), text alignment
|
|
13
|
+
(3), letter spacing (3), readable font toggle, dyslexia font toggle, high
|
|
14
|
+
contrast, grayscale overlay, hide images, highlight links, colorblind filters
|
|
15
|
+
(3 types), reading guide, reading mask, big cursor, big targets (44×44 hit
|
|
16
|
+
area, WCAG 2.5.5), pause animations, focus outlines.
|
|
17
|
+
- **4 profile presets** (additive — pressing several unions their flags):
|
|
18
|
+
low vision, dyslexia, motor, no distractions.
|
|
15
19
|
- **8 locales**: es, en, gn (Guaraní), fr, it, de, nl, sv.
|
|
16
20
|
- **Privacy-first**: zero dependencies, no analytics, no remote calls. User
|
|
17
21
|
preferences persist in `localStorage` only.
|
|
@@ -29,7 +33,7 @@ re-packaged as a framework-agnostic web library.
|
|
|
29
33
|
## Screenshot
|
|
30
34
|
|
|
31
35
|
<p align="center">
|
|
32
|
-
<img src="https://raw.githubusercontent.com/OksigeniaSL/oksigenia-web-libs/main/packages/access-panel/assets/screenshot.png" alt="Open accessibility panel showing Text, Visual and Orientation sections
|
|
36
|
+
<img src="https://raw.githubusercontent.com/OksigeniaSL/oksigenia-web-libs/main/packages/access-panel/assets/screenshot.png" alt="Open accessibility panel showing profile presets and Text, Visual and Orientation sections" width="320" />
|
|
33
37
|
</p>
|
|
34
38
|
|
|
35
39
|
## Install
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ interface Translation {
|
|
|
15
15
|
links: string;
|
|
16
16
|
ori: string;
|
|
17
17
|
guide: string;
|
|
18
|
+
mask: string;
|
|
19
|
+
targets: string;
|
|
18
20
|
cursor: string;
|
|
19
21
|
pause: string;
|
|
20
22
|
reset: string;
|
|
@@ -22,6 +24,13 @@ interface Translation {
|
|
|
22
24
|
ls: string;
|
|
23
25
|
cb: string;
|
|
24
26
|
focus: string;
|
|
27
|
+
/** Section title for the preset row. */
|
|
28
|
+
presets: string;
|
|
29
|
+
/** Preset labels. */
|
|
30
|
+
pLow: string;
|
|
31
|
+
pDys: string;
|
|
32
|
+
pMot: string;
|
|
33
|
+
pCalm: string;
|
|
25
34
|
}
|
|
26
35
|
declare function getTranslation(locale: string): Translation;
|
|
27
36
|
declare function supportedLocales(): readonly LocaleCode[];
|
|
@@ -68,6 +77,10 @@ interface PanelState {
|
|
|
68
77
|
grayOverlay: boolean;
|
|
69
78
|
/** Guía horizontal de lectura. */
|
|
70
79
|
readingGuide: boolean;
|
|
80
|
+
/** Máscara de lectura: oscurece todo menos una banda alrededor del cursor. */
|
|
81
|
+
readingMask: boolean;
|
|
82
|
+
/** Aumenta el hit-area de interactivos a 44×44 mínimo (WCAG 2.5.5/2.5.8). */
|
|
83
|
+
bigTargets: boolean;
|
|
71
84
|
}
|
|
72
85
|
declare const DEFAULT_STATE: Readonly<PanelState>;
|
|
73
86
|
declare function loadState(key: string): PanelState;
|
|
@@ -85,7 +98,7 @@ interface BehaviorOptions {
|
|
|
85
98
|
*/
|
|
86
99
|
declare function bindPanelBehavior(root: ShadowRoot, opts?: BehaviorOptions): () => void;
|
|
87
100
|
|
|
88
|
-
declare const PANEL_CSS = "\n:host {\n --oks-btn-size: 55px;\n --oks-bg: #000;\n --oks-icon: #fff;\n --oks-h-bg: #fff;\n --oks-h-icon: #000;\n --oks-z: 9999999;\n}\n.oks-access-wrapper {\n position: fixed;\n z-index: var(--oks-z);\n line-height: 1;\n}\n.oks-access-btn {\n width: var(--oks-btn-size);\n height: var(--oks-btn-size);\n border-radius: 50%;\n background: var(--oks-bg);\n color: var(--oks-icon);\n border: 2px solid #fff;\n box-shadow: 0 4px 15px rgba(0,0,0,0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: 0.2s;\n padding: 0;\n}\n.oks-access-btn:hover {\n background: var(--oks-h-bg);\n color: var(--oks-h-icon);\n transform: scale(1.1);\n}\n.oks-access-btn svg {\n fill: currentColor;\n display: block;\n margin: 0 auto;\n width: 60%;\n height: 60%;\n}\n.oks-active-badge {\n position: absolute;\n top: -2px;\n right: -2px;\n width: 20px;\n height: 20px;\n background: #25D366;\n border-radius: 50%;\n border: 2px solid #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n opacity: 0;\n pointer-events: none;\n}\n.oks-active-badge svg { width: 12px; height: 12px; }\n.oks-access-wrapper.has-active .oks-active-badge { opacity: 1; }\n\n.oks-access-panel {\n position: fixed;\n width: 340px;\n max-height: 90vh;\n background: #fff;\n border-radius: 20px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n z-index: var(--oks-z);\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n transition: 0.2s;\n border: 1px solid rgba(0,0,0,0.1);\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n color: #333;\n}\n.oks-access-panel.is-open { opacity: 1; pointer-events: all; }\n.oks-access-header {\n padding: 15px 20px;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.oks-access-header h3 { margin: 0; font-size: 18px; color: #000; }\n.oks-access-close {\n background: #f0f0f0;\n color: #333;\n border: 1px solid #ddd;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: 0.2s;\n padding: 0;\n}\n.oks-access-close:hover { background: #e0e0e0; border-color: #ccc; }\n.oks-access-close svg { width: 24px; height: 24px; stroke-width: 2.5px; }\n.oks-access-content { padding: 0 20px 20px; overflow-y: auto; }\n.oks-access-title {\n margin: 10px 0 5px;\n font-size: 11px;\n font-weight: 800;\n text-transform: uppercase;\n color: #888;\n}\n.oks-access-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }\n.oks-access-opt {\n background: #f9f9f9;\n border: 2px solid #eee;\n border-radius: 10px;\n padding: 10px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n min-width: 0;\n min-height: 70px;\n color: #333;\n transition: 0.2s;\n font: inherit;\n}\n.oks-access-opt.full-width { grid-column: span 2; }\n.oks-access-opt.is-active {\n border-color: #000;\n background: #fff;\n box-shadow: 0 0 0 1px #000;\n}\n.oks-access-opt:hover { background: #000; color: #fff; border-color: #000; }\n.oks-icon { font-size: 28px; margin-bottom: 3px; display: block; line-height: 1; }\n.oks-icon svg { width: 24px; height: 24px; fill: currentColor; }\n.oks-label {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n text-align: center;\n line-height: 1.2;\n overflow-wrap: anywhere;\n word-break: break-word;\n}\n.oks-levels { display: flex; gap: 3px; height: 5px; width: 50%; margin-top: 5px; }\n.oks-levels span { flex: 1; background: #ddd; border-radius: 3px; }\n.oks-access-opt[data-level=\"1\"] .oks-levels span:nth-child(1),\n.oks-access-opt[data-level=\"2\"] .oks-levels span:nth-child(-n+2),\n.oks-access-opt[data-level=\"3\"] .oks-levels span:nth-child(-n+3),\n.oks-access-opt[data-level=\"4\"] .oks-levels span:nth-child(-n+4) { background: #000; }\n.oks-access-opt:hover .oks-levels span { background: #555; }\n.oks-access-footer {\n padding: 12px 20px;\n border-top: 1px solid #eee;\n text-align: center;\n}\n.oks-access-reset {\n width: 100%;\n padding: 8px;\n border: 2px solid #000;\n color: #000;\n background: transparent;\n font-weight: 700;\n cursor: pointer;\n border-radius: 6px;\n font-size: 12px;\n}\n.oks-access-reset:hover { background: #000; color: #fff; }\n.oks-access-branding { margin-top: 12px; font-size: 12px; color: #000; font-weight: 700; }\n.oks-access-branding a { color: #000; text-decoration: none; border-bottom: 1px dotted #000; }\n\n@media (max-width: 768px) {\n .oks-access-panel {\n width: 100%; height: 100%; max-height: 100%;\n top: 0; left: 0; right: 0; bottom: 0;\n border-radius: 0;\n }\n .oks-access-opt { min-height: 72px; padding: 10px 8px; }\n .oks-icon svg { width: 26px; height: 26px; }\n .oks-label { font-size: 12px; line-height: 1.25; }\n .oks-access-grid { gap: 8px; }\n .oks-access-content { padding: 0 14px 20px; }\n .oks-access-title { font-size: 11px; margin: 10px 0 4px; }\n /* Cursor grande no aplica en t\u00E1ctil: oculto y dejo el \u00FAltimo bot\u00F3n\n de la secci\u00F3n ocupando 2 columnas para no romper la grilla par. */\n .oks-access-opt[data-class=\"oks-big-cursor\"] { display: none; }\n .oks-access-opt[data-class=\"oks-a11y-focus\"] { grid-column: span 2; }\n .oks-access-reset { padding: 14px; font-size: 14px; }\n}\n";
|
|
89
|
-
declare const EFFECT_CSS = "\nhtml.oks-colorblind-1 { filter: url('#oks-filter-protanopia'); }\nhtml.oks-colorblind-2 { filter: url('#oks-filter-deuteranopia'); }\nhtml.oks-colorblind-3 { filter: url('#oks-filter-tritanopia'); }\n\n/* Text-size levels.\n Applied to <html> via :has(), not to <body>. rem is anchored to the root\n element, so a site whose CSS sizes things in rem (most modern Astro / Tailwind\n builds) needs the root font-size to change for the scale to take effect.\n A previous version applied this to body with %, which only moved descendants\n that inherited font-size from body \u2014 anything sized in rem stayed locked to\n the 16px default of <html>. An even earlier version used the universal\n selector with em and compounded the factor at every nesting level.\n :has(body.oks-zoom-N) is the right anchor: one change at the root, rem\n descendants scale exactly once. Hard-coded px is intentionally left alone;\n browser zoom covers that case. */\nhtml:has(body.oks-zoom-1) { font-size: 110% !important; }\nhtml:has(body.oks-zoom-2) { font-size: 120% !important; }\nhtml:has(body.oks-zoom-3) { font-size: 135% !important; }\nhtml:has(body.oks-zoom-4) { font-size: 150% !important; }\n\nbody.oks-lh-1 * { line-height: 1.6 !important; }\nbody.oks-lh-2 * { line-height: 1.9 !important; }\nbody.oks-lh-3 * { line-height: 2.2 !important; }\n\nbody.oks-a11y-font { font-family: Arial, sans-serif !important; }\n\nbody.oks-dyslexia * {\n font-family: 'Comic Sans MS', 'Verdana', sans-serif !important;\n letter-spacing: 0.05em !important;\n word-spacing: 0.1em !important;\n line-height: 1.6 !important;\n}\n\nbody.oks-a11y-hide img { opacity: 0 !important; visibility: hidden !important; }\nbody.oks-a11y-links a { text-decoration: underline !important; background: #ff0 !important; color: #000 !important; }\n\nbody.oks-align-1 * { text-align: left !important; }\nbody.oks-align-2 * { text-align: center !important; }\nbody.oks-align-3 * { text-align: right !important; }\n\nbody.oks-a11y-pause * { animation: none !important; transition: none !important; }\n\nbody.oks-ls-1 * { letter-spacing: 0.05em !important; }\nbody.oks-ls-2 * { letter-spacing: 0.10em !important; }\nbody.oks-ls-3 * { letter-spacing: 0.16em !important; }\n\nbody.oks-a11y-focus a:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-focus button:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-focus input,\nbody.oks-a11y-focus select,\nbody.oks-a11y-focus textarea {\n outline: 2px dashed rgba(0, 95, 204, 0.45) !important;\n outline-offset: 2px !important;\n}\nbody.oks-a11y-focus *:focus-visible {\n outline: 3px solid #005fcc !important;\n outline-offset: 3px !important;\n box-shadow: 0 0 0 6px rgba(0, 95, 204, 0.25) !important;\n}\n\nbody.oks-a11y-contrast.oks-a11y-focus *:focus,\nbody.oks-a11y-contrast.oks-a11y-focus *:focus-visible {\n outline-color: #0ff !important;\n box-shadow: 0 0 0 6px rgba(0, 255, 255, 0.3) !important;\n}\n\n@media (pointer: fine) {\n body.oks-big-cursor, body.oks-big-cursor a, body.oks-big-cursor button {\n cursor: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 24 24'%3E%3Cpath d='M4 2L4 18L8 14L11 21L14 19.5L11 13L15.5 13Z' stroke='white' stroke-width='4' stroke-linejoin='round' fill='white'/%3E%3Cpath d='M4 2L4 18L8 14L11 21L14 19.5L11 13L15.5 13Z' fill='black'/%3E%3C/svg%3E\") 8 4, auto !important;\n }\n}\n\nbody.oks-a11y-contrast,\nbody.oks-a11y-contrast *:not(oksigenia-access-panel):not(oksigenia-access-panel *) {\n background-color: #000 !important;\n color: #ff0 !important;\n border-color: #ff0 !important;\n text-shadow: none !important;\n box-shadow: none !important;\n}\nbody.oks-a11y-contrast img { filter: grayscale(100%) contrast(120%) !important; }\nbody.oks-a11y-contrast a:not(oksigenia-access-panel *) { color: #0ff !important; text-decoration: underline !important; }\n\n/* High-contrast applies background:#000 to every descendant of body to flip\n the page to inverted colours. That selector also catches our own overlays\n (.oks-reading-guide, .oks-overlay-effect), which would then paint a solid\n black band on top of the text and defeat their purpose. Restore the\n overlay-specific values here so they keep working in high-contrast mode. */\nbody.oks-a11y-contrast .oks-reading-guide {\n background-color: rgba(255, 255, 0, 0.25) !important;\n border-top-color: #ff0 !important;\n border-bottom-color: #ff0 !important;\n}\nbody.oks-a11y-contrast .oks-overlay-effect {\n background-color: transparent !important;\n}\n\n.oks-overlay-effect {\n position: fixed; top: 0; left: 0;\n width: 100%; height: 100%;\n pointer-events: none;\n z-index: 999990;\n display: none;\n backdrop-filter: grayscale(100%);\n}\n.oks-overlay-effect.is-active { display: block; }\n\n.oks-reading-guide {\n position: fixed; left: 0;\n width: 100%; height: 50px;\n background: rgba(255, 255, 0, 0.2);\n border-top: 3px solid red;\n border-bottom: 3px solid red;\n pointer-events: none;\n z-index: 2147483647;\n display: none;\n transform: translateY(-50%);\n}\nbody.oks-a11y-guide .oks-reading-guide { display: block; }\n";
|
|
101
|
+
declare const PANEL_CSS = "\n:host {\n --oks-btn-size: 55px;\n --oks-bg: #000;\n --oks-icon: #fff;\n --oks-h-bg: #fff;\n --oks-h-icon: #000;\n --oks-z: 9999999;\n}\n.oks-access-wrapper {\n position: fixed;\n z-index: var(--oks-z);\n line-height: 1;\n}\n.oks-access-btn {\n width: var(--oks-btn-size);\n height: var(--oks-btn-size);\n border-radius: 50%;\n background: var(--oks-bg);\n color: var(--oks-icon);\n border: 2px solid #fff;\n box-shadow: 0 4px 15px rgba(0,0,0,0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: 0.2s;\n padding: 0;\n}\n.oks-access-btn:hover {\n background: var(--oks-h-bg);\n color: var(--oks-h-icon);\n transform: scale(1.1);\n}\n.oks-access-btn svg {\n fill: currentColor;\n display: block;\n margin: 0 auto;\n width: 60%;\n height: 60%;\n}\n.oks-active-badge {\n position: absolute;\n top: -2px;\n right: -2px;\n width: 20px;\n height: 20px;\n background: #25D366;\n border-radius: 50%;\n border: 2px solid #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n opacity: 0;\n pointer-events: none;\n}\n.oks-active-badge svg { width: 12px; height: 12px; }\n.oks-access-wrapper.has-active .oks-active-badge { opacity: 1; }\n\n.oks-access-panel {\n position: fixed;\n width: 340px;\n max-height: 90vh;\n background: #fff;\n border-radius: 20px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n z-index: var(--oks-z);\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n transition: 0.2s;\n border: 1px solid rgba(0,0,0,0.1);\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n color: #333;\n}\n.oks-access-panel.is-open { opacity: 1; pointer-events: all; }\n.oks-access-header {\n padding: 15px 20px;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.oks-access-header h3 { margin: 0; font-size: 18px; color: #000; }\n.oks-access-close {\n background: #f0f0f0;\n color: #333;\n border: 1px solid #ddd;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: 0.2s;\n padding: 0;\n}\n.oks-access-close:hover { background: #e0e0e0; border-color: #ccc; }\n.oks-access-close svg { width: 24px; height: 24px; stroke-width: 2.5px; }\n.oks-access-content { padding: 0 20px 20px; overflow-y: auto; }\n.oks-access-title {\n margin: 10px 0 5px;\n font-size: 11px;\n font-weight: 800;\n text-transform: uppercase;\n color: #888;\n}\n.oks-access-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }\n.oks-access-presets { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }\n.oks-preset {\n background: #f0f4f8;\n border: 2px solid transparent;\n border-radius: 8px;\n padding: 8px 4px;\n display: flex;\n flex-direction: column;\n align-items: center;\n cursor: pointer;\n font: inherit;\n color: #333;\n min-width: 0;\n transition: 0.15s;\n}\n.oks-preset:hover { background: #000; color: #fff; }\n.oks-preset:focus-visible { outline: 2px solid #000; outline-offset: 2px; }\n/* Click feedback: a 250 ms flip + slight squeeze. Pure transient \u2014 the\n button does not carry persistent active state because a preset is a\n trigger, not a mode. */\n.oks-preset.is-flashing {\n background: #000;\n color: #fff;\n transform: scale(0.96);\n}\n.oks-preset .oks-icon { font-size: 22px; margin-bottom: 4px; }\n.oks-preset .oks-icon svg { width: 20px; height: 20px; }\n.oks-preset .oks-label {\n font-size: 10px; font-weight: 700; text-transform: uppercase;\n text-align: center; line-height: 1.15;\n overflow-wrap: anywhere; word-break: break-word;\n /* Reserve room for 2 lines so 1-line labels (DISLEXIA, MOTOR) and\n 2-line labels (BAJA VISI\u00D3N, SIN DISTRAC.) end up the same height,\n centred. Without this the row looks ragged. */\n min-height: 2.3em;\n display: flex; align-items: center; justify-content: center;\n}\n.oks-access-opt {\n background: #f9f9f9;\n border: 2px solid #eee;\n border-radius: 10px;\n padding: 10px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n min-width: 0;\n min-height: 70px;\n color: #333;\n transition: 0.2s;\n font: inherit;\n}\n.oks-access-opt.full-width { grid-column: span 2; }\n.oks-access-opt.is-active {\n border-color: #000;\n background: #fff;\n box-shadow: 0 0 0 1px #000;\n}\n.oks-access-opt:hover { background: #000; color: #fff; border-color: #000; }\n.oks-icon { font-size: 28px; margin-bottom: 3px; display: block; line-height: 1; }\n.oks-icon svg { width: 24px; height: 24px; fill: currentColor; }\n.oks-label {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n text-align: center;\n line-height: 1.2;\n overflow-wrap: anywhere;\n word-break: break-word;\n}\n.oks-levels { display: flex; gap: 3px; height: 5px; width: 50%; margin-top: 5px; }\n.oks-levels span { flex: 1; background: #ddd; border-radius: 3px; }\n.oks-access-opt[data-level=\"1\"] .oks-levels span:nth-child(1),\n.oks-access-opt[data-level=\"2\"] .oks-levels span:nth-child(-n+2),\n.oks-access-opt[data-level=\"3\"] .oks-levels span:nth-child(-n+3),\n.oks-access-opt[data-level=\"4\"] .oks-levels span:nth-child(-n+4) { background: #000; }\n.oks-access-opt:hover .oks-levels span { background: #555; }\n.oks-access-footer {\n padding: 12px 20px;\n border-top: 1px solid #eee;\n text-align: center;\n}\n.oks-access-reset {\n width: 100%;\n padding: 8px;\n border: 2px solid #000;\n color: #000;\n background: transparent;\n font-weight: 700;\n cursor: pointer;\n border-radius: 6px;\n font-size: 12px;\n}\n.oks-access-reset:hover { background: #000; color: #fff; }\n.oks-access-branding { margin-top: 12px; font-size: 12px; color: #000; font-weight: 700; }\n.oks-access-branding a { color: #000; text-decoration: none; border-bottom: 1px dotted #000; }\n\n@media (max-width: 768px) {\n .oks-access-panel {\n width: 100%; height: 100%; max-height: 100%;\n top: 0; left: 0; right: 0; bottom: 0;\n border-radius: 0;\n }\n .oks-access-opt { min-height: 72px; padding: 10px 8px; }\n .oks-icon svg { width: 26px; height: 26px; }\n .oks-label { font-size: 12px; line-height: 1.25; }\n .oks-access-grid { gap: 8px; }\n .oks-access-content { padding: 0 14px 20px; }\n .oks-access-title { font-size: 11px; margin: 10px 0 4px; }\n /* Cursor grande no aplica en t\u00E1ctil: oculto y dejo el \u00FAltimo bot\u00F3n\n de la secci\u00F3n ocupando 2 columnas para no romper la grilla par. */\n .oks-access-opt[data-class=\"oks-big-cursor\"] { display: none; }\n .oks-access-opt[data-class=\"oks-a11y-focus\"] { grid-column: span 2; }\n .oks-access-reset { padding: 14px; font-size: 14px; }\n}\n";
|
|
102
|
+
declare const EFFECT_CSS = "\nhtml.oks-colorblind-1 { filter: url('#oks-filter-protanopia'); }\nhtml.oks-colorblind-2 { filter: url('#oks-filter-deuteranopia'); }\nhtml.oks-colorblind-3 { filter: url('#oks-filter-tritanopia'); }\n\n/* Text-size levels.\n Applied to <html> via :has(), not to <body>. rem is anchored to the root\n element, so a site whose CSS sizes things in rem (most modern Astro / Tailwind\n builds) needs the root font-size to change for the scale to take effect.\n A previous version applied this to body with %, which only moved descendants\n that inherited font-size from body \u2014 anything sized in rem stayed locked to\n the 16px default of <html>. An even earlier version used the universal\n selector with em and compounded the factor at every nesting level.\n :has(body.oks-zoom-N) is the right anchor: one change at the root, rem\n descendants scale exactly once. Hard-coded px is intentionally left alone;\n browser zoom covers that case. */\nhtml:has(body.oks-zoom-1) { font-size: 110% !important; }\nhtml:has(body.oks-zoom-2) { font-size: 120% !important; }\nhtml:has(body.oks-zoom-3) { font-size: 135% !important; }\nhtml:has(body.oks-zoom-4) { font-size: 150% !important; }\n\nbody.oks-lh-1 * { line-height: 1.6 !important; }\nbody.oks-lh-2 * { line-height: 1.9 !important; }\nbody.oks-lh-3 * { line-height: 2.2 !important; }\n\nbody.oks-a11y-font { font-family: Arial, sans-serif !important; }\n\nbody.oks-dyslexia * {\n font-family: 'Comic Sans MS', 'Verdana', sans-serif !important;\n letter-spacing: 0.05em !important;\n word-spacing: 0.1em !important;\n line-height: 1.6 !important;\n}\n\nbody.oks-a11y-hide img { opacity: 0 !important; visibility: hidden !important; }\nbody.oks-a11y-links a { text-decoration: underline !important; background: #ff0 !important; color: #000 !important; }\n\nbody.oks-align-1 * { text-align: left !important; }\nbody.oks-align-2 * { text-align: center !important; }\nbody.oks-align-3 * { text-align: right !important; }\n\nbody.oks-a11y-pause * { animation: none !important; transition: none !important; }\n\nbody.oks-ls-1 * { letter-spacing: 0.05em !important; }\nbody.oks-ls-2 * { letter-spacing: 0.10em !important; }\nbody.oks-ls-3 * { letter-spacing: 0.16em !important; }\n\nbody.oks-a11y-focus a:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-focus button:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-focus input,\nbody.oks-a11y-focus select,\nbody.oks-a11y-focus textarea {\n outline: 2px dashed rgba(0, 95, 204, 0.45) !important;\n outline-offset: 2px !important;\n}\nbody.oks-a11y-focus *:focus-visible {\n outline: 3px solid #005fcc !important;\n outline-offset: 3px !important;\n box-shadow: 0 0 0 6px rgba(0, 95, 204, 0.25) !important;\n}\n\nbody.oks-a11y-contrast.oks-a11y-focus *:focus,\nbody.oks-a11y-contrast.oks-a11y-focus *:focus-visible {\n outline-color: #0ff !important;\n box-shadow: 0 0 0 6px rgba(0, 255, 255, 0.3) !important;\n}\n\n@media (pointer: fine) {\n body.oks-big-cursor, body.oks-big-cursor a, body.oks-big-cursor button {\n cursor: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 24 24'%3E%3Cpath d='M4 2L4 18L8 14L11 21L14 19.5L11 13L15.5 13Z' stroke='white' stroke-width='4' stroke-linejoin='round' fill='white'/%3E%3Cpath d='M4 2L4 18L8 14L11 21L14 19.5L11 13L15.5 13Z' fill='black'/%3E%3C/svg%3E\") 8 4, auto !important;\n }\n}\n\nbody.oks-a11y-contrast,\nbody.oks-a11y-contrast *:not(oksigenia-access-panel):not(oksigenia-access-panel *) {\n background-color: #000 !important;\n color: #ff0 !important;\n border-color: #ff0 !important;\n text-shadow: none !important;\n box-shadow: none !important;\n}\nbody.oks-a11y-contrast img { filter: grayscale(100%) contrast(120%) !important; }\nbody.oks-a11y-contrast a:not(oksigenia-access-panel *) { color: #0ff !important; text-decoration: underline !important; }\n\n/* High-contrast applies background:#000 to every descendant of body to flip\n the page to inverted colours. That selector also catches our own overlays\n (.oks-reading-guide, .oks-overlay-effect), which would then paint a solid\n black band on top of the text and defeat their purpose. Restore the\n overlay-specific values here so they keep working in high-contrast mode. */\nbody.oks-a11y-contrast .oks-reading-guide {\n background-color: rgba(255, 255, 0, 0.25) !important;\n border-top-color: #ff0 !important;\n border-bottom-color: #ff0 !important;\n}\nbody.oks-a11y-contrast .oks-overlay-effect {\n background-color: transparent !important;\n}\n\n.oks-overlay-effect {\n position: fixed; top: 0; left: 0;\n width: 100%; height: 100%;\n pointer-events: none;\n z-index: 999990;\n display: none;\n backdrop-filter: grayscale(100%);\n}\n.oks-overlay-effect.is-active { display: block; }\n\n.oks-reading-guide {\n position: fixed; left: 0;\n width: 100%; height: 50px;\n background: rgba(255, 255, 0, 0.2);\n border-top: 3px solid red;\n border-bottom: 3px solid red;\n pointer-events: none;\n z-index: 2147483647;\n display: none;\n transform: translateY(-50%);\n}\nbody.oks-a11y-guide .oks-reading-guide { display: block; }\n\n/* Reading mask: dark overlay leaving a horizontal band lit around the cursor.\n --oks-mask-y is updated from JS on mousemove; band is \u00B190px around it. */\n.oks-reading-mask {\n position: fixed; top: 0; left: 0;\n width: 100vw; height: 100vh;\n pointer-events: none;\n z-index: 2147483646;\n background: rgba(0, 0, 0, 0.75);\n display: none;\n clip-path: polygon(\n 0 0, 100% 0,\n 100% calc(var(--oks-mask-y, 50vh) - 90px),\n 0 calc(var(--oks-mask-y, 50vh) - 90px),\n 0 calc(var(--oks-mask-y, 50vh) + 90px),\n 100% calc(var(--oks-mask-y, 50vh) + 90px),\n 100% 100%, 0 100%\n );\n}\nbody.oks-a11y-mask .oks-reading-mask { display: block; }\nbody.oks-a11y-contrast .oks-reading-mask { background-color: rgba(0, 0, 0, 0.85) !important; }\n\n/* Big targets: bump interactive hit-areas to WCAG 2.5.5 (44\u00D744 minimum).\n Only adjusts padding + min-* \u2014 never display, so layouts that rely on\n inline flow or grid placement survive. Exempts our own shadow-DOM host. */\nbody.oks-a11y-bigtargets a:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-bigtargets button:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-bigtargets [role=\"button\"]:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-bigtargets input[type=\"checkbox\"]:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-bigtargets input[type=\"radio\"]:not(oksigenia-access-panel):not(oksigenia-access-panel *),\nbody.oks-a11y-bigtargets summary:not(oksigenia-access-panel):not(oksigenia-access-panel *) {\n min-height: 44px !important;\n min-width: 44px !important;\n padding: 8px 12px !important;\n box-sizing: border-box !important;\n}\n";
|
|
90
103
|
|
|
91
104
|
export { type BehaviorOptions, COLORBLIND_FILTERS_SVG, DEFAULT_STATE, EFFECT_CSS, type LocaleCode, PANEL_CSS, type PanelState, type Position, type Translation, type TriggerIcon, bindPanelBehavior, buildPanelHtml, getTranslation, isStateEmpty, loadState, positionCss, saveState, supportedLocales };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// src/translations.ts
|
|
2
2
|
var DICT = {
|
|
3
|
-
es: { title: "Accesibilidad", close: "Cerrar", txt: "Texto", size: "Tama\xF1o", lh: "Interlineado", align: "Alineaci\xF3n", font: "Legible", dyslexia: "Fuente Dislexia", vis: "Visual", contrast: "Contraste", gray: "Grises", hide: "Ocultar Img", links: "Links", ori: "Orientaci\xF3n", guide: "Gu\xEDa", cursor: "Cursor Grande", pause: "Parar Animac.", reset: "Restablecer Todo", dev: "Desarrollado por", ls: "Espaciado", cb: "Daltonismo", focus: "Foco" },
|
|
4
|
-
en: { title: "Accessibility", close: "Close", txt: "Text", size: "Size", lh: "Line Height", align: "Align", font: "Readable Font", dyslexia: "Dyslexia Font", vis: "Visual", contrast: "Contrast", gray: "Grayscale", hide: "Hide Images", links: "Highlight Links", ori: "Orientation", guide: "Reading Guide", cursor: "Big Cursor", pause: "Pause Anim.", reset: "Reset All", dev: "Developed by", ls: "Letter Spacing", cb: "Color Blind", focus: "Focus" },
|
|
5
|
-
gn: { title: "Oikeha (Accesibilidad)", close: "Mboty", txt: "Mo\xF1e'\u1EBDr\xE3", size: "Tuichakue", lh: "Jei", align: "Mbojoja", font: "Letra Por\xE3", dyslexia: "Dislexia", vis: "Hechapy", contrast: "Sa'y", gray: "H\u0169 ha T\u0129", hide: "Moka\xF1y Ta'anga", links: "Joajuha", ori: "S\xE3mbyhy", guide: "S\xE3mbyhyha", cursor: "Cursor Guasu", pause: "Mboopyta", reset: "Mbojevy", dev: "Apojare", ls: "Rapykue", cb: "Sa'yvy", focus: "\xD1emoha" },
|
|
6
|
-
fr: { title: "Accessibilit\xE9", close: "Fermer", txt: "Texte", size: "Taille", lh: "Interligne", align: "Alignement", font: "Police Lisible", dyslexia: "Police Dyslexie", vis: "Visuel", contrast: "Contraste", gray: "Niveaux Gris", hide: "Masquer Img", links: "Liens", ori: "Orientation", guide: "Guide Lecture", cursor: "Grand Curseur", pause: "Pause Anim.", reset: "R\xE9initialiser", dev: "D\xE9velopp\xE9 par", ls: "Espacement", cb: "Daltonisme", focus: "Focus" },
|
|
7
|
-
it: { title: "Accessibilit\xE0", close: "Chiudi", txt: "Testo", size: "Dimensione", lh: "Interlinea", align: "Allineamento", font: "Leggibile", dyslexia: "Font Dislessia", vis: "Visivo", contrast: "Contrasto", gray: "Scala Grig.", hide: "Nascondi Img", links: "Link", ori: "Orientamento", guide: "Guida", cursor: "Cursore Grande", pause: "Pausa Anim.", reset: "Reimposta", dev: "Sviluppato da", ls: "Spaziatura", cb: "Daltonismo", focus: "Focus" },
|
|
8
|
-
de: { title: "Barrierefreiheit", close: "Schlie\xDFen", txt: "Text", size: "Gr\xF6\xDFe", lh: "Zeilenh\xF6he", align: "Ausrichtung", font: "Lesbar", dyslexia: "Dyslexie", vis: "Visuell", contrast: "Kontrast", gray: "Graustufen", hide: "Bilder Aus", links: "Links", ori: "Orientierung", guide: "Lesehilfe", cursor: "Gro\xDFer Cursor", pause: "Anim. Stopp", reset: "Zur\xFCcksetzen", dev: "Entwickelt von", ls: "Buchst.abst.", cb: "Farbblindheit", focus: "Fokus" },
|
|
9
|
-
nl: { title: "Toegankelijkheid", close: "Sluiten", txt: "Tekst", size: "Grootte", lh: "Regelhoogte", align: "Uitlijning", font: "Leesbaar", dyslexia: "Dyslexie", vis: "Visueel", contrast: "Contrast", gray: "Grijstinten", hide: "Verberg Afb.", links: "Links", ori: "Ori\xEBntatie", guide: "Leesgids", cursor: "Grote Cursor", pause: "Anim. Pauze", reset: "Resetten", dev: "Ontwikkeld door", ls: "Letterspatie", cb: "Kleurenblind", focus: "Focus" },
|
|
10
|
-
sv: { title: "Tillg\xE4nglighet", close: "St\xE4ng", txt: "Text", size: "Storlek", lh: "Radh\xF6jd", align: "Justering", font: "L\xE4sbar", dyslexia: "Dyslexi", vis: "Visuell", contrast: "Kontrast", gray: "Gr\xE5skala", hide: "D\xF6lj Bilder", links: "L\xE4nkar", ori: "Orientering", guide: "L\xE4slinjal", cursor: "Stor Mark\xF6r", pause: "Pausa Anim.", reset: "\xC5terst\xE4ll", dev: "Utvecklad av", ls: "Bokstavsavst.", cb: "F\xE4rgblindhet", focus: "Fokus" }
|
|
3
|
+
es: { title: "Accesibilidad", close: "Cerrar", txt: "Texto", size: "Tama\xF1o", lh: "Interlineado", align: "Alineaci\xF3n", font: "Legible", dyslexia: "Fuente Dislexia", vis: "Visual", contrast: "Contraste", gray: "Grises", hide: "Ocultar Img", links: "Links", ori: "Orientaci\xF3n", guide: "Gu\xEDa", mask: "M\xE1scara", targets: "\xC1reas Grandes", cursor: "Cursor Grande", pause: "Parar Animac.", reset: "Restablecer Todo", dev: "Desarrollado por", ls: "Espaciado", cb: "Daltonismo", focus: "Foco", presets: "Perfiles", pLow: "Baja Visi\xF3n", pDys: "Dislexia", pMot: "Motor", pCalm: "Sin Distrac." },
|
|
4
|
+
en: { title: "Accessibility", close: "Close", txt: "Text", size: "Size", lh: "Line Height", align: "Align", font: "Readable Font", dyslexia: "Dyslexia Font", vis: "Visual", contrast: "Contrast", gray: "Grayscale", hide: "Hide Images", links: "Highlight Links", ori: "Orientation", guide: "Reading Guide", mask: "Reading Mask", targets: "Big Targets", cursor: "Big Cursor", pause: "Pause Anim.", reset: "Reset All", dev: "Developed by", ls: "Letter Spacing", cb: "Color Blind", focus: "Focus", presets: "Profiles", pLow: "Low Vision", pDys: "Dyslexia", pMot: "Motor", pCalm: "No Distract." },
|
|
5
|
+
gn: { title: "Oikeha (Accesibilidad)", close: "Mboty", txt: "Mo\xF1e'\u1EBDr\xE3", size: "Tuichakue", lh: "Jei", align: "Mbojoja", font: "Letra Por\xE3", dyslexia: "Dislexia", vis: "Hechapy", contrast: "Sa'y", gray: "H\u0169 ha T\u0129", hide: "Moka\xF1y Ta'anga", links: "Joajuha", ori: "S\xE3mbyhy", guide: "S\xE3mbyhyha", mask: "Mbohov\xE1i", targets: "Tenda Guasu", cursor: "Cursor Guasu", pause: "Mboopyta", reset: "Mbojevy", dev: "Apojare", ls: "Rapykue", cb: "Sa'yvy", focus: "\xD1emoha", presets: "Tekor\xE3", pLow: "Hechapy Vai", pDys: "Dislexia", pMot: "Po-rehegua", pCalm: "Py\u02BCa Guapy" },
|
|
6
|
+
fr: { title: "Accessibilit\xE9", close: "Fermer", txt: "Texte", size: "Taille", lh: "Interligne", align: "Alignement", font: "Police Lisible", dyslexia: "Police Dyslexie", vis: "Visuel", contrast: "Contraste", gray: "Niveaux Gris", hide: "Masquer Img", links: "Liens", ori: "Orientation", guide: "Guide Lecture", mask: "Masque Lecture", targets: "Grandes Cibles", cursor: "Grand Curseur", pause: "Pause Anim.", reset: "R\xE9initialiser", dev: "D\xE9velopp\xE9 par", ls: "Espacement", cb: "Daltonisme", focus: "Focus", presets: "Profils", pLow: "Basse Vision", pDys: "Dyslexie", pMot: "Moteur", pCalm: "Sans Distrac." },
|
|
7
|
+
it: { title: "Accessibilit\xE0", close: "Chiudi", txt: "Testo", size: "Dimensione", lh: "Interlinea", align: "Allineamento", font: "Leggibile", dyslexia: "Font Dislessia", vis: "Visivo", contrast: "Contrasto", gray: "Scala Grig.", hide: "Nascondi Img", links: "Link", ori: "Orientamento", guide: "Guida", mask: "Maschera", targets: "Aree Grandi", cursor: "Cursore Grande", pause: "Pausa Anim.", reset: "Reimposta", dev: "Sviluppato da", ls: "Spaziatura", cb: "Daltonismo", focus: "Focus", presets: "Profili", pLow: "Ipovisione", pDys: "Dislessia", pMot: "Motorio", pCalm: "No Distraz." },
|
|
8
|
+
de: { title: "Barrierefreiheit", close: "Schlie\xDFen", txt: "Text", size: "Gr\xF6\xDFe", lh: "Zeilenh\xF6he", align: "Ausrichtung", font: "Lesbar", dyslexia: "Dyslexie", vis: "Visuell", contrast: "Kontrast", gray: "Graustufen", hide: "Bilder Aus", links: "Links", ori: "Orientierung", guide: "Lesehilfe", mask: "Lesemaske", targets: "Gro\xDFe Ziele", cursor: "Gro\xDFer Cursor", pause: "Anim. Stopp", reset: "Zur\xFCcksetzen", dev: "Entwickelt von", ls: "Buchst.abst.", cb: "Farbblindheit", focus: "Fokus", presets: "Profile", pLow: "Sehschw\xE4che", pDys: "Dyslexie", pMot: "Motorik", pCalm: "Ohne Ablenk." },
|
|
9
|
+
nl: { title: "Toegankelijkheid", close: "Sluiten", txt: "Tekst", size: "Grootte", lh: "Regelhoogte", align: "Uitlijning", font: "Leesbaar", dyslexia: "Dyslexie", vis: "Visueel", contrast: "Contrast", gray: "Grijstinten", hide: "Verberg Afb.", links: "Links", ori: "Ori\xEBntatie", guide: "Leesgids", mask: "Leesmasker", targets: "Grote Doelen", cursor: "Grote Cursor", pause: "Anim. Pauze", reset: "Resetten", dev: "Ontwikkeld door", ls: "Letterspatie", cb: "Kleurenblind", focus: "Focus", presets: "Profielen", pLow: "Slechtziend", pDys: "Dyslexie", pMot: "Motoriek", pCalm: "Geen Afleid." },
|
|
10
|
+
sv: { title: "Tillg\xE4nglighet", close: "St\xE4ng", txt: "Text", size: "Storlek", lh: "Radh\xF6jd", align: "Justering", font: "L\xE4sbar", dyslexia: "Dyslexi", vis: "Visuell", contrast: "Kontrast", gray: "Gr\xE5skala", hide: "D\xF6lj Bilder", links: "L\xE4nkar", ori: "Orientering", guide: "L\xE4slinjal", mask: "L\xE4smask", targets: "Stora Ytor", cursor: "Stor Mark\xF6r", pause: "Pausa Anim.", reset: "\xC5terst\xE4ll", dev: "Utvecklad av", ls: "Bokstavsavst.", cb: "F\xE4rgblindhet", focus: "Fokus", presets: "Profiler", pLow: "Synneds\xE4tt.", pDys: "Dyslexi", pMot: "Motorik", pCalm: "Inga Distrak." }
|
|
11
11
|
};
|
|
12
12
|
function getTranslation(locale) {
|
|
13
13
|
const lc = locale.toLowerCase();
|
|
@@ -35,6 +35,8 @@ var ICON_PAUSE = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 19h4V
|
|
|
35
35
|
var ICON_LS = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M5 5v14h2V5H5zm4 0v14h2V5H9zm4 4v6h2V9h-2zm4-4v14h2V5h-2z"/></svg>';
|
|
36
36
|
var ICON_COLORBLIND = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></svg>';
|
|
37
37
|
var ICON_FOCUS = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 7V3h4v2H5v2H3zm14-4h4v4h-2V5h-2V3zm4 14v4h-4v-2h2v-2h2zM7 21H3v-4h2v2h2v2z"/></svg>';
|
|
38
|
+
var ICON_MASK = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M2 4h20v6H2zm0 10h20v6H2zm2-9v4h16V5zm0 10v4h16v-4z" opacity=".55"/><rect x="2" y="10" width="20" height="4"/></svg>';
|
|
39
|
+
var ICON_TARGETS = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 3h4v2H5v2H3zm14 0h4v4h-2V5h-2zm0 18v-2h2v-2h2v4zM3 21v-4h2v2h2v2zM12 8a4 4 0 100 8 4 4 0 000-8zm0 2a2 2 0 110 4 2 2 0 010-4z"/></svg>';
|
|
38
40
|
var TRIGGER_ICONS = {
|
|
39
41
|
vitruvian: '<svg viewBox="0 0 122.88 122.88" fill="currentColor"><path d="M61.44,0A61.46,61.46,0,1,1,18,18,61.21,61.21,0,0,1,61.44,0Zm-.39,74.18L52.1,98.91a4.94,4.94,0,0,1-2.58,2.83A5,5,0,0,1,42.7,95.5l6.24-17.28a26.3,26.3,0,0,0,1.17-4,40.64,40.64,0,0,0,.54-4.18c.24-2.53.41-5.27.54-7.9s.22-5.18.29-7.29c.09-2.63-.62-2.8-2.73-3.3l-.44-.1-18-3.39A5,5,0,0,1,27.08,46a5,5,0,0,1,5.05-7.74l19.34,3.63c.77.07,1.52.16,2.31.25a57.64,57.64,0,0,0,7.18.53A81.13,81.13,0,0,0,69.9,42c.9-.1,1.75-.21,2.6-.29l18.25-3.42A5,5,0,0,1,94.5,39a5,5,0,0,1,1.3,7,5,5,0,0,1-3.21,2.09L75.15,51.37c-.58.13-1.1.22-1.56.29-1.82.31-2.72.47-2.61,3.06.08,1.89.31,4.15.61,6.51.35,2.77.81,5.71,1.29,8.4.31,1.77.6,3.19,1,4.55s.79,2.75,1.39,4.42l6.11,16.9a5,5,0,0,1-6.82,6.24,4.94,4.94,0,0,1-2.58-2.83L63,74.23,62,72.4l-1,1.78Zm.39-53.52a8.83,8.83,0,1,1-6.24,2.59,8.79,8.79,0,0,1,6.24-2.59Zm36.35,4.43a51.42,51.42,0,1,0,15,36.35,51.27,51.27,0,0,0-15-36.35Z"/></svg>',
|
|
40
42
|
wheelchair: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 13v-2c-1.54.02-3.09-.75-4.07-1.83l-1.29-1.43c-.17-.19-.38-.34-.61-.45-.01 0-.01-.01-.02-.01H13c-.35-.2-.75-.3-1.19-.26C10.76 7.11 10 8.04 10 9.09V15c0 1.1.9 2 2 2h5v5h2v-5.5c0-1.1-.9-2-2-2h-3v-3.45c1.29 1.07 3.25 1.94 5 1.95zm-6.17 5c-.41 1.16-1.52 2-2.83 2-1.66 0-3-1.34-3-3 0-1.31.84-2.41 2-2.83V12.1c-2.28.46-4 2.48-4 4.9 0 2.76 2.24 5 5 5 2.42 0 4.44-1.72 4.9-4h-2.07zM12 6c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/></svg>',
|
|
@@ -57,6 +59,8 @@ function buildPanelHtml(opts) {
|
|
|
57
59
|
const toggle = (klass, label, icon) => `<button class="oks-access-opt" data-action="toggle" data-class="${klass}" aria-pressed="false" type="button"><span class="oks-icon">${icon}</span><span class="oks-label">${label}</span></button>`;
|
|
58
60
|
const overlay = (id, label, icon) => `<button class="oks-access-opt" data-action="overlay" data-target="${id}" aria-pressed="false" type="button"><span class="oks-icon">${icon}</span><span class="oks-label">${label}</span></button>`;
|
|
59
61
|
const guide = (label, icon) => `<button class="oks-access-opt" data-action="guide" aria-pressed="false" type="button"><span class="oks-icon">${icon}</span><span class="oks-label">${label}</span></button>`;
|
|
62
|
+
const mask = (label, icon) => `<button class="oks-access-opt" data-action="mask" aria-pressed="false" type="button"><span class="oks-icon">${icon}</span><span class="oks-label">${label}</span></button>`;
|
|
63
|
+
const preset = (id, label, icon) => `<button class="oks-preset" data-action="preset" data-preset="${id}" type="button"><span class="oks-icon">${icon}</span><span class="oks-label">${label}</span></button>`;
|
|
60
64
|
return `
|
|
61
65
|
<div class="oks-access-wrapper" id="oks-wrapper" data-position="${opts.position}">
|
|
62
66
|
<button class="oks-access-btn" id="oks-trigger" aria-label="${escapeAttr(t.title)}" aria-expanded="false" aria-controls="oks-panel" type="button">
|
|
@@ -70,6 +74,13 @@ function buildPanelHtml(opts) {
|
|
|
70
74
|
<button class="oks-access-close" id="oks-close" aria-label="${escapeAttr(t.close)}" type="button">${ICON_CLOSE}</button>
|
|
71
75
|
</div>
|
|
72
76
|
<div class="oks-access-content">
|
|
77
|
+
<h4 class="oks-access-title">${escapeHtml(t.presets)}</h4>
|
|
78
|
+
<div class="oks-access-presets">
|
|
79
|
+
${preset("lowvision", t.pLow, ICON_CONTRAST)}
|
|
80
|
+
${preset("dyslexia", t.pDys, ICON_DYSLEXIA)}
|
|
81
|
+
${preset("motor", t.pMot, ICON_CURSOR)}
|
|
82
|
+
${preset("calm", t.pCalm, ICON_HIDE)}
|
|
83
|
+
</div>
|
|
73
84
|
<h4 class="oks-access-title">${escapeHtml(t.txt)}</h4>
|
|
74
85
|
${grid([
|
|
75
86
|
multi("multi", "oks-zoom", 4, t.size, ICON_TXT),
|
|
@@ -90,7 +101,9 @@ function buildPanelHtml(opts) {
|
|
|
90
101
|
<h4 class="oks-access-title">${escapeHtml(t.ori)}</h4>
|
|
91
102
|
${grid([
|
|
92
103
|
guide(t.guide, ICON_GUIDE),
|
|
104
|
+
mask(t.mask, ICON_MASK),
|
|
93
105
|
toggle("oks-big-cursor", t.cursor, ICON_CURSOR),
|
|
106
|
+
toggle("oks-a11y-bigtargets", t.targets, ICON_TARGETS),
|
|
94
107
|
toggle("oks-a11y-pause", t.pause, ICON_PAUSE),
|
|
95
108
|
toggle("oks-a11y-focus", t.focus, ICON_FOCUS)
|
|
96
109
|
])}
|
|
@@ -156,7 +169,9 @@ var DEFAULT_STATE = Object.freeze({
|
|
|
156
169
|
pauseAnim: false,
|
|
157
170
|
focusOutline: false,
|
|
158
171
|
grayOverlay: false,
|
|
159
|
-
readingGuide: false
|
|
172
|
+
readingGuide: false,
|
|
173
|
+
readingMask: false,
|
|
174
|
+
bigTargets: false
|
|
160
175
|
});
|
|
161
176
|
function loadState(key) {
|
|
162
177
|
if (typeof localStorage === "undefined") return { ...DEFAULT_STATE };
|
|
@@ -187,7 +202,7 @@ function saveState(key, state) {
|
|
|
187
202
|
}
|
|
188
203
|
}
|
|
189
204
|
function isStateEmpty(state) {
|
|
190
|
-
return state.zoom === 0 && state.lh === 0 && state.align === 0 && state.ls === 0 && state.colorblind === 0 && !state.font && !state.dyslexia && !state.contrast && !state.hideImages && !state.highlightLinks && !state.bigCursor && !state.pauseAnim && !state.focusOutline && !state.grayOverlay && !state.readingGuide;
|
|
205
|
+
return state.zoom === 0 && state.lh === 0 && state.align === 0 && state.ls === 0 && state.colorblind === 0 && !state.font && !state.dyslexia && !state.contrast && !state.hideImages && !state.highlightLinks && !state.bigCursor && !state.pauseAnim && !state.focusOutline && !state.grayOverlay && !state.readingGuide && !state.readingMask && !state.bigTargets;
|
|
191
206
|
}
|
|
192
207
|
|
|
193
208
|
// src/behavior.ts
|
|
@@ -213,7 +228,14 @@ var TOGGLE_KEYS = {
|
|
|
213
228
|
"oks-a11y-links": "highlightLinks",
|
|
214
229
|
"oks-big-cursor": "bigCursor",
|
|
215
230
|
"oks-a11y-pause": "pauseAnim",
|
|
216
|
-
"oks-a11y-focus": "focusOutline"
|
|
231
|
+
"oks-a11y-focus": "focusOutline",
|
|
232
|
+
"oks-a11y-bigtargets": "bigTargets"
|
|
233
|
+
};
|
|
234
|
+
var PRESETS = {
|
|
235
|
+
lowvision: { zoom: 2, contrast: true, highlightLinks: true, bigCursor: true, focusOutline: true },
|
|
236
|
+
dyslexia: { dyslexia: true, lh: 2, ls: 2, readingGuide: true },
|
|
237
|
+
motor: { bigCursor: true, bigTargets: true, focusOutline: true },
|
|
238
|
+
calm: { hideImages: true, pauseAnim: true }
|
|
217
239
|
};
|
|
218
240
|
function bindPanelBehavior(root, opts = {}) {
|
|
219
241
|
const storageKey = opts.storageKey ?? "oksiacSettings";
|
|
@@ -222,7 +244,7 @@ function bindPanelBehavior(root, opts = {}) {
|
|
|
222
244
|
const closeBtn = root.getElementById("oks-close");
|
|
223
245
|
const resetBtn = root.getElementById("oks-reset");
|
|
224
246
|
const wrapper = root.getElementById("oks-wrapper");
|
|
225
|
-
const opts$ = Array.from(root.querySelectorAll(".oks-access-opt"));
|
|
247
|
+
const opts$ = Array.from(root.querySelectorAll(".oks-access-opt, .oks-preset"));
|
|
226
248
|
if (!trigger || !panel || !closeBtn || !resetBtn || !wrapper) {
|
|
227
249
|
return () => {
|
|
228
250
|
};
|
|
@@ -247,6 +269,8 @@ function bindPanelBehavior(root, opts = {}) {
|
|
|
247
269
|
if (state.pauseAnim) body.classList.add("oks-a11y-pause");
|
|
248
270
|
if (state.focusOutline) body.classList.add("oks-a11y-focus");
|
|
249
271
|
if (state.readingGuide) body.classList.add("oks-a11y-guide");
|
|
272
|
+
if (state.readingMask) body.classList.add("oks-a11y-mask");
|
|
273
|
+
if (state.bigTargets) body.classList.add("oks-a11y-bigtargets");
|
|
250
274
|
const overlay = ensureOverlay();
|
|
251
275
|
overlay.classList.toggle("is-active", state.grayOverlay);
|
|
252
276
|
syncButtonsFromState();
|
|
@@ -276,6 +300,9 @@ function bindPanelBehavior(root, opts = {}) {
|
|
|
276
300
|
} else if (action === "guide") {
|
|
277
301
|
btn.classList.toggle("is-active", state.readingGuide);
|
|
278
302
|
btn.setAttribute("aria-pressed", state.readingGuide ? "true" : "false");
|
|
303
|
+
} else if (action === "mask") {
|
|
304
|
+
btn.classList.toggle("is-active", state.readingMask);
|
|
305
|
+
btn.setAttribute("aria-pressed", state.readingMask ? "true" : "false");
|
|
279
306
|
}
|
|
280
307
|
}
|
|
281
308
|
}
|
|
@@ -302,6 +329,14 @@ function bindPanelBehavior(root, opts = {}) {
|
|
|
302
329
|
if (state.grayOverlay) state.contrast = false;
|
|
303
330
|
} else if (action === "guide") {
|
|
304
331
|
state.readingGuide = !state.readingGuide;
|
|
332
|
+
} else if (action === "mask") {
|
|
333
|
+
state.readingMask = !state.readingMask;
|
|
334
|
+
} else if (action === "preset") {
|
|
335
|
+
const id = btn.getAttribute("data-preset") ?? "";
|
|
336
|
+
const preset = PRESETS[id];
|
|
337
|
+
if (preset) Object.assign(state, preset);
|
|
338
|
+
btn.classList.add("is-flashing");
|
|
339
|
+
setTimeout(() => btn.classList.remove("is-flashing"), 250);
|
|
305
340
|
}
|
|
306
341
|
applyState();
|
|
307
342
|
saveState(storageKey, state);
|
|
@@ -331,8 +366,9 @@ function bindPanelBehavior(root, opts = {}) {
|
|
|
331
366
|
};
|
|
332
367
|
const onDocClick = (e) => {
|
|
333
368
|
if (!panel.classList.contains("is-open")) return;
|
|
334
|
-
const
|
|
335
|
-
if (
|
|
369
|
+
const path = e.composedPath();
|
|
370
|
+
if (path.includes(panel) || path.includes(trigger) || path.includes(wrapper)) return;
|
|
371
|
+
closePanel();
|
|
336
372
|
};
|
|
337
373
|
const onKeyDown = (e) => {
|
|
338
374
|
if (!panel.classList.contains("is-open")) return;
|
|
@@ -359,11 +395,17 @@ function bindPanelBehavior(root, opts = {}) {
|
|
|
359
395
|
}
|
|
360
396
|
};
|
|
361
397
|
const onMove = (e) => {
|
|
362
|
-
if (!state.readingGuide) return;
|
|
363
|
-
const guide = document.getElementById("oks-reading-guide");
|
|
364
|
-
if (!guide) return;
|
|
398
|
+
if (!state.readingGuide && !state.readingMask) return;
|
|
365
399
|
const y = e.touches?.[0]?.clientY ?? e.clientY;
|
|
366
|
-
if (typeof y
|
|
400
|
+
if (typeof y !== "number") return;
|
|
401
|
+
if (state.readingGuide) {
|
|
402
|
+
const guide = document.getElementById("oks-reading-guide");
|
|
403
|
+
if (guide) guide.style.top = `${y}px`;
|
|
404
|
+
}
|
|
405
|
+
if (state.readingMask) {
|
|
406
|
+
const mask = document.getElementById("oks-reading-mask");
|
|
407
|
+
if (mask) mask.style.setProperty("--oks-mask-y", `${y}px`);
|
|
408
|
+
}
|
|
367
409
|
};
|
|
368
410
|
trigger.addEventListener("click", onTriggerClick);
|
|
369
411
|
closeBtn.addEventListener("click", closePanel);
|
|
@@ -508,6 +550,43 @@ var PANEL_CSS = `
|
|
|
508
550
|
color: #888;
|
|
509
551
|
}
|
|
510
552
|
.oks-access-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }
|
|
553
|
+
.oks-access-presets { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
|
|
554
|
+
.oks-preset {
|
|
555
|
+
background: #f0f4f8;
|
|
556
|
+
border: 2px solid transparent;
|
|
557
|
+
border-radius: 8px;
|
|
558
|
+
padding: 8px 4px;
|
|
559
|
+
display: flex;
|
|
560
|
+
flex-direction: column;
|
|
561
|
+
align-items: center;
|
|
562
|
+
cursor: pointer;
|
|
563
|
+
font: inherit;
|
|
564
|
+
color: #333;
|
|
565
|
+
min-width: 0;
|
|
566
|
+
transition: 0.15s;
|
|
567
|
+
}
|
|
568
|
+
.oks-preset:hover { background: #000; color: #fff; }
|
|
569
|
+
.oks-preset:focus-visible { outline: 2px solid #000; outline-offset: 2px; }
|
|
570
|
+
/* Click feedback: a 250 ms flip + slight squeeze. Pure transient \u2014 the
|
|
571
|
+
button does not carry persistent active state because a preset is a
|
|
572
|
+
trigger, not a mode. */
|
|
573
|
+
.oks-preset.is-flashing {
|
|
574
|
+
background: #000;
|
|
575
|
+
color: #fff;
|
|
576
|
+
transform: scale(0.96);
|
|
577
|
+
}
|
|
578
|
+
.oks-preset .oks-icon { font-size: 22px; margin-bottom: 4px; }
|
|
579
|
+
.oks-preset .oks-icon svg { width: 20px; height: 20px; }
|
|
580
|
+
.oks-preset .oks-label {
|
|
581
|
+
font-size: 10px; font-weight: 700; text-transform: uppercase;
|
|
582
|
+
text-align: center; line-height: 1.15;
|
|
583
|
+
overflow-wrap: anywhere; word-break: break-word;
|
|
584
|
+
/* Reserve room for 2 lines so 1-line labels (DISLEXIA, MOTOR) and
|
|
585
|
+
2-line labels (BAJA VISI\xD3N, SIN DISTRAC.) end up the same height,
|
|
586
|
+
centred. Without this the row looks ragged. */
|
|
587
|
+
min-height: 2.3em;
|
|
588
|
+
display: flex; align-items: center; justify-content: center;
|
|
589
|
+
}
|
|
511
590
|
.oks-access-opt {
|
|
512
591
|
background: #f9f9f9;
|
|
513
592
|
border: 2px solid #eee;
|
|
@@ -708,6 +787,42 @@ body.oks-a11y-contrast .oks-overlay-effect {
|
|
|
708
787
|
transform: translateY(-50%);
|
|
709
788
|
}
|
|
710
789
|
body.oks-a11y-guide .oks-reading-guide { display: block; }
|
|
790
|
+
|
|
791
|
+
/* Reading mask: dark overlay leaving a horizontal band lit around the cursor.
|
|
792
|
+
--oks-mask-y is updated from JS on mousemove; band is \xB190px around it. */
|
|
793
|
+
.oks-reading-mask {
|
|
794
|
+
position: fixed; top: 0; left: 0;
|
|
795
|
+
width: 100vw; height: 100vh;
|
|
796
|
+
pointer-events: none;
|
|
797
|
+
z-index: 2147483646;
|
|
798
|
+
background: rgba(0, 0, 0, 0.75);
|
|
799
|
+
display: none;
|
|
800
|
+
clip-path: polygon(
|
|
801
|
+
0 0, 100% 0,
|
|
802
|
+
100% calc(var(--oks-mask-y, 50vh) - 90px),
|
|
803
|
+
0 calc(var(--oks-mask-y, 50vh) - 90px),
|
|
804
|
+
0 calc(var(--oks-mask-y, 50vh) + 90px),
|
|
805
|
+
100% calc(var(--oks-mask-y, 50vh) + 90px),
|
|
806
|
+
100% 100%, 0 100%
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
body.oks-a11y-mask .oks-reading-mask { display: block; }
|
|
810
|
+
body.oks-a11y-contrast .oks-reading-mask { background-color: rgba(0, 0, 0, 0.85) !important; }
|
|
811
|
+
|
|
812
|
+
/* Big targets: bump interactive hit-areas to WCAG 2.5.5 (44\xD744 minimum).
|
|
813
|
+
Only adjusts padding + min-* \u2014 never display, so layouts that rely on
|
|
814
|
+
inline flow or grid placement survive. Exempts our own shadow-DOM host. */
|
|
815
|
+
body.oks-a11y-bigtargets a:not(oksigenia-access-panel):not(oksigenia-access-panel *),
|
|
816
|
+
body.oks-a11y-bigtargets button:not(oksigenia-access-panel):not(oksigenia-access-panel *),
|
|
817
|
+
body.oks-a11y-bigtargets [role="button"]:not(oksigenia-access-panel):not(oksigenia-access-panel *),
|
|
818
|
+
body.oks-a11y-bigtargets input[type="checkbox"]:not(oksigenia-access-panel):not(oksigenia-access-panel *),
|
|
819
|
+
body.oks-a11y-bigtargets input[type="radio"]:not(oksigenia-access-panel):not(oksigenia-access-panel *),
|
|
820
|
+
body.oks-a11y-bigtargets summary:not(oksigenia-access-panel):not(oksigenia-access-panel *) {
|
|
821
|
+
min-height: 44px !important;
|
|
822
|
+
min-width: 44px !important;
|
|
823
|
+
padding: 8px 12px !important;
|
|
824
|
+
box-sizing: border-box !important;
|
|
825
|
+
}
|
|
711
826
|
`;
|
|
712
827
|
|
|
713
828
|
export { COLORBLIND_FILTERS_SVG, DEFAULT_STATE, EFFECT_CSS, PANEL_CSS, bindPanelBehavior, buildPanelHtml, getTranslation, isStateEmpty, loadState, positionCss, saveState, supportedLocales };
|