@oksigenia/access-panel 0.3.8 → 0.4.1
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/CHANGELOG.md +110 -0
- package/README.md +35 -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 +6 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @oksigenia/access-panel
|
|
2
|
+
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
Include `CHANGELOG.md` in the published npm tarball. The `files` array in
|
|
8
|
+
`package.json` was an allow-list that excluded the changelog, so consumers
|
|
9
|
+
using `npm view` or reading their installed `node_modules` had no
|
|
10
|
+
visibility into release notes. Pure packaging fix — no runtime change.
|
|
11
|
+
|
|
12
|
+
## 0.4.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- 8d395a3: Add **reading mask** (dark overlay that follows the cursor with a lit reading band, complementary to the existing reading guide), **big targets** (boosts interactive hit-area to 44×44 minimum per WCAG 2.5.5/2.5.8 with `padding` + `min-*` only, no layout-breaking `display` changes), and **4 additive profile presets** (low vision, dyslexia, motor, no distractions) that bundle related toggles in one click. Presets are triggers, not modes — they apply flags and let the user adjust afterwards; a 250 ms flash gives click feedback without a persistent active state.
|
|
17
|
+
|
|
18
|
+
Also fixes a latent Shadow DOM event-target bug in the document-level "click outside the panel" handler. `panel.contains(e.target)` returned `false` for any click originating inside the panel because the target is retargeted to the host element when the event crosses the shadow boundary. Replaced with `e.composedPath()` which is shadow-aware, so the panel no longer closes spuriously on its own button clicks.
|
|
19
|
+
|
|
20
|
+
New fields in `PanelState` (`readingMask`, `bigTargets`), new translation keys for all 8 locales (`mask`, `targets`, `presets`, `pLow`, `pDys`, `pMot`, `pCalm`), and two new SVG icons (`ICON_MASK`, `ICON_TARGETS`).
|
|
21
|
+
|
|
22
|
+
## 0.3.8
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
Mobile panel densified and big-cursor option hidden on touch devices. The WP plugin already did this; the web component lagged behind. Three concrete changes inside the `@media (max-width: 768px)` block:
|
|
27
|
+
|
|
28
|
+
- `.oks-access-opt[data-class="oks-big-cursor"] { display: none; }` — the option only makes sense with a mouse; `pointer: coarse` devices never see it.
|
|
29
|
+
- `.oks-access-opt[data-class="oks-a11y-focus"] { grid-column: span 2; }` — fills the gap left by the hidden cursor button so the grid stays even.
|
|
30
|
+
- Compacted spacing: `min-height` 88 → 72 px (still well above the 44×44 minimum from WCAG 2.5.5), padding 14/8 → 10/8, gap 10 → 8, icons 30 → 26, content padding 16/24 → 14/20, section titles 14/6 → 10/4. Result: all 14 controls fit one screen on common mobile viewports (~640-844 px high) without scrolling.
|
|
31
|
+
|
|
32
|
+
## 0.3.7
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
Real fix for the mobile panel overflow reported on granjaoga.com. The grid `minmax(0, 1fr)` change in 0.3.6 was a red herring — the actual cause was in `positionCss()`. Dynamic position rules (`top: 50%; left: 90px; transform: translateY(-50%)` for `position="mid-left"`, etc.) were injected into the Shadow DOM **after** the mobile `@media (max-width: 768px)` block that puts the panel fullscreen. The dynamic rules sat at the bottom of the stylesheet, so they overrode `top`, `left`, `transform` on mobile too, leaving the panel `width: 100%` but anchored at `left: 90px` — clipping its right side by 90px on narrow viewports. Position rules for `.oks-access-panel` now live inside `@media (min-width: 769px)` so they only apply on desktop. Wrapper (trigger button) rules are unaffected.
|
|
37
|
+
|
|
38
|
+
## 0.3.6
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
Mobile responsive fix: the option grid (`.oks-access-grid`) used `grid-template-columns: 1fr 1fr`, which lets each column grow to its min-content. On narrow viewports, long labels (FUENTE DISLEXIA, LINKS DESTACADOS, INTERLINEADO) pushed the second column off-screen — the right half of the panel was clipped on mobile. Switched to `minmax(0, 1fr) minmax(0, 1fr)`, added `min-width: 0` on `.oks-access-opt` and `overflow-wrap: anywhere; word-break: break-word;` on `.oks-label`. The panel now fits the viewport on every device.
|
|
43
|
+
|
|
44
|
+
## 0.3.5
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
First release published via **npm Trusted Publishing (GitHub Actions OIDC)** instead of a long-lived publish token. Same code as 0.3.4 — this bump exists to validate the OIDC-based publish workflow. The published tarball ships with an [npm provenance attestation](https://docs.npmjs.com/generating-provenance-statements) that links the package back to the exact commit + workflow run that produced it (verifiable in the [sigstore transparency log](https://search.sigstore.dev/)).
|
|
49
|
+
|
|
50
|
+
## 0.3.4
|
|
51
|
+
|
|
52
|
+
### Patch Changes
|
|
53
|
+
|
|
54
|
+
- Fix: text-size levels had no visible effect on sites whose CSS sizes things in `rem` (anchored to `<html>`).
|
|
55
|
+
|
|
56
|
+
The 0.3.3 fix moved `oks-zoom-*` from the universal selector to `<body>` with percent values, which only moves descendants that inherit `font-size` from `<body>`. Sites whose CSS uses `rem` (anchored to `<html>`) saw no change at all.
|
|
57
|
+
|
|
58
|
+
Anchor the change at `<html>` via `:has(body.oks-zoom-N)` so the root font-size updates once and every `rem` descendant scales cleanly. No compounding, no missed descendants, hard-coded `px` intentionally left alone.
|
|
59
|
+
|
|
60
|
+
`:has()` is supported in Chrome 105+, Safari 15.4+ and Firefox 121+.
|
|
61
|
+
|
|
62
|
+
## 0.3.3
|
|
63
|
+
|
|
64
|
+
### Patch Changes
|
|
65
|
+
|
|
66
|
+
Re-publish of the same content shipped as 0.3.2 below — the 0.3.2 tarball on
|
|
67
|
+
the npm registry went out without the `dist/` directory because the local
|
|
68
|
+
build had errored just before `npm pack` (a stray backtick inside a template
|
|
69
|
+
literal made `tsup` fail) and the publish proceeded anyway. **Do not use
|
|
70
|
+
0.3.2** — it is missing all compiled output. Use 0.3.3.
|
|
71
|
+
|
|
72
|
+
## 0.3.2 (broken — DO NOT USE)
|
|
73
|
+
|
|
74
|
+
### Patch Changes
|
|
75
|
+
|
|
76
|
+
- Fix: Text-size levels (`oks-zoom-1` through `oks-zoom-4`) blew up the layout exponentially.
|
|
77
|
+
|
|
78
|
+
The previous rules applied `font-size: 1.20em !important` to every descendant of `<body>` via `*`. Since `em` is relative to the parent, doing that at every nesting level compounded the factor — a heading three levels deep ended up at `1.20³ = 1.73×` its intended size, which is why headings spilled out of the viewport at level 3 and the page became unusable at level 4.
|
|
79
|
+
|
|
80
|
+
New rules target the `<body>` only with percentage values (10 / 20 / 35 / 50%). `font-size` inherits natively, so descendants using `em` or `rem` scale exactly once. Hard-coded `px` values are intentionally left alone — that's what the browser's own zoom is for.
|
|
81
|
+
|
|
82
|
+
No new API. No behavioural change when the controls are off.
|
|
83
|
+
|
|
84
|
+
## 0.3.1
|
|
85
|
+
|
|
86
|
+
### Patch Changes
|
|
87
|
+
|
|
88
|
+
- Fix: reading guide painted a solid black band on top of the text when **High contrast** was also active.
|
|
89
|
+
|
|
90
|
+
The high-contrast mode flips every descendant of `<body>` to `background-color: #000 !important; color: #ff0`. That selector was also catching the reading-guide overlay (`.oks-reading-guide`), overriding its semi-transparent yellow with an opaque black, which defeated the purpose of the feature.
|
|
91
|
+
|
|
92
|
+
Two corrective rules added right after the high-contrast block: the reading guide keeps its translucent yellow background and gets `#ff0` borders (visible on the new black page), and `.oks-overlay-effect` is forced back to `transparent` for the same reason.
|
|
93
|
+
|
|
94
|
+
No behavioural change when high-contrast is off. No new API.
|
|
95
|
+
|
|
96
|
+
## 0.3.0
|
|
97
|
+
|
|
98
|
+
### Minor Changes
|
|
99
|
+
|
|
100
|
+
- Expose `--oks-z` CSS custom property to control the trigger and panel z-index from outside the Shadow DOM.
|
|
101
|
+
|
|
102
|
+
Default unchanged (`9999999`). Consumers can lower it to sit below specific modals, or raise it to outrank other floating widgets:
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
oksigenia-access-panel {
|
|
106
|
+
--oks-z: 99999;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
This makes the z-index deterministic across browsers — previously, attempts to control the trigger's stacking from outside via the host element's z-index were best-effort because the trigger is `position: fixed` inside the Shadow DOM and creates its own stacking context.
|
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
|
|
@@ -103,6 +107,30 @@ If you need to brand the panel itself, fork the package and customize
|
|
|
103
107
|
<oksigenia-access-panel locale="es-PY"></oksigenia-access-panel>
|
|
104
108
|
```
|
|
105
109
|
|
|
110
|
+
## Use it in Ghost (CMS)
|
|
111
|
+
|
|
112
|
+
Ghost has no plugin system for frontend components, but Code Injection
|
|
113
|
+
covers this case in one snippet. In the admin, go to **Settings → Code
|
|
114
|
+
injection → Site Footer** and paste:
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<oksigenia-access-panel locale="en" position="bottom-left"></oksigenia-access-panel>
|
|
118
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@oksigenia/access-panel/dist/web-component.js"></script>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Save. Reload any page on the site — the floating trigger appears.
|
|
122
|
+
Same attributes as above (`locale`, `position`, `trigger-icon`, etc.)
|
|
123
|
+
work as inline attributes on the tag.
|
|
124
|
+
|
|
125
|
+
The snippet above loads the bundle from jsDelivr, which logs requests
|
|
126
|
+
like any third-party CDN. To keep everything first-party, download
|
|
127
|
+
`dist/web-component.js` from npm or GitHub, upload it as a theme asset
|
|
128
|
+
(`assets/access-panel.js` in your active Ghost theme), and point the
|
|
129
|
+
`<script src=…>` at your own domain. Same component, no third-party hop.
|
|
130
|
+
|
|
131
|
+
Discussion on the Ghost forum (questions, issues, feedback):
|
|
132
|
+
<https://forum.ghost.org/t/accessibility-panel-for-ghost-via-code-injection-web-component-45-kb-no-tracking/62940>.
|
|
133
|
+
|
|
106
134
|
## Low-level building blocks
|
|
107
135
|
|
|
108
136
|
If you want to render the panel manually or write your own behavior
|
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 };
|