accessify-widget 0.1.0 → 0.2.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/README.md +57 -3
- package/dist/accessify.min.js +1 -1
- package/dist/accessify.min.js.map +1 -1
- package/dist/accessify.mjs +1 -1
- package/dist/{alt-text-CLxbmwG6.js → alt-text-CgzNGvdT.js} +2 -2
- package/dist/{alt-text-CLxbmwG6.js.map → alt-text-CgzNGvdT.js.map} +1 -1
- package/dist/contrast-CqsICAkU.js +139 -0
- package/dist/contrast-CqsICAkU.js.map +1 -0
- package/dist/{index-CUQfpnwR.js → index-qmiN2JAz.js} +1811 -736
- package/dist/index-qmiN2JAz.js.map +1 -0
- package/dist/{keyboard-nav-BdPyLaZt.js → keyboard-nav-DH4qBThF.js} +16 -12
- package/dist/keyboard-nav-DH4qBThF.js.map +1 -0
- package/dist/{page-structure-2X8mOSpC.js → page-structure-DTBqkrYs.js} +11 -7
- package/dist/page-structure-DTBqkrYs.js.map +1 -0
- package/dist/text-size-C6OFhCGi.js +186 -0
- package/dist/text-size-C6OFhCGi.js.map +1 -0
- package/dist/widget.js +1 -1
- package/dist/widget.js.map +1 -1
- package/package.json +1 -1
- package/dist/color-blind-0LFng55r.js +0 -108
- package/dist/color-blind-0LFng55r.js.map +0 -1
- package/dist/contrast-DCkE0NXZ.js +0 -64
- package/dist/contrast-DCkE0NXZ.js.map +0 -1
- package/dist/dyslexia-font-wONgIy2T.js +0 -77
- package/dist/dyslexia-font-wONgIy2T.js.map +0 -1
- package/dist/index-CUQfpnwR.js.map +0 -1
- package/dist/keyboard-nav-BdPyLaZt.js.map +0 -1
- package/dist/line-height-BT98qgEF.js +0 -54
- package/dist/line-height-BT98qgEF.js.map +0 -1
- package/dist/page-structure-2X8mOSpC.js.map +0 -1
- package/dist/saturation-D8ZXpWAN.js +0 -59
- package/dist/saturation-D8ZXpWAN.js.map +0 -1
- package/dist/spacing-DENai3JU.js +0 -106
- package/dist/spacing-DENai3JU.js.map +0 -1
- package/dist/text-align-BDRPqPvl.js +0 -51
- package/dist/text-align-BDRPqPvl.js.map +0 -1
- package/dist/text-size-B-uv436p.js +0 -69
- package/dist/text-size-B-uv436p.js.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t, g as getCurrentWidgetLang } from "./index-qmiN2JAz.js";
|
|
1
2
|
function createKeyboardNavModule() {
|
|
2
3
|
let enabled = false;
|
|
3
4
|
const STYLE_ID = "accessify-keyboard-nav";
|
|
@@ -9,6 +10,9 @@ function createKeyboardNavModule() {
|
|
|
9
10
|
let headings = [];
|
|
10
11
|
let landmarks = [];
|
|
11
12
|
let helpOverlayVisible = false;
|
|
13
|
+
function lang() {
|
|
14
|
+
return getCurrentWidgetLang();
|
|
15
|
+
}
|
|
12
16
|
function findMainContent() {
|
|
13
17
|
return document.querySelector("main") || document.getElementById("content") || document.getElementById("main-content") || document.querySelector('[role="main"]') || document.querySelector("h1");
|
|
14
18
|
}
|
|
@@ -32,7 +36,7 @@ function createKeyboardNavModule() {
|
|
|
32
36
|
const skipLink = document.createElement("a");
|
|
33
37
|
skipLink.id = SKIP_LINK_ID;
|
|
34
38
|
skipLink.href = `#${target.id}`;
|
|
35
|
-
skipLink.textContent = "
|
|
39
|
+
skipLink.textContent = t("keyboard.skipToContent", lang());
|
|
36
40
|
skipLink.addEventListener("click", (e) => {
|
|
37
41
|
e.preventDefault();
|
|
38
42
|
target.setAttribute("tabindex", "-1");
|
|
@@ -100,7 +104,7 @@ function createKeyboardNavModule() {
|
|
|
100
104
|
const overlay = document.createElement("div");
|
|
101
105
|
overlay.id = OVERLAY_ID;
|
|
102
106
|
overlay.setAttribute("role", "dialog");
|
|
103
|
-
overlay.setAttribute("aria-label", "
|
|
107
|
+
overlay.setAttribute("aria-label", t("keyboard.shortcuts", lang()));
|
|
104
108
|
overlay.setAttribute("aria-modal", "true");
|
|
105
109
|
overlay.innerHTML = `
|
|
106
110
|
<div style="
|
|
@@ -113,41 +117,41 @@ function createKeyboardNavModule() {
|
|
|
113
117
|
max-width: 480px; width: 90%; max-height: 80vh; overflow-y: auto;
|
|
114
118
|
box-shadow: 0 8px 32px rgba(0,0,0,0.3); font-family: system-ui, sans-serif;
|
|
115
119
|
" role="document">
|
|
116
|
-
<h2 style="margin: 0 0 16px; font-size: 20px; color: #1a73e8;"
|
|
120
|
+
<h2 style="margin: 0 0 16px; font-size: 20px; color: #1a73e8;">${t("keyboard.shortcuts", lang())}</h2>
|
|
117
121
|
<table style="width: 100%; border-collapse: collapse; font-size: 14px;">
|
|
118
122
|
<thead>
|
|
119
123
|
<tr style="border-bottom: 2px solid #e0e0e0;">
|
|
120
|
-
<th style="text-align: left; padding: 8px 12px;"
|
|
121
|
-
<th style="text-align: left; padding: 8px 12px;"
|
|
124
|
+
<th style="text-align: left; padding: 8px 12px;">${t("keyboard.shortcut", lang())}</th>
|
|
125
|
+
<th style="text-align: left; padding: 8px 12px;">${t("keyboard.action", lang())}</th>
|
|
122
126
|
</tr>
|
|
123
127
|
</thead>
|
|
124
128
|
<tbody>
|
|
125
129
|
<tr style="border-bottom: 1px solid #f0f0f0;">
|
|
126
130
|
<td style="padding: 8px 12px;"><kbd style="background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;">Alt + H</kbd></td>
|
|
127
|
-
<td style="padding: 8px 12px;"
|
|
131
|
+
<td style="padding: 8px 12px;">${t("keyboard.nextHeading", lang())}</td>
|
|
128
132
|
</tr>
|
|
129
133
|
<tr style="border-bottom: 1px solid #f0f0f0;">
|
|
130
134
|
<td style="padding: 8px 12px;"><kbd style="background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;">Alt + L</kbd></td>
|
|
131
|
-
<td style="padding: 8px 12px;"
|
|
135
|
+
<td style="padding: 8px 12px;">${t("keyboard.nextLandmark", lang())}</td>
|
|
132
136
|
</tr>
|
|
133
137
|
<tr style="border-bottom: 1px solid #f0f0f0;">
|
|
134
138
|
<td style="padding: 8px 12px;"><kbd style="background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;">Alt + K</kbd></td>
|
|
135
|
-
<td style="padding: 8px 12px;"
|
|
139
|
+
<td style="padding: 8px 12px;">${t("keyboard.toggleHelp", lang())}</td>
|
|
136
140
|
</tr>
|
|
137
141
|
<tr style="border-bottom: 1px solid #f0f0f0;">
|
|
138
142
|
<td style="padding: 8px 12px;"><kbd style="background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;">Tab</kbd></td>
|
|
139
|
-
<td style="padding: 8px 12px;"
|
|
143
|
+
<td style="padding: 8px 12px;">${t("keyboard.nextFocusable", lang())}</td>
|
|
140
144
|
</tr>
|
|
141
145
|
<tr>
|
|
142
146
|
<td style="padding: 8px 12px;"><kbd style="background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;">Escape</kbd></td>
|
|
143
|
-
<td style="padding: 8px 12px;"
|
|
147
|
+
<td style="padding: 8px 12px;">${t("keyboard.closeOverlay", lang())}</td>
|
|
144
148
|
</tr>
|
|
145
149
|
</tbody>
|
|
146
150
|
</table>
|
|
147
151
|
<button style="
|
|
148
152
|
margin-top: 20px; padding: 8px 24px; background: #1a73e8; color: #fff;
|
|
149
153
|
border: none; border-radius: 6px; cursor: pointer; font-size: 14px;
|
|
150
|
-
" id="accessify-keyboard-help-close"
|
|
154
|
+
" id="accessify-keyboard-help-close">${t("widget.close", lang())}</button>
|
|
151
155
|
</div>
|
|
152
156
|
</div>
|
|
153
157
|
`;
|
|
@@ -309,4 +313,4 @@ function createKeyboardNavModule() {
|
|
|
309
313
|
export {
|
|
310
314
|
createKeyboardNavModule as default
|
|
311
315
|
};
|
|
312
|
-
//# sourceMappingURL=keyboard-nav-
|
|
316
|
+
//# sourceMappingURL=keyboard-nav-DH4qBThF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard-nav-DH4qBThF.js","sources":["../src/features/keyboard-nav.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\nimport { getCurrentWidgetLang, t } from '../i18n/index';\n\nexport default function createKeyboardNavModule(): FeatureModule {\n let enabled = false;\n const STYLE_ID = 'accessify-keyboard-nav';\n const SKIP_LINK_ID = 'accessify-skip-link';\n const OVERLAY_ID = 'accessify-keyboard-help';\n const STORAGE_KEY = 'accessify-keyboard-nav';\n\n let headingIndex = -1;\n let landmarkIndex = -1;\n let headings: HTMLElement[] = [];\n let landmarks: HTMLElement[] = [];\n let helpOverlayVisible = false;\n\n function lang(): string {\n return getCurrentWidgetLang();\n }\n\n // --- Skip-to-content link ---\n\n function findMainContent(): HTMLElement | null {\n return (\n document.querySelector('main') ||\n document.getElementById('content') ||\n document.getElementById('main-content') ||\n document.querySelector('[role=\"main\"]') ||\n document.querySelector('h1')\n );\n }\n\n function hasSkipLink(): boolean {\n const links = document.querySelectorAll('a[href^=\"#\"]');\n for (const link of links) {\n const text = (link as HTMLElement).textContent?.toLowerCase() || '';\n if (text.includes('skip') || text.includes('main content') || text.includes('navigation')) {\n return true;\n }\n }\n return false;\n }\n\n function injectSkipLink() {\n if (hasSkipLink()) return;\n const target = findMainContent();\n if (!target) return;\n\n // Ensure target has an ID for the skip link to reference\n if (!target.id) {\n target.id = 'accessify-main-content';\n }\n\n const skipLink = document.createElement('a');\n skipLink.id = SKIP_LINK_ID;\n skipLink.href = `#${target.id}`;\n skipLink.textContent = t('keyboard.skipToContent', lang());\n skipLink.addEventListener('click', (e) => {\n e.preventDefault();\n target.setAttribute('tabindex', '-1');\n target.focus();\n target.scrollIntoView({ behavior: 'smooth', block: 'start' });\n });\n\n document.body.insertBefore(skipLink, document.body.firstChild);\n }\n\n function removeSkipLink() {\n const skipLink = document.getElementById(SKIP_LINK_ID);\n skipLink?.remove();\n }\n\n // --- Heading navigation (Alt+H) ---\n\n function collectHeadings() {\n headings = Array.from(\n document.querySelectorAll<HTMLElement>('h1, h2, h3, h4, h5, h6')\n ).filter((el) => {\n // Only visible headings\n const style = window.getComputedStyle(el);\n return style.display !== 'none' && style.visibility !== 'hidden';\n });\n }\n\n function navigateToNextHeading() {\n collectHeadings();\n if (headings.length === 0) return;\n headingIndex = (headingIndex + 1) % headings.length;\n const heading = headings[headingIndex];\n heading.setAttribute('tabindex', '-1');\n heading.focus();\n heading.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n\n // --- Landmark navigation (Alt+L) ---\n\n function collectLandmarks() {\n const selectors = [\n 'header, [role=\"banner\"]',\n 'nav, [role=\"navigation\"]',\n 'main, [role=\"main\"]',\n 'aside, [role=\"complementary\"]',\n '[role=\"search\"]',\n '[role=\"form\"]',\n 'footer, [role=\"contentinfo\"]',\n '[role=\"region\"][aria-label]',\n ];\n landmarks = Array.from(\n document.querySelectorAll<HTMLElement>(selectors.join(', '))\n ).filter((el) => {\n const style = window.getComputedStyle(el);\n return style.display !== 'none' && style.visibility !== 'hidden';\n });\n }\n\n function navigateToNextLandmark() {\n collectLandmarks();\n if (landmarks.length === 0) return;\n landmarkIndex = (landmarkIndex + 1) % landmarks.length;\n const landmark = landmarks[landmarkIndex];\n landmark.setAttribute('tabindex', '-1');\n landmark.focus();\n landmark.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n\n // --- Keyboard shortcut help overlay (Alt+K) ---\n\n function toggleHelpOverlay() {\n const existing = document.getElementById(OVERLAY_ID);\n if (existing) {\n existing.remove();\n helpOverlayVisible = false;\n return;\n }\n\n helpOverlayVisible = true;\n const overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n overlay.setAttribute('role', 'dialog');\n overlay.setAttribute('aria-label', t('keyboard.shortcuts', lang()));\n overlay.setAttribute('aria-modal', 'true');\n\n overlay.innerHTML = `\n <div style=\"\n position: fixed; inset: 0; background: rgba(0,0,0,0.6);\n display: flex; align-items: center; justify-content: center;\n z-index: 2147483647;\n \">\n <div style=\"\n background: #fff; color: #222; border-radius: 12px; padding: 32px;\n max-width: 480px; width: 90%; max-height: 80vh; overflow-y: auto;\n box-shadow: 0 8px 32px rgba(0,0,0,0.3); font-family: system-ui, sans-serif;\n \" role=\"document\">\n <h2 style=\"margin: 0 0 16px; font-size: 20px; color: #1a73e8;\">${t('keyboard.shortcuts', lang())}</h2>\n <table style=\"width: 100%; border-collapse: collapse; font-size: 14px;\">\n <thead>\n <tr style=\"border-bottom: 2px solid #e0e0e0;\">\n <th style=\"text-align: left; padding: 8px 12px;\">${t('keyboard.shortcut', lang())}</th>\n <th style=\"text-align: left; padding: 8px 12px;\">${t('keyboard.action', lang())}</th>\n </tr>\n </thead>\n <tbody>\n <tr style=\"border-bottom: 1px solid #f0f0f0;\">\n <td style=\"padding: 8px 12px;\"><kbd style=\"background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;\">Alt + H</kbd></td>\n <td style=\"padding: 8px 12px;\">${t('keyboard.nextHeading', lang())}</td>\n </tr>\n <tr style=\"border-bottom: 1px solid #f0f0f0;\">\n <td style=\"padding: 8px 12px;\"><kbd style=\"background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;\">Alt + L</kbd></td>\n <td style=\"padding: 8px 12px;\">${t('keyboard.nextLandmark', lang())}</td>\n </tr>\n <tr style=\"border-bottom: 1px solid #f0f0f0;\">\n <td style=\"padding: 8px 12px;\"><kbd style=\"background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;\">Alt + K</kbd></td>\n <td style=\"padding: 8px 12px;\">${t('keyboard.toggleHelp', lang())}</td>\n </tr>\n <tr style=\"border-bottom: 1px solid #f0f0f0;\">\n <td style=\"padding: 8px 12px;\"><kbd style=\"background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;\">Tab</kbd></td>\n <td style=\"padding: 8px 12px;\">${t('keyboard.nextFocusable', lang())}</td>\n </tr>\n <tr>\n <td style=\"padding: 8px 12px;\"><kbd style=\"background:#f5f5f5;padding:2px 8px;border-radius:4px;border:1px solid #ccc;font-family:monospace;\">Escape</kbd></td>\n <td style=\"padding: 8px 12px;\">${t('keyboard.closeOverlay', lang())}</td>\n </tr>\n </tbody>\n </table>\n <button style=\"\n margin-top: 20px; padding: 8px 24px; background: #1a73e8; color: #fff;\n border: none; border-radius: 6px; cursor: pointer; font-size: 14px;\n \" id=\"accessify-keyboard-help-close\">${t('widget.close', lang())}</button>\n </div>\n </div>\n `;\n\n document.body.appendChild(overlay);\n\n // Focus management for the dialog\n const closeBtn = document.getElementById('accessify-keyboard-help-close');\n closeBtn?.focus();\n closeBtn?.addEventListener('click', () => {\n overlay.remove();\n helpOverlayVisible = false;\n });\n }\n\n // --- Tabindex injection for interactive elements ---\n\n function injectTabindex() {\n const selectors = [\n 'a[href]',\n 'button',\n 'input',\n 'select',\n 'textarea',\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[role=\"tab\"]',\n '[role=\"menuitem\"]',\n '[role=\"switch\"]',\n '[contenteditable=\"true\"]',\n 'summary',\n ];\n\n const elements = document.querySelectorAll<HTMLElement>(selectors.join(', '));\n elements.forEach((el) => {\n // Only add tabindex if the element is not already focusable via native mechanism\n // and does not already have an explicit tabindex\n if (!el.hasAttribute('tabindex') && !isNativelyFocusable(el)) {\n el.setAttribute('tabindex', '0');\n el.dataset.accessifyTabindex = 'true';\n }\n });\n }\n\n function removeInjectedTabindex() {\n const elements = document.querySelectorAll<HTMLElement>('[data-accessify-tabindex=\"true\"]');\n elements.forEach((el) => {\n el.removeAttribute('tabindex');\n delete el.dataset.accessifyTabindex;\n });\n }\n\n function isNativelyFocusable(el: HTMLElement): boolean {\n const tag = el.tagName.toLowerCase();\n if (['a', 'button', 'input', 'select', 'textarea'].includes(tag)) {\n return true;\n }\n if (tag === 'a' && !(el as HTMLAnchorElement).href) {\n return false;\n }\n return false;\n }\n\n // --- Keyboard event handler ---\n\n function handleKeyDown(e: KeyboardEvent) {\n if (!enabled) return;\n\n // Close help overlay on Escape\n if (e.key === 'Escape' && helpOverlayVisible) {\n const overlay = document.getElementById(OVERLAY_ID);\n overlay?.remove();\n helpOverlayVisible = false;\n return;\n }\n\n if (!e.altKey) return;\n\n switch (e.key.toLowerCase()) {\n case 'h':\n e.preventDefault();\n navigateToNextHeading();\n break;\n case 'l':\n e.preventDefault();\n navigateToNextLandmark();\n break;\n case 'k':\n e.preventDefault();\n toggleHelpOverlay();\n break;\n }\n }\n\n // --- Styles for skip link ---\n\n function getStyles(): string {\n return `\n /* accessify keyboard navigation */\n #${SKIP_LINK_ID} {\n position: fixed;\n top: -100px;\n left: 50%;\n transform: translateX(-50%);\n background: #1a73e8;\n color: #fff;\n padding: 12px 24px;\n border-radius: 0 0 8px 8px;\n font-size: 16px;\n font-family: system-ui, sans-serif;\n text-decoration: none;\n z-index: 2147483647;\n transition: top 0.2s ease;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n }\n #${SKIP_LINK_ID}:focus {\n top: 0;\n outline: 3px solid #ffdd00;\n outline-offset: 2px;\n }\n `;\n }\n\n function injectStyles() {\n let styleEl = document.getElementById(STYLE_ID);\n if (!styleEl) {\n styleEl = document.createElement('style');\n styleEl.id = STYLE_ID;\n document.head.appendChild(styleEl);\n }\n styleEl.textContent = getStyles();\n }\n\n function removeStyles() {\n const styleEl = document.getElementById(STYLE_ID);\n styleEl?.remove();\n }\n\n // --- Module lifecycle ---\n\n function activate() {\n enabled = true;\n headingIndex = -1;\n landmarkIndex = -1;\n\n injectStyles();\n injectSkipLink();\n injectTabindex();\n document.addEventListener('keydown', handleKeyDown);\n localStorage.setItem(STORAGE_KEY, 'true');\n }\n\n function deactivate() {\n enabled = false;\n helpOverlayVisible = false;\n\n document.removeEventListener('keydown', handleKeyDown);\n removeSkipLink();\n removeInjectedTabindex();\n removeStyles();\n\n const overlay = document.getElementById(OVERLAY_ID);\n overlay?.remove();\n\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'keyboard-nav',\n name: () => 'Keyboard Navigation',\n description: 'Enhanced keyboard navigation with skip links, heading/landmark jumping, and shortcut help',\n icon: 'keyboard-nav',\n category: 'motor',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'keyboard-nav',\n enabled,\n }),\n setState: (state: { enabled: boolean }) => {\n if (state.enabled) {\n activate();\n } else {\n deactivate();\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { t, g as getCurrentWidgetLang } from "./index-qmiN2JAz.js";
|
|
1
2
|
function createPageStructureModule() {
|
|
2
3
|
let enabled = false;
|
|
3
4
|
let panelEl = null;
|
|
4
5
|
const PANEL_ID = "accessify-page-structure";
|
|
6
|
+
function lang() {
|
|
7
|
+
return getCurrentWidgetLang();
|
|
8
|
+
}
|
|
5
9
|
function collectHeadings() {
|
|
6
10
|
const results = [];
|
|
7
11
|
const headings = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
|
@@ -42,7 +46,7 @@ function createPageStructureModule() {
|
|
|
42
46
|
panelEl = document.createElement("div");
|
|
43
47
|
panelEl.id = PANEL_ID;
|
|
44
48
|
panelEl.setAttribute("role", "dialog");
|
|
45
|
-
panelEl.setAttribute("aria-label", "
|
|
49
|
+
panelEl.setAttribute("aria-label", t("pageStructure.title", lang()));
|
|
46
50
|
const headings = collectHeadings();
|
|
47
51
|
const landmarks = collectLandmarks();
|
|
48
52
|
const indent = {
|
|
@@ -91,11 +95,11 @@ function createPageStructureModule() {
|
|
|
91
95
|
#${PANEL_ID} .ps-close:hover { background: #2a2a2e; }
|
|
92
96
|
}
|
|
93
97
|
</style>
|
|
94
|
-
<button class="ps-close" aria-label="
|
|
95
|
-
<h3
|
|
98
|
+
<button class="ps-close" aria-label="${t("widget.close", lang())}">×</button>
|
|
99
|
+
<h3>${t("pageStructure.title", lang())}</h3>
|
|
96
100
|
`;
|
|
97
101
|
if (headings.length > 0) {
|
|
98
|
-
html +=
|
|
102
|
+
html += `<div class="ps-section"><div class="ps-label">${t("pageStructure.headings", lang())}</div>`;
|
|
99
103
|
headings.forEach((h, i) => {
|
|
100
104
|
html += `<button class="ps-item" data-type="heading" data-index="${i}" style="padding-left:${indent[h.tag] || "0"}">
|
|
101
105
|
<span class="ps-tag">${h.tag}</span>${escapeHtml(h.text.slice(0, 80))}
|
|
@@ -104,7 +108,7 @@ function createPageStructureModule() {
|
|
|
104
108
|
html += "</div>";
|
|
105
109
|
}
|
|
106
110
|
if (landmarks.length > 0) {
|
|
107
|
-
html +=
|
|
111
|
+
html += `<div class="ps-section"><div class="ps-label">${t("pageStructure.landmarks", lang())}</div>`;
|
|
108
112
|
landmarks.forEach((lm, i) => {
|
|
109
113
|
html += `<button class="ps-item" data-type="landmark" data-index="${i}">
|
|
110
114
|
<span class="ps-tag">${escapeHtml(lm.role)}</span>${escapeHtml(lm.label.slice(0, 60))}
|
|
@@ -113,7 +117,7 @@ function createPageStructureModule() {
|
|
|
113
117
|
html += "</div>";
|
|
114
118
|
}
|
|
115
119
|
if (headings.length === 0 && landmarks.length === 0) {
|
|
116
|
-
html +=
|
|
120
|
+
html += `<p style="color:#888">${t("pageStructure.empty", lang())}</p>`;
|
|
117
121
|
}
|
|
118
122
|
panelEl.innerHTML = html;
|
|
119
123
|
panelEl.addEventListener("click", (e) => {
|
|
@@ -163,4 +167,4 @@ function createPageStructureModule() {
|
|
|
163
167
|
export {
|
|
164
168
|
createPageStructureModule as default
|
|
165
169
|
};
|
|
166
|
-
//# sourceMappingURL=page-structure-
|
|
170
|
+
//# sourceMappingURL=page-structure-DTBqkrYs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-structure-DTBqkrYs.js","sources":["../src/features/page-structure.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\nimport { getCurrentWidgetLang, t } from '../i18n/index';\n\nexport default function createPageStructureModule(): FeatureModule {\n let enabled = false;\n let panelEl: HTMLElement | null = null;\n const PANEL_ID = 'accessify-page-structure';\n\n function lang(): string {\n return getCurrentWidgetLang();\n }\n\n function collectHeadings(): Array<{ tag: string; text: string; el: HTMLElement }> {\n const results: Array<{ tag: string; text: string; el: HTMLElement }> = [];\n const headings = document.querySelectorAll<HTMLElement>('h1, h2, h3, h4, h5, h6');\n headings.forEach((el) => {\n if (el.closest('#accessify-root')) return;\n const text = el.textContent?.trim() || '';\n if (text) results.push({ tag: el.tagName.toLowerCase(), text, el });\n });\n return results;\n }\n\n function collectLandmarks(): Array<{ role: string; label: string; el: HTMLElement }> {\n const results: Array<{ role: string; label: string; el: HTMLElement }> = [];\n const selectors = [\n 'main', 'nav', 'aside', 'header', 'footer', 'section[aria-label]',\n 'section[aria-labelledby]', '[role=\"main\"]', '[role=\"navigation\"]',\n '[role=\"complementary\"]', '[role=\"banner\"]', '[role=\"contentinfo\"]',\n '[role=\"search\"]',\n ];\n const els = document.querySelectorAll<HTMLElement>(selectors.join(','));\n els.forEach((el) => {\n if (el.closest('#accessify-root')) return;\n const role = el.getAttribute('role') || el.tagName.toLowerCase();\n const label = el.getAttribute('aria-label') || el.getAttribute('aria-labelledby') || role;\n results.push({ role, label, el });\n });\n return results;\n }\n\n function buildPanel() {\n panelEl = document.createElement('div');\n panelEl.id = PANEL_ID;\n panelEl.setAttribute('role', 'dialog');\n panelEl.setAttribute('aria-label', t('pageStructure.title', lang()));\n\n const headings = collectHeadings();\n const landmarks = collectLandmarks();\n\n const indent: Record<string, string> = {\n h1: '0', h2: '12px', h3: '24px', h4: '36px', h5: '48px', h6: '60px',\n };\n\n let html = `\n <style>\n #${PANEL_ID} {\n position: fixed; top: 50%; left: 50%;\n transform: translate(-50%, -50%);\n z-index: 999998;\n background: #fff; color: #1a1a1a;\n border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.2);\n padding: 24px; width: 400px; max-height: 80vh;\n overflow-y: auto; font-family: system-ui, sans-serif;\n font-size: 14px; line-height: 1.5;\n }\n #${PANEL_ID} h3 { margin: 0 0 12px; font-size: 16px; }\n #${PANEL_ID} .ps-section { margin-bottom: 16px; }\n #${PANEL_ID} .ps-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: #888; margin-bottom: 6px; }\n #${PANEL_ID} .ps-item {\n display: block; width: 100%; text-align: left;\n padding: 6px 8px; border: none; background: none;\n cursor: pointer; border-radius: 6px; font-size: 13px;\n color: #1a1a1a; font-family: inherit;\n }\n #${PANEL_ID} .ps-item:hover { background: #f0f0f2; }\n #${PANEL_ID} .ps-item:focus-visible { outline: 2px solid #0055CC; outline-offset: 1px; }\n #${PANEL_ID} .ps-tag { color: #888; font-size: 11px; margin-right: 6px; }\n #${PANEL_ID} .ps-close {\n position: absolute; top: 12px; right: 12px;\n background: none; border: none; cursor: pointer;\n font-size: 18px; color: #888; padding: 4px 8px; border-radius: 4px;\n }\n #${PANEL_ID} .ps-close:hover { background: #f0f0f2; }\n @media (prefers-color-scheme: dark) {\n #${PANEL_ID} { background: #1a1a1a; color: #f0f0f0; }\n #${PANEL_ID} .ps-item { color: #f0f0f0; }\n #${PANEL_ID} .ps-item:hover { background: #2a2a2e; }\n #${PANEL_ID} .ps-close { color: #aaa; }\n #${PANEL_ID} .ps-close:hover { background: #2a2a2e; }\n }\n </style>\n <button class=\"ps-close\" aria-label=\"${t('widget.close', lang())}\">×</button>\n <h3>${t('pageStructure.title', lang())}</h3>\n `;\n\n if (headings.length > 0) {\n html += `<div class=\"ps-section\"><div class=\"ps-label\">${t('pageStructure.headings', lang())}</div>`;\n headings.forEach((h, i) => {\n html += `<button class=\"ps-item\" data-type=\"heading\" data-index=\"${i}\" style=\"padding-left:${indent[h.tag] || '0'}\">\n <span class=\"ps-tag\">${h.tag}</span>${escapeHtml(h.text.slice(0, 80))}\n </button>`;\n });\n html += '</div>';\n }\n\n if (landmarks.length > 0) {\n html += `<div class=\"ps-section\"><div class=\"ps-label\">${t('pageStructure.landmarks', lang())}</div>`;\n landmarks.forEach((lm, i) => {\n html += `<button class=\"ps-item\" data-type=\"landmark\" data-index=\"${i}\">\n <span class=\"ps-tag\">${escapeHtml(lm.role)}</span>${escapeHtml(lm.label.slice(0, 60))}\n </button>`;\n });\n html += '</div>';\n }\n\n if (headings.length === 0 && landmarks.length === 0) {\n html += `<p style=\"color:#888\">${t('pageStructure.empty', lang())}</p>`;\n }\n\n panelEl.innerHTML = html;\n\n // Event delegation\n panelEl.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest<HTMLElement>('.ps-item');\n if (btn) {\n const type = btn.dataset.type;\n const idx = parseInt(btn.dataset.index || '0', 10);\n let target: HTMLElement | undefined;\n if (type === 'heading') target = headings[idx]?.el;\n else if (type === 'landmark') target = landmarks[idx]?.el;\n if (target) {\n target.scrollIntoView({ behavior: 'smooth', block: 'center' });\n target.focus({ preventScroll: true });\n }\n }\n if ((e.target as HTMLElement).closest('.ps-close')) {\n deactivate();\n }\n });\n\n document.body.appendChild(panelEl);\n const firstBtn = panelEl.querySelector<HTMLElement>('.ps-item, .ps-close');\n firstBtn?.focus();\n }\n\n function escapeHtml(str: string): string {\n return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n }\n\n function activate() {\n enabled = true;\n buildPanel();\n }\n\n function deactivate() {\n enabled = false;\n panelEl?.remove();\n panelEl = null;\n }\n\n return {\n id: 'page-structure',\n name: () => 'Page Structure',\n description: 'View headings and landmarks for quick navigation',\n icon: 'page-structure',\n category: 'motor',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'page-structure', enabled }),\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
function createTextSizeModule() {
|
|
2
|
+
let currentSize = 100;
|
|
3
|
+
let observer = null;
|
|
4
|
+
let refreshQueued = false;
|
|
5
|
+
const STYLE_ID = "accessify-text-size-styles";
|
|
6
|
+
const STORAGE_KEY = "accessify-text-size";
|
|
7
|
+
const PROCESSED_ATTR = "data-accessify-text-size-processed";
|
|
8
|
+
const ORIGINAL_INLINE_ATTR = "data-accessify-original-inline-font-size";
|
|
9
|
+
const ORIGINAL_COMPUTED_ATTR = "data-accessify-original-computed-font-size";
|
|
10
|
+
const MIN_SIZE = 100;
|
|
11
|
+
const MAX_SIZE = 200;
|
|
12
|
+
const STEP = 10;
|
|
13
|
+
const SKIP_TAGS = /* @__PURE__ */ new Set([
|
|
14
|
+
"SCRIPT",
|
|
15
|
+
"STYLE",
|
|
16
|
+
"NOSCRIPT",
|
|
17
|
+
"IFRAME",
|
|
18
|
+
"SVG",
|
|
19
|
+
"PATH",
|
|
20
|
+
"G",
|
|
21
|
+
"DEFS",
|
|
22
|
+
"MASK",
|
|
23
|
+
"BR",
|
|
24
|
+
"META",
|
|
25
|
+
"LINK",
|
|
26
|
+
"HEAD"
|
|
27
|
+
]);
|
|
28
|
+
function ensureStyleMarker(percent) {
|
|
29
|
+
let styleEl = document.getElementById(STYLE_ID);
|
|
30
|
+
if (!styleEl) {
|
|
31
|
+
styleEl = document.createElement("style");
|
|
32
|
+
styleEl.id = STYLE_ID;
|
|
33
|
+
document.head.appendChild(styleEl);
|
|
34
|
+
}
|
|
35
|
+
styleEl.textContent = `/* accessify text-size: ${percent}% */`;
|
|
36
|
+
}
|
|
37
|
+
function removeStyleMarker() {
|
|
38
|
+
document.getElementById(STYLE_ID)?.remove();
|
|
39
|
+
}
|
|
40
|
+
function hasOwnTextContent(el) {
|
|
41
|
+
return Array.from(el.childNodes).some((node) => {
|
|
42
|
+
return node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim());
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function shouldScaleElement(el) {
|
|
46
|
+
if (el.id === "accessify-root" || el.closest("#accessify-root")) return false;
|
|
47
|
+
if (SKIP_TAGS.has(el.tagName)) return false;
|
|
48
|
+
const computed = window.getComputedStyle(el);
|
|
49
|
+
const fontSize = parseFloat(computed.fontSize);
|
|
50
|
+
if (!Number.isFinite(fontSize) || fontSize <= 0) return false;
|
|
51
|
+
if (computed.display === "none" || computed.visibility === "hidden") return false;
|
|
52
|
+
const interactiveTags = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT", "BUTTON", "LABEL", "OPTION"]);
|
|
53
|
+
return interactiveTags.has(el.tagName) || hasOwnTextContent(el);
|
|
54
|
+
}
|
|
55
|
+
function getTargetElements() {
|
|
56
|
+
if (!document.body) return [];
|
|
57
|
+
const elements = [document.body, ...Array.from(document.body.querySelectorAll("*"))];
|
|
58
|
+
return elements.filter(shouldScaleElement);
|
|
59
|
+
}
|
|
60
|
+
function rememberOriginalSize(el) {
|
|
61
|
+
if (!el.hasAttribute(ORIGINAL_INLINE_ATTR)) {
|
|
62
|
+
el.setAttribute(ORIGINAL_INLINE_ATTR, el.style.fontSize || "");
|
|
63
|
+
}
|
|
64
|
+
if (!el.hasAttribute(ORIGINAL_COMPUTED_ATTR)) {
|
|
65
|
+
const computedSize = parseFloat(window.getComputedStyle(el).fontSize);
|
|
66
|
+
if (Number.isFinite(computedSize) && computedSize > 0) {
|
|
67
|
+
el.setAttribute(ORIGINAL_COMPUTED_ATTR, String(computedSize));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function scaleElement(el, scale) {
|
|
72
|
+
rememberOriginalSize(el);
|
|
73
|
+
const originalSize = parseFloat(el.getAttribute(ORIGINAL_COMPUTED_ATTR) || "");
|
|
74
|
+
if (!Number.isFinite(originalSize) || originalSize <= 0) return;
|
|
75
|
+
const nextSize = Math.round(originalSize * scale * 100) / 100;
|
|
76
|
+
el.style.setProperty("font-size", `${nextSize}px`, "important");
|
|
77
|
+
el.setAttribute(PROCESSED_ATTR, "true");
|
|
78
|
+
}
|
|
79
|
+
function restoreElement(el) {
|
|
80
|
+
const originalInline = el.getAttribute(ORIGINAL_INLINE_ATTR);
|
|
81
|
+
if (originalInline === null) return;
|
|
82
|
+
if (originalInline) {
|
|
83
|
+
el.style.fontSize = originalInline;
|
|
84
|
+
} else {
|
|
85
|
+
el.style.removeProperty("font-size");
|
|
86
|
+
}
|
|
87
|
+
el.removeAttribute(PROCESSED_ATTR);
|
|
88
|
+
el.removeAttribute(ORIGINAL_INLINE_ATTR);
|
|
89
|
+
el.removeAttribute(ORIGINAL_COMPUTED_ATTR);
|
|
90
|
+
}
|
|
91
|
+
function restoreProcessedElements() {
|
|
92
|
+
document.querySelectorAll(`[${PROCESSED_ATTR}]`).forEach((el) => {
|
|
93
|
+
restoreElement(el);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function queueRefresh() {
|
|
97
|
+
if (refreshQueued || currentSize === 100) return;
|
|
98
|
+
refreshQueued = true;
|
|
99
|
+
const flush = () => {
|
|
100
|
+
refreshQueued = false;
|
|
101
|
+
applySize(currentSize);
|
|
102
|
+
};
|
|
103
|
+
if (typeof window.requestAnimationFrame === "function") {
|
|
104
|
+
window.requestAnimationFrame(() => flush());
|
|
105
|
+
} else {
|
|
106
|
+
window.setTimeout(flush, 0);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function startObserver() {
|
|
110
|
+
if (observer || !document.body) return;
|
|
111
|
+
observer = new MutationObserver((mutations) => {
|
|
112
|
+
for (const mutation of mutations) {
|
|
113
|
+
if (mutation.type === "childList" && (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0)) {
|
|
114
|
+
queueRefresh();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
observer.observe(document.body, {
|
|
120
|
+
childList: true,
|
|
121
|
+
subtree: true
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function stopObserver() {
|
|
125
|
+
observer?.disconnect();
|
|
126
|
+
observer = null;
|
|
127
|
+
refreshQueued = false;
|
|
128
|
+
}
|
|
129
|
+
function applySize(percent) {
|
|
130
|
+
if (percent === 100) {
|
|
131
|
+
stopObserver();
|
|
132
|
+
removeStyleMarker();
|
|
133
|
+
restoreProcessedElements();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
ensureStyleMarker(percent);
|
|
137
|
+
const scale = percent / 100;
|
|
138
|
+
const targets = new Set(getTargetElements());
|
|
139
|
+
document.querySelectorAll(`[${PROCESSED_ATTR}]`).forEach((el) => {
|
|
140
|
+
if (!targets.has(el)) {
|
|
141
|
+
restoreElement(el);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
targets.forEach((el) => {
|
|
145
|
+
scaleElement(el, scale);
|
|
146
|
+
});
|
|
147
|
+
startObserver();
|
|
148
|
+
}
|
|
149
|
+
function clamp(value) {
|
|
150
|
+
return Math.min(MAX_SIZE, Math.max(MIN_SIZE, Math.round(value / STEP) * STEP));
|
|
151
|
+
}
|
|
152
|
+
function activate() {
|
|
153
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
154
|
+
currentSize = saved ? clamp(parseInt(saved, 10)) : 150;
|
|
155
|
+
applySize(currentSize);
|
|
156
|
+
localStorage.setItem(STORAGE_KEY, String(currentSize));
|
|
157
|
+
}
|
|
158
|
+
function deactivate() {
|
|
159
|
+
currentSize = 100;
|
|
160
|
+
applySize(100);
|
|
161
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
id: "text-size",
|
|
165
|
+
name: () => "Text Size",
|
|
166
|
+
description: "Adjust text size from 100% to 200%",
|
|
167
|
+
icon: "text-size",
|
|
168
|
+
category: "visual",
|
|
169
|
+
activate,
|
|
170
|
+
deactivate,
|
|
171
|
+
getState: () => ({
|
|
172
|
+
id: "text-size",
|
|
173
|
+
enabled: currentSize !== 100,
|
|
174
|
+
value: currentSize
|
|
175
|
+
}),
|
|
176
|
+
setState: (size) => {
|
|
177
|
+
currentSize = clamp(size);
|
|
178
|
+
applySize(currentSize);
|
|
179
|
+
localStorage.setItem(STORAGE_KEY, String(currentSize));
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
export {
|
|
184
|
+
createTextSizeModule as default
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=text-size-C6OFhCGi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-size-C6OFhCGi.js","sources":["../src/features/text-size.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\n\nexport default function createTextSizeModule(): FeatureModule {\n let currentSize = 100;\n let observer: MutationObserver | null = null;\n let refreshQueued = false;\n const STYLE_ID = 'accessify-text-size-styles';\n const STORAGE_KEY = 'accessify-text-size';\n const PROCESSED_ATTR = 'data-accessify-text-size-processed';\n const ORIGINAL_INLINE_ATTR = 'data-accessify-original-inline-font-size';\n const ORIGINAL_COMPUTED_ATTR = 'data-accessify-original-computed-font-size';\n const MIN_SIZE = 100;\n const MAX_SIZE = 200;\n const STEP = 10;\n const SKIP_TAGS = new Set([\n 'SCRIPT',\n 'STYLE',\n 'NOSCRIPT',\n 'IFRAME',\n 'SVG',\n 'PATH',\n 'G',\n 'DEFS',\n 'MASK',\n 'BR',\n 'META',\n 'LINK',\n 'HEAD',\n ]);\n\n function ensureStyleMarker(percent: number) {\n let styleEl = document.getElementById(STYLE_ID) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = document.createElement('style');\n styleEl.id = STYLE_ID;\n document.head.appendChild(styleEl);\n }\n styleEl.textContent = `/* accessify text-size: ${percent}% */`;\n }\n\n function removeStyleMarker() {\n document.getElementById(STYLE_ID)?.remove();\n }\n\n function hasOwnTextContent(el: HTMLElement): boolean {\n return Array.from(el.childNodes).some((node) => {\n return node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim());\n });\n }\n\n function shouldScaleElement(el: HTMLElement): boolean {\n if (el.id === 'accessify-root' || el.closest('#accessify-root')) return false;\n if (SKIP_TAGS.has(el.tagName)) return false;\n\n const computed = window.getComputedStyle(el);\n const fontSize = parseFloat(computed.fontSize);\n if (!Number.isFinite(fontSize) || fontSize <= 0) return false;\n if (computed.display === 'none' || computed.visibility === 'hidden') return false;\n\n const interactiveTags = new Set(['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'LABEL', 'OPTION']);\n return interactiveTags.has(el.tagName) || hasOwnTextContent(el);\n }\n\n function getTargetElements(): HTMLElement[] {\n if (!document.body) return [];\n const elements = [document.body, ...Array.from(document.body.querySelectorAll<HTMLElement>('*'))];\n return elements.filter(shouldScaleElement);\n }\n\n function rememberOriginalSize(el: HTMLElement) {\n if (!el.hasAttribute(ORIGINAL_INLINE_ATTR)) {\n el.setAttribute(ORIGINAL_INLINE_ATTR, el.style.fontSize || '');\n }\n\n if (!el.hasAttribute(ORIGINAL_COMPUTED_ATTR)) {\n const computedSize = parseFloat(window.getComputedStyle(el).fontSize);\n if (Number.isFinite(computedSize) && computedSize > 0) {\n el.setAttribute(ORIGINAL_COMPUTED_ATTR, String(computedSize));\n }\n }\n }\n\n function scaleElement(el: HTMLElement, scale: number) {\n rememberOriginalSize(el);\n\n const originalSize = parseFloat(el.getAttribute(ORIGINAL_COMPUTED_ATTR) || '');\n if (!Number.isFinite(originalSize) || originalSize <= 0) return;\n\n const nextSize = Math.round(originalSize * scale * 100) / 100;\n el.style.setProperty('font-size', `${nextSize}px`, 'important');\n el.setAttribute(PROCESSED_ATTR, 'true');\n }\n\n function restoreElement(el: HTMLElement) {\n const originalInline = el.getAttribute(ORIGINAL_INLINE_ATTR);\n if (originalInline === null) return;\n\n if (originalInline) {\n el.style.fontSize = originalInline;\n } else {\n el.style.removeProperty('font-size');\n }\n\n el.removeAttribute(PROCESSED_ATTR);\n el.removeAttribute(ORIGINAL_INLINE_ATTR);\n el.removeAttribute(ORIGINAL_COMPUTED_ATTR);\n }\n\n function restoreProcessedElements() {\n document.querySelectorAll<HTMLElement>(`[${PROCESSED_ATTR}]`).forEach((el) => {\n restoreElement(el);\n });\n }\n\n function queueRefresh() {\n if (refreshQueued || currentSize === 100) return;\n\n refreshQueued = true;\n const flush = () => {\n refreshQueued = false;\n applySize(currentSize);\n };\n\n if (typeof window.requestAnimationFrame === 'function') {\n window.requestAnimationFrame(() => flush());\n } else {\n window.setTimeout(flush, 0);\n }\n }\n\n function startObserver() {\n if (observer || !document.body) return;\n\n observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'childList' && (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0)) {\n queueRefresh();\n return;\n }\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n });\n }\n\n function stopObserver() {\n observer?.disconnect();\n observer = null;\n refreshQueued = false;\n }\n\n function applySize(percent: number) {\n if (percent === 100) {\n stopObserver();\n removeStyleMarker();\n restoreProcessedElements();\n return;\n }\n\n ensureStyleMarker(percent);\n\n const scale = percent / 100;\n const targets = new Set(getTargetElements());\n\n document.querySelectorAll<HTMLElement>(`[${PROCESSED_ATTR}]`).forEach((el) => {\n if (!targets.has(el)) {\n restoreElement(el);\n }\n });\n\n targets.forEach((el) => {\n scaleElement(el, scale);\n });\n\n startObserver();\n }\n\n function clamp(value: number): number {\n return Math.min(MAX_SIZE, Math.max(MIN_SIZE, Math.round(value / STEP) * STEP));\n }\n\n function activate() {\n const saved = localStorage.getItem(STORAGE_KEY);\n currentSize = saved ? clamp(parseInt(saved, 10)) : 150;\n applySize(currentSize);\n localStorage.setItem(STORAGE_KEY, String(currentSize));\n }\n\n function deactivate() {\n currentSize = 100;\n applySize(100);\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'text-size',\n name: () => 'Text Size',\n description: 'Adjust text size from 100% to 200%',\n icon: 'text-size',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'text-size',\n enabled: currentSize !== 100,\n value: currentSize,\n }),\n setState: (size: number) => {\n currentSize = clamp(size);\n applySize(currentSize);\n localStorage.setItem(STORAGE_KEY, String(currentSize));\n },\n };\n}\n"],"names":[],"mappings":"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"}
|