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.
- package/dist/accessify.min.js +1 -1
- package/dist/accessify.min.js.map +1 -1
- package/dist/accessify.mjs +1 -1
- package/dist/{contrast-DK34ryFE.js → contrast-CqsOs6Uo.js} +43 -34
- package/dist/contrast-CqsOs6Uo.js.map +1 -0
- package/dist/{index-C1fl-p3j.js → index-BrudtQik.js} +4 -4
- package/dist/{index-C1fl-p3j.js.map → index-BrudtQik.js.map} +1 -1
- package/dist/{keyboard-nav-B-NA3oL4.js → keyboard-nav-C8-HgfWw.js} +2 -2
- package/dist/{keyboard-nav-B-NA3oL4.js.map → keyboard-nav-C8-HgfWw.js.map} +1 -1
- package/dist/loader.min.js +1 -1
- package/dist/{page-structure-CtX2A4VH.js → page-structure-B_Do_gCl.js} +2 -2
- package/dist/{page-structure-CtX2A4VH.js.map → page-structure-B_Do_gCl.js.map} +1 -1
- package/dist/widget.js +1 -1
- package/dist/widget.js.map +1 -1
- package/package.json +1 -1
- package/dist/contrast-DK34ryFE.js.map +0 -1
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contrast-DK34ryFE.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: Background on structural elements ──\n // Override background-color broadly BUT exclude media elements (img, video,\n // picture, canvas, svg, iframe) — changing their bg can break blend-modes,\n // lazy-load opacity transitions, and transparent overlays on Shopify/etc.\n const MEDIA_EX = ':not(img):not(video):not(picture):not(canvas):not(svg):not(iframe)';\n const base = `\n html {\n color-scheme: ${t.colorScheme} !important;\n }\n html, body,\n body *${EX}${MEDIA_EX} {\n background-color: ${t.pageBg} !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\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 /** Mark elements whose background we forced transparent so we can undo on deactivate */\n const OVERLAY_ATTR = 'data-accessify-overlay-fix';\n\n function applyStyles(mode: ContrastMode) {\n let styleEl = document.getElementById(STYLE_ID);\n if (mode === 'off') {\n styleEl?.remove();\n undoOverlayFixes();\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 // After CSS applies, fix overlay elements that now hide images\n requestAnimationFrame(() => fixOverlays());\n }\n\n /**\n * Find positioned elements that cover most of their parent (overlays)\n * and make them transparent so they don't hide images beneath them.\n */\n function fixOverlays() {\n undoOverlayFixes(); // Clean previous run\n const els = document.querySelectorAll<HTMLElement>(\n 'body *:not(#accessify-root):not(#accessify-root *):not(img):not(video):not(picture):not(svg):not(canvas):not(iframe)'\n );\n for (const el of els) {\n const cs = getComputedStyle(el);\n if (cs.position !== 'absolute' && cs.position !== 'fixed') continue;\n // Check if this element covers most of its offset parent (overlay pattern)\n const parent = el.offsetParent || el.parentElement;\n if (!parent) continue;\n const pRect = parent.getBoundingClientRect();\n const eRect = el.getBoundingClientRect();\n if (pRect.width < 10 || pRect.height < 10) continue;\n const covX = eRect.width / pRect.width;\n const covY = eRect.height / pRect.height;\n if (covX > 0.8 && covY > 0.8) {\n // Looks like an overlay — make transparent\n el.style.setProperty('background-color', 'transparent', 'important');\n el.setAttribute(OVERLAY_ATTR, '1');\n }\n }\n }\n\n function undoOverlayFixes() {\n document.querySelectorAll<HTMLElement>(`[${OVERLAY_ATTR}]`).forEach(el => {\n el.style.removeProperty('background-color');\n el.removeAttribute(OVERLAY_ATTR);\n });\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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"}
|