accessify-widget 0.3.47 → 0.3.49

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.
@@ -1,4 +1,4 @@
1
- import { d, i } from "./index-C1fl-p3j.js";
1
+ import { d, i } from "./index-BrudtQik.js";
2
2
  export {
3
3
  d as destroy,
4
4
  i as init
@@ -43,15 +43,17 @@ const EX = ":not(#accessify-root):not(#accessify-root *)";
43
43
  function buildCSS(mode) {
44
44
  const t = TOKENS[mode];
45
45
  const isHigh = mode === "high";
46
- const MEDIA_EX = ":not(img):not(video):not(picture):not(canvas):not(svg):not(iframe)";
47
46
  const base = `
48
47
  html {
49
48
  color-scheme: ${t.colorScheme} !important;
50
49
  }
51
- html, body,
52
- body *${EX}${MEDIA_EX} {
50
+ html, body {
53
51
  background-color: ${t.pageBg} !important;
54
52
  }
53
+ body *${EX} {
54
+ background-color: transparent !important;
55
+ background-image: none !important;
56
+ }
55
57
  `;
56
58
  const textColor = `
57
59
  body *${EX} {
@@ -120,16 +122,50 @@ function buildCSS(mode) {
120
122
  ` : "";
121
123
  return base + textColor + links + forms + focus + borders + images + highExtras;
122
124
  }
125
+ const BACKUP_ATTR = "data-a11y-bg";
126
+ function stripInlineBackgrounds() {
127
+ const els = document.querySelectorAll("body *:not(#accessify-root):not(#accessify-root *)");
128
+ for (const el of els) {
129
+ const html = el;
130
+ if (html.tagName === "IMG" || html.tagName === "VIDEO" || html.tagName === "PICTURE" || html.tagName === "CANVAS" || html.tagName === "SVG") continue;
131
+ if (html.tagName === "INPUT" || html.tagName === "TEXTAREA" || html.tagName === "SELECT") continue;
132
+ const inlineBg = html.style.background || html.style.backgroundColor || html.style.backgroundImage;
133
+ if (!inlineBg) continue;
134
+ if (!html.hasAttribute(BACKUP_ATTR)) {
135
+ html.setAttribute(BACKUP_ATTR, JSON.stringify({
136
+ bg: html.style.background,
137
+ bgColor: html.style.backgroundColor,
138
+ bgImage: html.style.backgroundImage
139
+ }));
140
+ }
141
+ html.style.setProperty("background", "transparent", "important");
142
+ html.style.setProperty("background-color", "transparent", "important");
143
+ html.style.setProperty("background-image", "none", "important");
144
+ }
145
+ }
146
+ function restoreInlineBackgrounds() {
147
+ const els = document.querySelectorAll(`[${BACKUP_ATTR}]`);
148
+ for (const el of els) {
149
+ const html = el;
150
+ try {
151
+ const saved = JSON.parse(html.getAttribute(BACKUP_ATTR) || "{}");
152
+ html.style.background = saved.bg || "";
153
+ html.style.backgroundColor = saved.bgColor || "";
154
+ html.style.backgroundImage = saved.bgImage || "";
155
+ } catch {
156
+ }
157
+ html.removeAttribute(BACKUP_ATTR);
158
+ }
159
+ }
123
160
  function createContrastModule() {
124
161
  let currentMode = "off";
125
162
  const STYLE_ID = "accessify-contrast";
126
163
  const STORAGE_KEY = "accessify-contrast-mode";
127
- const OVERLAY_ATTR = "data-accessify-overlay-fix";
128
164
  function applyStyles(mode) {
129
165
  let styleEl = document.getElementById(STYLE_ID);
130
166
  if (mode === "off") {
131
167
  styleEl?.remove();
132
- undoOverlayFixes();
168
+ restoreInlineBackgrounds();
133
169
  return;
134
170
  }
135
171
  if (!styleEl) {
@@ -138,34 +174,7 @@ function createContrastModule() {
138
174
  document.head.appendChild(styleEl);
139
175
  }
140
176
  styleEl.textContent = buildCSS(mode);
141
- requestAnimationFrame(() => fixOverlays());
142
- }
143
- function fixOverlays() {
144
- undoOverlayFixes();
145
- const els = document.querySelectorAll(
146
- "body *:not(#accessify-root):not(#accessify-root *):not(img):not(video):not(picture):not(svg):not(canvas):not(iframe)"
147
- );
148
- for (const el of els) {
149
- const cs = getComputedStyle(el);
150
- if (cs.position !== "absolute" && cs.position !== "fixed") continue;
151
- const parent = el.offsetParent || el.parentElement;
152
- if (!parent) continue;
153
- const pRect = parent.getBoundingClientRect();
154
- const eRect = el.getBoundingClientRect();
155
- if (pRect.width < 10 || pRect.height < 10) continue;
156
- const covX = eRect.width / pRect.width;
157
- const covY = eRect.height / pRect.height;
158
- if (covX > 0.8 && covY > 0.8) {
159
- el.style.setProperty("background-color", "transparent", "important");
160
- el.setAttribute(OVERLAY_ATTR, "1");
161
- }
162
- }
163
- }
164
- function undoOverlayFixes() {
165
- document.querySelectorAll(`[${OVERLAY_ATTR}]`).forEach((el) => {
166
- el.style.removeProperty("background-color");
167
- el.removeAttribute(OVERLAY_ATTR);
168
- });
177
+ stripInlineBackgrounds();
169
178
  }
170
179
  function activate() {
171
180
  const saved = localStorage.getItem(STORAGE_KEY);
@@ -200,4 +209,4 @@ function createContrastModule() {
200
209
  export {
201
210
  createContrastModule as default
202
211
  };
203
- //# sourceMappingURL=contrast-DK34ryFE.js.map
212
+ //# sourceMappingURL=contrast-CqsOs6Uo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contrast-CqsOs6Uo.js","sources":["../src/features/contrast.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Contrast Modes (Accessibility Feature)\n// ---------------------------------------------------------------------------\n//\n// Three modes: light, dark, high — each as a clearly defined token set.\n//\n// Design principles:\n// 1. CONTENT elements (text, headings, links, buttons, form controls) get\n// explicit color overrides — these are what users need to read.\n// 2. STRUCTURAL elements (wrapper divs, sections, nav) get background only\n// via `html` and `body` — not individually. This prevents breaking\n// Framer/CSS-Grid/Flex layouts where divs use fit-content, overflow:hidden,\n// or fixed heights.\n// 3. The widget itself (inside #accessify-root / Shadow DOM) is NEVER touched.\n// 4. Focus indicators are defined in ALL modes, not just high contrast.\n// 5. border-color is NOT globally overridden — only on elements that have\n// visible borders for content separation (tables, fieldsets, hr).\n//\n// Selector strategy:\n// - `:where()` for zero-specificity (site styles can still win if needed,\n// but `!important` ensures accessibility overrides take priority).\n// - `body :where(...)` scopes to page content.\n// - `body *:not(#accessify-root):not(#accessify-root *)` used only where\n// we need broad text color coverage.\n// - Framer-safe: no background-color on generic div/section/article — only\n// on html/body. Content readability comes from text color, not from\n// painting every container.\n//\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState } from '../types';\n\ntype ContrastMode = 'off' | 'light' | 'dark' | 'high';\n\n// ---------------------------------------------------------------------------\n// Token definitions — each mode is a self-contained color system\n// ---------------------------------------------------------------------------\n\ninterface ContrastTokens {\n colorScheme: string;\n pageBg: string;\n text: string;\n textStrong: string; // headings, bold\n link: string;\n linkVisited: string;\n focusRing: string;\n borderContent: string; // for tables, hr, fieldset — NOT every div\n inputBg: string;\n inputBorder: string;\n imgFilter: string; // empty string = no filter\n}\n\nconst TOKENS: Record<Exclude<ContrastMode, 'off'>, ContrastTokens> = {\n light: {\n colorScheme: 'light',\n pageBg: '#fbf7ef',\n text: '#1a1a1a',\n textStrong: '#0d0d0d',\n link: '#0047b3',\n linkVisited: '#3d2b85',\n focusRing: '#0047b3',\n borderContent:'#888078',\n inputBg: '#ffffff',\n inputBorder: '#6f675d',\n imgFilter: '',\n },\n dark: {\n colorScheme: 'dark',\n pageBg: '#101418',\n text: '#e8e4dc',\n textStrong: '#ffffff',\n link: '#7cc8f5',\n linkVisited: '#b8a0e8',\n focusRing: '#7cc8f5',\n borderContent:'#3a4a58',\n inputBg: '#1a2028',\n inputBorder: '#4a5a68',\n imgFilter: 'brightness(0.90) contrast(1.06)',\n },\n high: {\n colorScheme: 'dark',\n pageBg: '#000000',\n text: '#ffffff',\n textStrong: '#ffffff',\n link: '#ffff00',\n linkVisited: '#ffff00',\n focusRing: '#ffff00',\n borderContent:'#ffffff',\n inputBg: '#000000',\n inputBorder: '#ffffff',\n imgFilter: 'contrast(1.25) brightness(0.95)',\n },\n};\n\n// ---------------------------------------------------------------------------\n// CSS generation — separated into logical layers\n// ---------------------------------------------------------------------------\n\n/** Elements to exclude from page-level contrast (the widget itself) */\nconst EX = ':not(#accessify-root):not(#accessify-root *)';\n\nfunction buildCSS(mode: Exclude<ContrastMode, 'off'>): string {\n const t = TOKENS[mode];\n const isHigh = mode === 'high';\n\n // ── Layer 1: Page background + strip all container backgrounds ──\n // Strategy: set pageBg ONLY on html/body, then make all other elements\n // transparent. This prevents opaque containers from hiding images on\n // Shopify/Framer sites (overlay divs, z-index stacking, etc.).\n // Form controls get their own bg back in Layer 4.\n const base = `\n html {\n color-scheme: ${t.colorScheme} !important;\n }\n html, body {\n background-color: ${t.pageBg} !important;\n }\n body *${EX} {\n background-color: transparent !important;\n background-image: none !important;\n }\n `;\n\n // ── Layer 2: Text color on ALL content elements ──\n // Using body * ensures text inside any container is readable, without\n // painting the container's background (which would break layouts).\n const textColor = `\n body *${EX} {\n color: ${t.text} !important;\n }\n body :where(h1, h2, h3, h4, h5, h6, strong, b, th)${EX} {\n color: ${t.textStrong} !important;\n }\n `;\n\n // ── Layer 3: Links — distinct color + underline for visibility ──\n const links = `\n body :where(a)${EX} {\n color: ${t.link} !important;\n text-decoration: underline !important;\n text-decoration-color: ${t.link} !important;\n ${isHigh ? 'text-decoration-thickness: 2px !important; text-underline-offset: 3px !important;' : ''}\n }\n body :where(a:visited)${EX} {\n color: ${t.linkVisited} !important;\n }\n body :where(a:hover, a:focus)${EX} {\n opacity: 0.85 !important;\n }\n `;\n\n // ── Layer 4: Form controls — explicit bg + border for readability ──\n // These get background because they ARE content, not structural wrappers.\n const forms = `\n body :where(input, textarea, select)${EX} {\n background-color: ${t.inputBg} !important;\n color: ${t.text} !important;\n border: 1px solid ${t.inputBorder} !important;\n box-shadow: none !important;\n }\n body :where(button, [role=\"button\"])${EX} {\n color: ${t.text} !important;\n border-color: ${t.inputBorder} !important;\n ${isHigh ? `background-color: ${t.pageBg} !important; border: 2px solid ${t.inputBorder} !important;` : ''}\n }\n `;\n\n // ── Layer 5: Focus indicators — in ALL modes, stronger in high ──\n const focus = `\n body :where(a, button, input, textarea, select, [tabindex])${EX}:focus-visible {\n outline: ${isHigh ? '3px' : '2px'} solid ${t.focusRing} !important;\n outline-offset: 2px !important;\n }\n `;\n\n // ── Layer 6: Content borders — only on elements that visually separate ──\n // NOT on generic divs — that destroys Framer card layouts.\n const borders = `\n body :where(table, th, td, hr, fieldset)${EX} {\n border-color: ${t.borderContent} !important;\n }\n `;\n\n // ── Layer 7: Images — gentle filter, skip decorative SVG icons ──\n const images = t.imgFilter ? `\n body :where(img, video, picture)${EX} {\n filter: ${t.imgFilter} !important;\n }\n ` : '';\n\n // ── Layer 8: High contrast extras ──\n const highExtras = isHigh ? `\n body :where(::placeholder)${EX} {\n color: #aaaaaa !important;\n opacity: 1 !important;\n }\n body :where(::selection) {\n background: #ffff00 !important;\n color: #000000 !important;\n }\n body :where(mark)${EX} {\n background: #ffff00 !important;\n color: #000000 !important;\n }\n ` : '';\n\n return base + textColor + links + forms + focus + borders + images + highExtras;\n}\n\n// ---------------------------------------------------------------------------\n// Module\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Inline-style override — Framer/Webflow/etc set background via inline style\n// which beats stylesheet !important. We must strip them via JS and restore on\n// deactivate.\n// ---------------------------------------------------------------------------\n\nconst BACKUP_ATTR = 'data-a11y-bg';\n\n/** Strip inline background from all elements (except widget + media) */\nfunction stripInlineBackgrounds() {\n const els = document.querySelectorAll('body *:not(#accessify-root):not(#accessify-root *)');\n for (const el of els) {\n const html = el as HTMLElement;\n if (html.tagName === 'IMG' || html.tagName === 'VIDEO' || html.tagName === 'PICTURE' ||\n html.tagName === 'CANVAS' || html.tagName === 'SVG') continue;\n // Skip form controls — they get their own bg in Layer 4\n if (html.tagName === 'INPUT' || html.tagName === 'TEXTAREA' || html.tagName === 'SELECT') continue;\n\n const inlineBg = html.style.background || html.style.backgroundColor || html.style.backgroundImage;\n if (!inlineBg) continue;\n\n // Back up original values so we can restore later\n if (!html.hasAttribute(BACKUP_ATTR)) {\n html.setAttribute(BACKUP_ATTR, JSON.stringify({\n bg: html.style.background,\n bgColor: html.style.backgroundColor,\n bgImage: html.style.backgroundImage,\n }));\n }\n html.style.setProperty('background', 'transparent', 'important');\n html.style.setProperty('background-color', 'transparent', 'important');\n html.style.setProperty('background-image', 'none', 'important');\n }\n}\n\n/** Restore original inline backgrounds */\nfunction restoreInlineBackgrounds() {\n const els = document.querySelectorAll(`[${BACKUP_ATTR}]`);\n for (const el of els) {\n const html = el as HTMLElement;\n try {\n const saved = JSON.parse(html.getAttribute(BACKUP_ATTR) || '{}');\n html.style.background = saved.bg || '';\n html.style.backgroundColor = saved.bgColor || '';\n html.style.backgroundImage = saved.bgImage || '';\n } catch { /* ignore parse errors */ }\n html.removeAttribute(BACKUP_ATTR);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Module\n// ---------------------------------------------------------------------------\n\nexport default function createContrastModule(): FeatureModule {\n let currentMode: ContrastMode = 'off';\n const STYLE_ID = 'accessify-contrast';\n const STORAGE_KEY = 'accessify-contrast-mode';\n\n function applyStyles(mode: ContrastMode) {\n let styleEl = document.getElementById(STYLE_ID);\n if (mode === 'off') {\n styleEl?.remove();\n restoreInlineBackgrounds();\n return;\n }\n if (!styleEl) {\n styleEl = document.createElement('style');\n styleEl.id = STYLE_ID;\n document.head.appendChild(styleEl);\n }\n styleEl.textContent = buildCSS(mode);\n // Strip inline backgrounds AFTER CSS is applied (handles Framer/Webflow)\n stripInlineBackgrounds();\n }\n\n function activate() {\n const saved = localStorage.getItem(STORAGE_KEY) as ContrastMode;\n currentMode = saved === 'light' || saved === 'dark' || saved === 'high' ? saved : 'dark';\n applyStyles(currentMode);\n }\n\n function deactivate() {\n currentMode = 'off';\n applyStyles('off');\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'contrast',\n name: () => 'Contrast',\n description: 'Increase contrast for better readability',\n icon: 'contrast',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'contrast', enabled: currentMode !== 'off', value: currentMode }),\n setState: (mode: ContrastMode) => {\n currentMode = mode === 'light' || mode === 'dark' || mode === 'high' ? mode : 'off';\n applyStyles(currentMode);\n if (currentMode === 'off') {\n localStorage.removeItem(STORAGE_KEY);\n } else {\n localStorage.setItem(STORAGE_KEY, currentMode);\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}
@@ -6618,16 +6618,16 @@ function FeatureGrid($$anchor, $$props) {
6618
6618
  const AI_FEATURES = /* @__PURE__ */ new Set(["text-simplify", "alt-text"]);
6619
6619
  const loadedModules = /* @__PURE__ */ new Map();
6620
6620
  const FEATURE_LOADERS = {
6621
- contrast: () => import("./contrast-DK34ryFE.js"),
6621
+ contrast: () => import("./contrast-CqsOs6Uo.js"),
6622
6622
  "text-size": () => import("./text-size-m_mHNPWo.js"),
6623
- "keyboard-nav": () => import("./keyboard-nav-B-NA3oL4.js"),
6623
+ "keyboard-nav": () => import("./keyboard-nav-C8-HgfWw.js"),
6624
6624
  "link-highlight": () => import("./link-highlight-DBGm067Y.js"),
6625
6625
  "reading-guide": () => import("./reading-guide-VT8NciIL.js"),
6626
6626
  "reading-mask": () => import("./reading-mask-BABChuCz.js"),
6627
6627
  "animation-stop": () => import("./animation-stop-_chC8bg1.js"),
6628
6628
  "hide-images": () => import("./hide-images-B_LeCBcd.js"),
6629
6629
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6630
- "page-structure": () => import("./page-structure-CtX2A4VH.js"),
6630
+ "page-structure": () => import("./page-structure-B_Do_gCl.js"),
6631
6631
  tts: () => import("./tts-CjszLRnb.js"),
6632
6632
  "text-simplify": () => import("./text-simplify-CK2GFhq2.js"),
6633
6633
  "alt-text": () => Promise.resolve().then(() => altText)
@@ -8991,4 +8991,4 @@ export {
8991
8991
  init as i,
8992
8992
  t
8993
8993
  };
8994
- //# sourceMappingURL=index-C1fl-p3j.js.map
8994
+ //# sourceMappingURL=index-BrudtQik.js.map