accessify-widget 0.3.51 → 0.3.53

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-BklfOcaC.js";
1
+ import { d, i } from "./index-BAnoPX-u.js";
2
2
  export {
3
3
  d as destroy,
4
4
  i as init
@@ -1,3 +1,60 @@
1
+ const VISUAL_ONLY_PROPS = /* @__PURE__ */ new Set([
2
+ "transform",
3
+ "scale",
4
+ "rotate",
5
+ "translate",
6
+ "translateX",
7
+ "translateY",
8
+ "translateZ",
9
+ "rotateX",
10
+ "rotateY",
11
+ "rotateZ",
12
+ "filter",
13
+ "backdropFilter",
14
+ "perspective",
15
+ "transformOrigin",
16
+ // CamelCase variants that WAAPI sometimes accepts
17
+ "webkitTransform",
18
+ "webkitFilter"
19
+ ]);
20
+ function isWidgetInternal(node) {
21
+ let n = node || null;
22
+ let hops = 0;
23
+ while (n && hops < 50) {
24
+ if (n instanceof Element) {
25
+ if (n.id === "accessify-root") return true;
26
+ const tag = n.tagName;
27
+ if (tag === "ACCESSIFY-WIDGET") return true;
28
+ const cls = n.getAttribute?.("class");
29
+ if (cls && /(?:^|\s)accessify-/.test(cls)) return true;
30
+ }
31
+ const parent = n.parentNode;
32
+ if (parent) {
33
+ n = parent;
34
+ } else if (n.host) {
35
+ n = n.host;
36
+ } else {
37
+ break;
38
+ }
39
+ hops++;
40
+ }
41
+ return false;
42
+ }
43
+ function isVisualOnlyKeyframes(kf) {
44
+ if (!kf) return false;
45
+ const META = /* @__PURE__ */ new Set(["offset", "easing", "composite"]);
46
+ const collect = (obj) => Object.keys(obj || {}).filter((k) => !META.has(k));
47
+ let props = [];
48
+ if (Array.isArray(kf)) {
49
+ for (const frame of kf) {
50
+ props = props.concat(collect(frame));
51
+ }
52
+ } else {
53
+ props = collect(kf);
54
+ }
55
+ if (props.length === 0) return false;
56
+ return props.every((p) => VISUAL_ONLY_PROPS.has(p));
57
+ }
1
58
  function createAnimationStopModule() {
2
59
  let enabled = false;
3
60
  const STYLE_ID = "a11y-stop-animations";
@@ -7,44 +64,54 @@ function createAnimationStopModule() {
7
64
  let scrollHandler = null;
8
65
  let originalVideoPlay = null;
9
66
  let originalAnimate = null;
67
+ let originalMatchMedia = null;
68
+ const trackedMQLs = [];
10
69
  let pausedVideos = [];
11
70
  let gifOriginals = /* @__PURE__ */ new Map();
12
- const VISUAL_ONLY_PROPS = /* @__PURE__ */ new Set([
13
- "transform",
14
- "scale",
15
- "rotate",
16
- "translate",
17
- "filter",
18
- "backdropFilter",
19
- "backdrop-filter",
20
- "webkitTransform",
21
- "webkitFilter",
22
- "-webkit-transform",
23
- "-webkit-filter",
24
- "offset",
25
- "easing",
26
- "composite"
27
- ]);
28
- function isVisualOnlyKeyframes(keyframes) {
29
- if (!keyframes) return false;
30
- try {
31
- if (Array.isArray(keyframes)) {
32
- for (const kf of keyframes) {
33
- if (!kf || typeof kf !== "object") return false;
34
- for (const key of Object.keys(kf)) {
35
- if (!VISUAL_ONLY_PROPS.has(key)) return false;
36
- }
71
+ function isReducedMotionQuery(q) {
72
+ return /prefers-reduced-motion/i.test(q);
73
+ }
74
+ function patchMatchMedia() {
75
+ if (originalMatchMedia) return;
76
+ if (typeof window.matchMedia !== "function") return;
77
+ originalMatchMedia = window.matchMedia.bind(window);
78
+ window.matchMedia = function(query) {
79
+ const real = originalMatchMedia(query);
80
+ if (!isReducedMotionQuery(query)) return real;
81
+ const proxy = new Proxy(real, {
82
+ get(target, prop, receiver) {
83
+ if (prop === "matches") return true;
84
+ if (prop === "media") return "(prefers-reduced-motion: reduce)";
85
+ const v = Reflect.get(target, prop, target);
86
+ return typeof v === "function" ? v.bind(target) : v;
37
87
  }
38
- return true;
39
- }
40
- for (const key of Object.keys(keyframes)) {
41
- if (!VISUAL_ONLY_PROPS.has(key)) return false;
88
+ });
89
+ trackedMQLs.push(real);
90
+ try {
91
+ real.dispatchEvent(new Event("change"));
92
+ } catch {
42
93
  }
43
- return true;
94
+ return proxy;
95
+ };
96
+ try {
97
+ const existing = originalMatchMedia("(prefers-reduced-motion: reduce)");
98
+ trackedMQLs.push(existing);
99
+ existing.dispatchEvent(new Event("change"));
44
100
  } catch {
45
- return false;
46
101
  }
47
102
  }
103
+ function restoreMatchMedia() {
104
+ if (!originalMatchMedia) return;
105
+ window.matchMedia = originalMatchMedia;
106
+ originalMatchMedia = null;
107
+ for (const mql of trackedMQLs) {
108
+ try {
109
+ mql.dispatchEvent(new Event("change"));
110
+ } catch {
111
+ }
112
+ }
113
+ trackedMQLs.length = 0;
114
+ }
48
115
  function patchAnimate() {
49
116
  if (originalAnimate) return;
50
117
  originalAnimate = Element.prototype.animate;
@@ -52,19 +119,17 @@ function createAnimationStopModule() {
52
119
  if (!enabled) {
53
120
  return originalAnimate.call(this, keyframes, options);
54
121
  }
55
- try {
56
- let node = this;
57
- while (node) {
58
- if (node.id === "accessify-root") {
59
- return originalAnimate.call(this, keyframes, options);
60
- }
61
- const parent = node.parentNode || node.host;
62
- if (parent === node) break;
63
- node = parent;
122
+ if (isWidgetInternal(this)) {
123
+ return originalAnimate.call(this, keyframes, options);
124
+ }
125
+ if (isVisualOnlyKeyframes(keyframes)) {
126
+ const anim2 = originalAnimate.call(this, keyframes, options);
127
+ try {
128
+ anim2.cancel();
129
+ } catch {
64
130
  }
65
- } catch {
131
+ return anim2;
66
132
  }
67
- const visualOnly = isVisualOnlyKeyframes(keyframes);
68
133
  let opts;
69
134
  if (typeof options === "number") {
70
135
  opts = { duration: 1e-3, fill: "forwards" };
@@ -81,11 +146,7 @@ function createAnimationStopModule() {
81
146
  }
82
147
  const anim = originalAnimate.call(this, keyframes, opts);
83
148
  try {
84
- if (visualOnly) {
85
- anim.cancel();
86
- } else {
87
- anim.finish();
88
- }
149
+ anim.finish();
89
150
  } catch {
90
151
  }
91
152
  return anim;
@@ -119,29 +180,41 @@ function createAnimationStopModule() {
119
180
  function removeStyles() {
120
181
  document.getElementById(STYLE_ID)?.remove();
121
182
  }
122
- function isWidgetAnimation(anim) {
123
- try {
124
- const target = anim.effect?.target;
125
- if (!target) return false;
126
- let node = target;
127
- while (node) {
128
- if (node.id === "accessify-root") return true;
129
- const parent = node.parentNode || node.host;
130
- if (parent === node) break;
131
- node = parent;
132
- }
133
- } catch {
134
- }
135
- return false;
136
- }
137
183
  function finishAllAnimations() {
138
184
  try {
139
185
  const animations = document.getAnimations?.();
140
186
  if (!animations) return;
141
187
  for (const anim of animations) {
142
- if (isWidgetAnimation(anim)) continue;
188
+ const target = anim.effect?.target;
189
+ if (target && isWidgetInternal(target)) continue;
190
+ let visualOnly = false;
191
+ try {
192
+ const kf = anim.effect?.getKeyframes?.();
193
+ if (kf && kf.length > 0) {
194
+ const META = /* @__PURE__ */ new Set(["offset", "computedOffset", "easing", "composite"]);
195
+ let allVisual = true;
196
+ let hasProps = false;
197
+ for (const frame of kf) {
198
+ for (const key of Object.keys(frame)) {
199
+ if (META.has(key)) continue;
200
+ hasProps = true;
201
+ if (!VISUAL_ONLY_PROPS.has(key)) {
202
+ allVisual = false;
203
+ break;
204
+ }
205
+ }
206
+ if (!allVisual) break;
207
+ }
208
+ visualOnly = hasProps && allVisual;
209
+ }
210
+ } catch {
211
+ }
143
212
  try {
144
- anim.finish();
213
+ if (visualOnly) {
214
+ anim.cancel();
215
+ } else {
216
+ anim.finish();
217
+ }
145
218
  } catch {
146
219
  try {
147
220
  anim.cancel();
@@ -413,6 +486,7 @@ function createAnimationStopModule() {
413
486
  function activate() {
414
487
  if (enabled) return;
415
488
  enabled = true;
489
+ patchMatchMedia();
416
490
  patchAnimate();
417
491
  injectStyles();
418
492
  finishAllAnimations();
@@ -443,6 +517,7 @@ function createAnimationStopModule() {
443
517
  stopPeriodicScan();
444
518
  teardownObserver();
445
519
  restoreAnimate();
520
+ restoreMatchMedia();
446
521
  unfreezeScrollAnimations();
447
522
  restoreGSAP();
448
523
  restoreHiddenElements();
@@ -471,4 +546,4 @@ function createAnimationStopModule() {
471
546
  export {
472
547
  createAnimationStopModule as default
473
548
  };
474
- //# sourceMappingURL=animation-stop-WqFHJSRH.js.map
549
+ //# sourceMappingURL=animation-stop-sX4g8tF2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation-stop-sX4g8tF2.js","sources":["../src/features/animation-stop.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\n\n/**\n * Animation Stop – V4 (Clean 3-Layer Approach)\n *\n * Layer 1: CSS injection — kill all CSS animations/transitions via 0.001ms duration\n * Layer 2: Web Animations API — finish() all running WAAPI animations (Framer Motion etc.)\n * Layer 3: JS library detection — GSAP globalTimeline, inline-style freeze for rAF-based libs\n * Layer 4: Media — pause videos, freeze GIFs, stop SVG SMIL, stop marquees\n *\n * + MutationObserver for dynamic content\n * + Periodic re-scan (every 500ms) for frameworks that create new animations\n *\n * DOES NOT:\n * - Monkey-patch IntersectionObserver (breaks lazy loading)\n * - Override requestAnimationFrame (breaks entire page)\n * - Override Element.prototype.animate() (too invasive)\n * - Override matchMedia (too invasive)\n * - Set opacity:1 !important via CSS (breaks modals/hidden elements)\n * - Use animation:none or transition:none (breaks JS events)\n */\n// Visually-only CSS properties — safe to cancel() (revert to baseline)\n// instead of finish() (land in end state). Hover animations like\n// `transform: scale(1.05)` get reverted to scale(1) instead of persisting zoom.\nconst VISUAL_ONLY_PROPS = new Set([\n 'transform', 'scale', 'rotate', 'translate',\n 'translateX', 'translateY', 'translateZ',\n 'rotateX', 'rotateY', 'rotateZ',\n 'filter', 'backdropFilter', 'perspective', 'transformOrigin',\n // CamelCase variants that WAAPI sometimes accepts\n 'webkitTransform', 'webkitFilter',\n]);\n\n/**\n * Walk up parentNode → shadowRoot.host chain to detect if a node\n * belongs to our own widget UI. Used to skip widget-internal animations\n * so the trigger/card hover effects inside Shadow DOM keep working.\n */\nfunction isWidgetInternal(node: Node | null | undefined): boolean {\n let n: Node | null = node || null;\n let hops = 0;\n while (n && hops < 50) {\n if (n instanceof Element) {\n if (n.id === 'accessify-root') return true;\n const tag = n.tagName;\n if (tag === 'ACCESSIFY-WIDGET') return true;\n // Any element whose class name starts with \"accessify-\" is ours\n const cls = n.getAttribute?.('class');\n if (cls && /(?:^|\\s)accessify-/.test(cls)) return true;\n }\n // Cross shadow boundary: ShadowRoot → host\n const parent = (n as any).parentNode;\n if (parent) {\n n = parent;\n } else if ((n as any).host) {\n n = (n as any).host;\n } else {\n break;\n }\n hops++;\n }\n return false;\n}\n\n/**\n * Returns true iff ALL animated properties in the keyframes are visual-only\n * (transform/filter/etc). Such animations can be safely cancel()ed to revert\n * to baseline — this kills hover-zoom without clobbering entry animations\n * that fade/slide content into view (those touch opacity and must finish()).\n */\nfunction isVisualOnlyKeyframes(\n kf: Keyframe[] | PropertyIndexedKeyframes | null,\n): boolean {\n if (!kf) return false;\n const META = new Set(['offset', 'easing', 'composite']);\n const collect = (obj: any): string[] =>\n Object.keys(obj || {}).filter(k => !META.has(k));\n\n let props: string[] = [];\n if (Array.isArray(kf)) {\n for (const frame of kf) {\n props = props.concat(collect(frame));\n }\n } else {\n props = collect(kf);\n }\n if (props.length === 0) return false;\n return props.every(p => VISUAL_ONLY_PROPS.has(p));\n}\n\nexport default function createAnimationStopModule(): FeatureModule {\n let enabled = false;\n const STYLE_ID = 'a11y-stop-animations';\n const STORAGE_KEY = 'accessify-animation-stop';\n\n // --- State ---\n let mutationObserver: MutationObserver | null = null;\n let scanInterval: ReturnType<typeof setInterval> | null = null;\n let scrollHandler: (() => void) | null = null;\n let originalVideoPlay: typeof HTMLVideoElement.prototype.play | null = null;\n let originalAnimate: typeof Element.prototype.animate | null = null;\n let originalMatchMedia: typeof window.matchMedia | null = null;\n const trackedMQLs: MediaQueryList[] = [];\n let pausedVideos: HTMLVideoElement[] = [];\n let gifOriginals = new Map<HTMLImageElement, string>();\n\n // =========================================================================\n // Layer A: matchMedia patch — signal prefers-reduced-motion: reduce\n //\n // Framer Motion (and many other libs) have a built-in reduced-motion\n // respect mode via window.matchMedia('(prefers-reduced-motion: reduce)').\n // By patching matchMedia to return matches:true for that query AND\n // dispatching a synthetic 'change' event on existing MQL subscriptions,\n // Framer disables whileHover gestures AT THE SOURCE — no fighting with\n // WAAPI animation objects, no visible hover zoom.\n // =========================================================================\n\n function isReducedMotionQuery(q: string): boolean {\n return /prefers-reduced-motion/i.test(q);\n }\n\n function patchMatchMedia() {\n if (originalMatchMedia) return;\n if (typeof window.matchMedia !== 'function') return;\n originalMatchMedia = window.matchMedia.bind(window);\n\n window.matchMedia = function (query: string): MediaQueryList {\n const real = originalMatchMedia!(query);\n if (!isReducedMotionQuery(query)) return real;\n\n // Wrap the real MQL in a Proxy that reports matches:true.\n // We keep addEventListener/removeEventListener pass-through so\n // libraries can subscribe; we just dispatch a synthetic 'change'\n // event on the real MQL so existing subscribers re-read.\n const proxy = new Proxy(real, {\n get(target, prop, receiver) {\n if (prop === 'matches') return true;\n if (prop === 'media') return '(prefers-reduced-motion: reduce)';\n const v = Reflect.get(target, prop, target);\n return typeof v === 'function' ? v.bind(target) : v;\n },\n });\n trackedMQLs.push(real);\n try {\n real.dispatchEvent(new Event('change'));\n } catch { /* ignore */ }\n return proxy;\n } as typeof window.matchMedia;\n\n // Also nudge anything that has already subscribed before we patched.\n // We re-query the real matchMedia for reduced-motion and dispatch change.\n try {\n const existing = originalMatchMedia('(prefers-reduced-motion: reduce)');\n trackedMQLs.push(existing);\n existing.dispatchEvent(new Event('change'));\n } catch { /* ignore */ }\n }\n\n function restoreMatchMedia() {\n if (!originalMatchMedia) return;\n window.matchMedia = originalMatchMedia;\n originalMatchMedia = null;\n // Fire change on tracked MQLs so subscribers re-read real state\n for (const mql of trackedMQLs) {\n try { mql.dispatchEvent(new Event('change')); } catch { /* ignore */ }\n }\n trackedMQLs.length = 0;\n }\n\n // =========================================================================\n // Layer B: Element.prototype.animate() intercept\n //\n // Three branches:\n // 1. Widget-internal target → pass through untouched (our own hover FX work)\n // 2. Visual-only keyframes (transform/filter only) → create then cancel()\n // so element reverts to baseline (kills Framer hover zoom)\n // 3. Everything else (opacity, layout, mixed) → force 0.001ms + finish()\n // so entry animations (fade-in, slide-in) land in their visible end state\n // =========================================================================\n\n function patchAnimate() {\n if (originalAnimate) return;\n originalAnimate = Element.prototype.animate;\n\n Element.prototype.animate = function (\n this: Element,\n keyframes: Keyframe[] | PropertyIndexedKeyframes | null,\n options?: number | KeyframeAnimationOptions,\n ): Animation {\n if (!enabled) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n // Branch 1: widget-internal → passthrough\n if (isWidgetInternal(this)) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n // Branch 2: visual-only keyframes → create and cancel (revert to baseline)\n if (isVisualOnlyKeyframes(keyframes)) {\n const anim = originalAnimate!.call(this, keyframes, options);\n try { anim.cancel(); } catch { /* ignore */ }\n return anim;\n }\n\n // Branch 3: everything else → snap to end state\n let opts: KeyframeAnimationOptions;\n if (typeof options === 'number') {\n opts = { duration: 0.001, fill: 'forwards' as FillMode };\n } else {\n opts = {\n ...(options || {}),\n duration: 0.001,\n delay: 0,\n iterations: 1,\n fill: 'forwards' as FillMode,\n };\n delete (opts as any).iterationStart;\n delete (opts as any).endDelay;\n }\n\n const anim = originalAnimate!.call(this, keyframes, opts);\n try { anim.finish(); } catch { /* ignore */ }\n return anim;\n };\n }\n\n function restoreAnimate() {\n if (originalAnimate) {\n Element.prototype.animate = originalAnimate;\n originalAnimate = null;\n }\n }\n\n // =========================================================================\n // Layer 1: CSS Injection\n // =========================================================================\n\n function injectStyles() {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n *, *::before, *::after {\n animation-duration: 0.001ms !important;\n animation-iteration-count: 1 !important;\n animation-delay: 0s !important;\n animation-fill-mode: forwards !important;\n transition-duration: 0.001ms !important;\n transition-delay: 0s !important;\n scroll-behavior: auto !important;\n animation-timeline: auto !important;\n scroll-timeline: none !important;\n }\n `;\n document.head.appendChild(style);\n }\n\n function removeStyles() {\n document.getElementById(STYLE_ID)?.remove();\n }\n\n // =========================================================================\n // Layer 2: Web Animations API — finish all WAAPI animations\n // =========================================================================\n\n function finishAllAnimations() {\n try {\n const animations = document.getAnimations?.();\n if (!animations) return;\n for (const anim of animations) {\n // Skip widget-internal animations so our own hover FX keep working\n const target = (anim.effect as KeyframeEffect | null)?.target as Node | null;\n if (target && isWidgetInternal(target)) continue;\n\n // Visual-only animations → cancel (revert to baseline) instead of\n // finish() which would persist hover zoom end-state.\n let visualOnly = false;\n try {\n const kf = (anim.effect as KeyframeEffect | null)?.getKeyframes?.();\n if (kf && kf.length > 0) {\n const META = new Set(['offset', 'computedOffset', 'easing', 'composite']);\n let allVisual = true;\n let hasProps = false;\n for (const frame of kf) {\n for (const key of Object.keys(frame)) {\n if (META.has(key)) continue;\n hasProps = true;\n if (!VISUAL_ONLY_PROPS.has(key)) { allVisual = false; break; }\n }\n if (!allVisual) break;\n }\n visualOnly = hasProps && allVisual;\n }\n } catch { /* ignore */ }\n\n try {\n if (visualOnly) {\n anim.cancel();\n } else {\n anim.finish();\n }\n } catch {\n try { anim.cancel(); } catch { /* ignore */ }\n }\n }\n } catch { /* getAnimations not supported */ }\n }\n\n // =========================================================================\n // Layer 3: JS animation library detection + inline style freeze\n // =========================================================================\n\n function patchGSAP() {\n const g = (window as any).gsap;\n if (g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(0);\n (window as any)._a11yGsapPatched = true;\n } catch { /* ignore */ }\n }\n }\n\n function restoreGSAP() {\n const g = (window as any).gsap;\n if ((window as any)._a11yGsapPatched && g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(1);\n delete (window as any)._a11yGsapPatched;\n } catch { /* ignore */ }\n }\n }\n\n /**\n * Force hidden-by-animation elements visible.\n * Only touches INLINE styles — never sets CSS !important on opacity etc.\n * which would break modals and intentionally hidden elements.\n */\n function forceHiddenElementsVisible() {\n // Only process elements near the viewport to avoid layout chaos on\n // Framer/scroll-animated pages where dozens of off-screen elements\n // are hidden via opacity:0 / translateY as part of scroll reveals.\n const viewH = window.innerHeight;\n const margin = viewH * 1.5; // 1.5x viewport ahead\n\n const all = document.querySelectorAll<HTMLElement>('*');\n for (const el of all) {\n if (el.tagName === 'SCRIPT' || el.tagName === 'STYLE' || el.tagName === 'NOSCRIPT' || el.tagName === 'META' || el.tagName === 'LINK') continue;\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) continue;\n if (el.dataset.a11yOrigStyle) continue; // Already processed\n\n const computed = window.getComputedStyle(el);\n if (computed.display === 'none') continue; // Intentionally hidden\n\n // Skip elements far below the current scroll position —\n // they will be handled when the user scrolls to them (periodic re-scan).\n const rect = el.getBoundingClientRect();\n if (rect.top > viewH + margin) continue; // Too far below viewport\n // Also skip if entirely above viewport (already scrolled past)\n if (rect.bottom < -margin) continue;\n\n const inline = el.style;\n let needsFix = false;\n const originals: Record<string, string> = {};\n\n // Inline opacity 0 or near-0 (computed, not stylesheet)\n const opacityVal = parseFloat(computed.opacity);\n if (opacityVal < 0.1 && inline.opacity !== '') {\n originals.opacity = inline.opacity;\n el.style.opacity = '1';\n needsFix = true;\n } else if (opacityVal < 0.1 && el.hasAttribute('data-framer-appear-id')) {\n // Framer appear elements: opacity set via WAAPI or framework\n originals.opacity = inline.opacity || '';\n el.style.opacity = '1';\n needsFix = true;\n }\n\n // Inline transform with translate that moves element off-screen\n if (inline.transform && /translate[XY]\\([^0]/.test(inline.transform)) {\n originals.transform = inline.transform;\n el.style.transform = 'none';\n needsFix = true;\n }\n\n // Inline visibility hidden\n if (inline.visibility === 'hidden') {\n originals.visibility = inline.visibility;\n el.style.visibility = 'visible';\n needsFix = true;\n }\n\n // Inline clip-path that hides element\n if (inline.clipPath && inline.clipPath !== 'none') {\n originals.clipPath = inline.clipPath;\n el.style.clipPath = 'none';\n needsFix = true;\n }\n\n if (needsFix) {\n el.dataset.a11yOrigStyle = JSON.stringify(originals);\n }\n }\n }\n\n function restoreHiddenElements() {\n document.querySelectorAll<HTMLElement>('[data-a11y-orig-style]').forEach(el => {\n try {\n const orig: Record<string, string> = JSON.parse(el.dataset.a11yOrigStyle || '{}');\n for (const [prop, val] of Object.entries(orig)) {\n if (val === '') {\n el.style.removeProperty(prop);\n } else {\n (el.style as any)[prop] = val;\n }\n }\n } catch { /* malformed JSON */ }\n delete el.dataset.a11yOrigStyle;\n });\n }\n\n /**\n * Freeze inline-animated styles so scroll-handlers can't update them.\n * Takes a snapshot of current inline transforms and enforces them on scroll.\n */\n function freezeScrollAnimations() {\n document.querySelectorAll<HTMLElement>('[style]').forEach(el => {\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) return;\n if (el.dataset.a11yFrozenStyle) return;\n const s = el.style;\n if (s.transform || s.opacity) {\n el.dataset.a11yFrozenStyle = JSON.stringify({\n transform: s.transform || '',\n opacity: s.opacity || '',\n });\n }\n });\n\n if (!scrollHandler) {\n scrollHandler = () => {\n if (!enabled) return;\n document.querySelectorAll<HTMLElement>('[data-a11y-frozen-style]').forEach(el => {\n try {\n const frozen = JSON.parse(el.dataset.a11yFrozenStyle || '{}');\n if (frozen.transform && el.style.transform !== frozen.transform) {\n el.style.transform = frozen.transform;\n }\n } catch { /* ignore */ }\n });\n };\n window.addEventListener('scroll', scrollHandler, { passive: true, capture: true });\n }\n }\n\n function unfreezeScrollAnimations() {\n if (scrollHandler) {\n window.removeEventListener('scroll', scrollHandler, true);\n scrollHandler = null;\n }\n document.querySelectorAll<HTMLElement>('[data-a11y-frozen-style]').forEach(el => {\n delete el.dataset.a11yFrozenStyle;\n });\n }\n\n // =========================================================================\n // Layer 4: Media\n // =========================================================================\n\n function pauseAllVideos() {\n document.querySelectorAll<HTMLVideoElement>('video').forEach(v => {\n if (!v.paused) {\n v.dataset.a11yPaused = 'true';\n v.pause();\n pausedVideos.push(v);\n }\n });\n }\n\n function interceptVideoPlay() {\n if (originalVideoPlay) return;\n originalVideoPlay = HTMLVideoElement.prototype.play;\n HTMLVideoElement.prototype.play = function () {\n if (enabled) return Promise.resolve();\n return originalVideoPlay!.call(this);\n };\n }\n\n function restoreVideoPlay() {\n if (originalVideoPlay) {\n HTMLVideoElement.prototype.play = originalVideoPlay;\n originalVideoPlay = null;\n }\n }\n\n function resumeAllVideos() {\n restoreVideoPlay();\n document.querySelectorAll<HTMLVideoElement>('video[data-a11y-paused]').forEach(v => {\n try { v.play(); } catch { /* gone */ }\n delete v.dataset.a11yPaused;\n });\n pausedVideos = [];\n }\n\n function freezeGif(img: HTMLImageElement) {\n const src = (img.currentSrc || img.src || '').toLowerCase();\n if (!src.match(/\\.gif(\\?|$)/i)) return;\n if (gifOriginals.has(img)) return;\n\n const doFreeze = () => {\n try {\n const w = img.naturalWidth || img.width;\n const h = img.naturalHeight || img.height;\n if (w === 0 || h === 0) return;\n const c = document.createElement('canvas');\n c.width = w; c.height = h;\n const ctx = c.getContext('2d');\n if (!ctx) return;\n ctx.drawImage(img, 0, 0);\n gifOriginals.set(img, img.src);\n img.src = c.toDataURL('image/png');\n } catch { /* CORS */ }\n };\n\n if (img.complete && img.naturalWidth > 0) doFreeze();\n else img.addEventListener('load', doFreeze, { once: true });\n }\n\n function freezeAllGifs() {\n document.querySelectorAll<HTMLImageElement>('img').forEach(freezeGif);\n }\n\n function restoreAllGifs() {\n for (const [img, src] of gifOriginals) {\n try { img.src = src; } catch { /* gone */ }\n }\n gifOriginals.clear();\n }\n\n function pauseSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).pauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function resumeSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).unpauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function stopMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).stop?.(); } catch { /* ignore */ }\n });\n }\n\n function startMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).start?.(); } catch { /* ignore */ }\n });\n }\n\n // =========================================================================\n // MutationObserver — dynamic content\n // =========================================================================\n\n function setupObserver() {\n if (mutationObserver) return;\n mutationObserver = new MutationObserver(mutations => {\n if (!enabled) return;\n let hasNewContent = false;\n for (const m of mutations) {\n if (m.addedNodes.length > 0) { hasNewContent = true; break; }\n }\n if (hasNewContent) {\n finishAllAnimations();\n forceHiddenElementsVisible();\n pauseAllVideos();\n freezeAllGifs();\n pauseSVG();\n }\n });\n mutationObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function teardownObserver() {\n mutationObserver?.disconnect();\n mutationObserver = null;\n }\n\n // =========================================================================\n // Periodic re-scan — frameworks create new animations constantly\n // =========================================================================\n\n function startPeriodicScan() {\n if (scanInterval) return;\n scanInterval = setInterval(() => {\n if (!enabled) return;\n finishAllAnimations();\n }, 500);\n }\n\n function stopPeriodicScan() {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n }\n\n // =========================================================================\n // Lifecycle\n // =========================================================================\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Layer A: Signal prefers-reduced-motion — disables Framer Motion hover at source\n patchMatchMedia();\n\n // Layer B: Intercept Element.animate() — catches ALL new WAAPI animations instantly\n patchAnimate();\n\n // Layer 1: CSS\n injectStyles();\n\n // Layer 2: Kill all currently running WAAPI animations\n finishAllAnimations();\n\n // Layer 3: JS libs + inline style fixes\n patchGSAP();\n forceHiddenElementsVisible();\n freezeScrollAnimations();\n\n // Layer 4: Media\n pauseAllVideos();\n interceptVideoPlay();\n freezeAllGifs();\n pauseSVG();\n stopMarquees();\n\n // Observers\n setupObserver();\n startPeriodicScan();\n\n // Delayed re-scans for async rendering frameworks\n for (const delay of [50, 200, 500, 1000, 2000, 4000]) {\n setTimeout(() => {\n if (!enabled) return;\n finishAllAnimations();\n forceHiddenElementsVisible();\n freezeScrollAnimations();\n pauseAllVideos();\n freezeAllGifs();\n }, delay);\n }\n\n localStorage.setItem(STORAGE_KEY, 'true');\n }\n\n function deactivate() {\n enabled = false;\n\n stopPeriodicScan();\n teardownObserver();\n restoreAnimate();\n restoreMatchMedia();\n unfreezeScrollAnimations();\n restoreGSAP();\n restoreHiddenElements();\n startMarquees();\n resumeSVG();\n restoreAllGifs();\n resumeAllVideos();\n removeStyles();\n\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'animation-stop',\n name: () => 'Stop Animations',\n description: 'Pause all animations, transitions, and auto-playing videos (WCAG 2.3.1)',\n icon: 'animation-stop',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'animation-stop', enabled }),\n setState: (state: { enabled: boolean }) => {\n if (state.enabled) activate();\n else deactivate();\n },\n };\n}\n"],"names":["anim"],"mappings":"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"}
@@ -6620,14 +6620,14 @@ function FeatureGrid($$anchor, $$props) {
6620
6620
  const FEATURE_LOADERS = {
6621
6621
  contrast: () => import("./contrast-CqsOs6Uo.js"),
6622
6622
  "text-size": () => import("./text-size-m_mHNPWo.js"),
6623
- "keyboard-nav": () => import("./keyboard-nav-hUpbQM12.js"),
6623
+ "keyboard-nav": () => import("./keyboard-nav-BzHTCdxB.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
- "animation-stop": () => import("./animation-stop-WqFHJSRH.js"),
6627
+ "animation-stop": () => import("./animation-stop-sX4g8tF2.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-CRbui1FZ.js"),
6630
+ "page-structure": () => import("./page-structure-B1V2uLzY.js"),
6631
6631
  tts: () => import("./tts-CjszLRnb.js"),
6632
6632
  "text-simplify": () => import("./text-simplify-B0hIi6bW.js"),
6633
6633
  "alt-text": () => Promise.resolve().then(() => altText)
@@ -8816,20 +8816,14 @@ const REMOVED_FEATURES = /* @__PURE__ */ new Set([
8816
8816
  "saturation",
8817
8817
  "text-align",
8818
8818
  "line-height",
8819
+ "page-structure",
8819
8820
  "focus-highlight",
8820
8821
  "auto-scan"
8821
8822
  ]);
8822
- function detectLang() {
8823
- const htmlLang = document.documentElement.lang?.trim();
8824
- if (htmlLang) return htmlLang.split("-")[0].toLowerCase();
8825
- const nav = (navigator.language || navigator.userLanguage || "").trim();
8826
- if (nav) return nav.split("-")[0].toLowerCase();
8827
- return "en";
8828
- }
8829
8823
  const DEFAULT_CONFIG = {
8830
8824
  position: "bottom-right",
8831
8825
  theme: "auto",
8832
- lang: detectLang(),
8826
+ lang: document.documentElement.lang || "en",
8833
8827
  features: [
8834
8828
  "contrast",
8835
8829
  "text-size",
@@ -8842,8 +8836,7 @@ const DEFAULT_CONFIG = {
8842
8836
  "animation-stop",
8843
8837
  "tts",
8844
8838
  "text-simplify",
8845
- "alt-text",
8846
- "page-structure"
8839
+ "alt-text"
8847
8840
  ],
8848
8841
  zIndex: 2147483647,
8849
8842
  compact: false
@@ -9037,4 +9030,4 @@ export {
9037
9030
  init as i,
9038
9031
  t
9039
9032
  };
9040
- //# sourceMappingURL=index-BklfOcaC.js.map
9033
+ //# sourceMappingURL=index-BAnoPX-u.js.map