accessify-widget 0.3.53 → 0.3.54

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-BAnoPX-u.js";
1
+ import { d, i } from "./index-Bz63wH7t.js";
2
2
  export {
3
3
  d as destroy,
4
4
  i as init
@@ -1,30 +1,10 @@
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
1
  function isWidgetInternal(node) {
21
2
  let n = node || null;
22
3
  let hops = 0;
23
4
  while (n && hops < 50) {
24
5
  if (n instanceof Element) {
25
6
  if (n.id === "accessify-root") return true;
26
- const tag = n.tagName;
27
- if (tag === "ACCESSIFY-WIDGET") return true;
7
+ if (n.tagName === "ACCESSIFY-WIDGET") return true;
28
8
  const cls = n.getAttribute?.("class");
29
9
  if (cls && /(?:^|\s)accessify-/.test(cls)) return true;
30
10
  }
@@ -40,21 +20,6 @@ function isWidgetInternal(node) {
40
20
  }
41
21
  return false;
42
22
  }
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
- }
58
23
  function createAnimationStopModule() {
59
24
  let enabled = false;
60
25
  const STYLE_ID = "a11y-stop-animations";
@@ -64,53 +29,44 @@ function createAnimationStopModule() {
64
29
  let scrollHandler = null;
65
30
  let originalVideoPlay = null;
66
31
  let originalAnimate = null;
67
- let originalMatchMedia = null;
68
- const trackedMQLs = [];
69
32
  let pausedVideos = [];
70
33
  let gifOriginals = /* @__PURE__ */ new Map();
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;
87
- }
88
- });
89
- trackedMQLs.push(real);
90
- try {
91
- real.dispatchEvent(new Event("change"));
92
- } catch {
93
- }
94
- return proxy;
95
- };
96
- try {
97
- const existing = originalMatchMedia("(prefers-reduced-motion: reduce)");
98
- trackedMQLs.push(existing);
99
- existing.dispatchEvent(new Event("change"));
100
- } catch {
34
+ let inPointerWindow = false;
35
+ let pointerWindowTimer = null;
36
+ let pointerListenerFn = null;
37
+ function openPointerWindow(e) {
38
+ const path = e.composedPath ? e.composedPath() : [];
39
+ const target = path && path[0] || e.target;
40
+ if (isWidgetInternal(target)) return;
41
+ inPointerWindow = true;
42
+ if (pointerWindowTimer) clearTimeout(pointerWindowTimer);
43
+ pointerWindowTimer = setTimeout(() => {
44
+ inPointerWindow = false;
45
+ pointerWindowTimer = null;
46
+ }, 120);
47
+ }
48
+ function startPointerTracking() {
49
+ if (pointerListenerFn) return;
50
+ pointerListenerFn = openPointerWindow;
51
+ const opts = { capture: true, passive: true };
52
+ window.addEventListener("pointerenter", pointerListenerFn, opts);
53
+ window.addEventListener("pointerover", pointerListenerFn, opts);
54
+ window.addEventListener("mouseenter", pointerListenerFn, opts);
55
+ window.addEventListener("mouseover", pointerListenerFn, opts);
56
+ }
57
+ function stopPointerTracking() {
58
+ if (!pointerListenerFn) return;
59
+ const opts = { capture: true };
60
+ window.removeEventListener("pointerenter", pointerListenerFn, opts);
61
+ window.removeEventListener("pointerover", pointerListenerFn, opts);
62
+ window.removeEventListener("mouseenter", pointerListenerFn, opts);
63
+ window.removeEventListener("mouseover", pointerListenerFn, opts);
64
+ pointerListenerFn = null;
65
+ if (pointerWindowTimer) {
66
+ clearTimeout(pointerWindowTimer);
67
+ pointerWindowTimer = null;
101
68
  }
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;
69
+ inPointerWindow = false;
114
70
  }
115
71
  function patchAnimate() {
116
72
  if (originalAnimate) return;
@@ -122,34 +78,15 @@ function createAnimationStopModule() {
122
78
  if (isWidgetInternal(this)) {
123
79
  return originalAnimate.call(this, keyframes, options);
124
80
  }
125
- if (isVisualOnlyKeyframes(keyframes)) {
126
- const anim2 = originalAnimate.call(this, keyframes, options);
81
+ if (inPointerWindow) {
82
+ const anim = originalAnimate.call(this, keyframes, options);
127
83
  try {
128
- anim2.cancel();
84
+ anim.cancel();
129
85
  } catch {
130
86
  }
131
- return anim2;
132
- }
133
- let opts;
134
- if (typeof options === "number") {
135
- opts = { duration: 1e-3, fill: "forwards" };
136
- } else {
137
- opts = {
138
- ...options || {},
139
- duration: 1e-3,
140
- delay: 0,
141
- iterations: 1,
142
- fill: "forwards"
143
- };
144
- delete opts.iterationStart;
145
- delete opts.endDelay;
87
+ return anim;
146
88
  }
147
- const anim = originalAnimate.call(this, keyframes, opts);
148
- try {
149
- anim.finish();
150
- } catch {
151
- }
152
- return anim;
89
+ return originalAnimate.call(this, keyframes, options);
153
90
  };
154
91
  }
155
92
  function restoreAnimate() {
@@ -185,36 +122,8 @@ function createAnimationStopModule() {
185
122
  const animations = document.getAnimations?.();
186
123
  if (!animations) return;
187
124
  for (const anim of animations) {
188
- const target = anim.effect?.target;
189
- if (target && isWidgetInternal(target)) continue;
190
- let visualOnly = false;
191
125
  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
- }
212
- try {
213
- if (visualOnly) {
214
- anim.cancel();
215
- } else {
216
- anim.finish();
217
- }
126
+ anim.finish();
218
127
  } catch {
219
128
  try {
220
129
  anim.cancel();
@@ -486,7 +395,7 @@ function createAnimationStopModule() {
486
395
  function activate() {
487
396
  if (enabled) return;
488
397
  enabled = true;
489
- patchMatchMedia();
398
+ startPointerTracking();
490
399
  patchAnimate();
491
400
  injectStyles();
492
401
  finishAllAnimations();
@@ -517,7 +426,7 @@ function createAnimationStopModule() {
517
426
  stopPeriodicScan();
518
427
  teardownObserver();
519
428
  restoreAnimate();
520
- restoreMatchMedia();
429
+ stopPointerTracking();
521
430
  unfreezeScrollAnimations();
522
431
  restoreGSAP();
523
432
  restoreHiddenElements();
@@ -546,4 +455,4 @@ function createAnimationStopModule() {
546
455
  export {
547
456
  createAnimationStopModule as default
548
457
  };
549
- //# sourceMappingURL=animation-stop-sX4g8tF2.js.map
458
+ //# sourceMappingURL=animation-stop-Bv6xRU2q.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation-stop-Bv6xRU2q.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/**\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 if (n.tagName === 'ACCESSIFY-WIDGET') return true;\n const cls = n.getAttribute?.('class');\n if (cls && /(?:^|\\s)accessify-/.test(cls)) return true;\n }\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\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 pausedVideos: HTMLVideoElement[] = [];\n let gifOriginals = new Map<HTMLImageElement, string>();\n\n // --- Pointer-window state ---\n // Framer Motion's whileHover creates a WAAPI animation synchronously in\n // response to a pointerenter event. We set this flag for ~120ms whenever\n // a pointer enters a non-widget element, so patchAnimate() can tell\n // \"this animate() call is a hover gesture\" vs \"this is an entry/scroll\n // animation created at mount\". Hover animations are cancelled (revert to\n // baseline); everything else passes through untouched.\n let inPointerWindow = false;\n let pointerWindowTimer: ReturnType<typeof setTimeout> | null = null;\n let pointerListenerFn: ((e: Event) => void) | null = null;\n\n // =========================================================================\n // Layer 0a: Pointer-window tracking\n //\n // When a pointer enters a non-widget element we open a ~120ms window where\n // any new Element.animate() call is classified as a HOVER gesture and\n // cancelled (reverts to baseline). Outside this window animate() is a\n // pass-through, so entry/scroll/layout animations at mount still reach\n // their target state. This is how we distinguish Framer's whileHover from\n // its initial=\"hidden\" / animate=\"show\" entry transforms (both use y/scale).\n // =========================================================================\n\n function openPointerWindow(e: Event) {\n // Ignore pointer events over our own widget — our card/trigger hover FX\n // must keep working and are excluded from the cancel logic anyway.\n const path = (e as any).composedPath ? (e as any).composedPath() : [];\n const target = (path && path[0]) || (e.target as Node | null);\n if (isWidgetInternal(target)) return;\n\n inPointerWindow = true;\n if (pointerWindowTimer) clearTimeout(pointerWindowTimer);\n pointerWindowTimer = setTimeout(() => {\n inPointerWindow = false;\n pointerWindowTimer = null;\n }, 120);\n }\n\n function startPointerTracking() {\n if (pointerListenerFn) return;\n pointerListenerFn = openPointerWindow;\n // Capture phase on window so we fire BEFORE any React/Framer listener\n // registered on descendants. passive:true = no preventDefault side-effect.\n const opts: AddEventListenerOptions = { capture: true, passive: true };\n window.addEventListener('pointerenter', pointerListenerFn, opts);\n window.addEventListener('pointerover', pointerListenerFn, opts);\n window.addEventListener('mouseenter', pointerListenerFn, opts);\n window.addEventListener('mouseover', pointerListenerFn, opts);\n }\n\n function stopPointerTracking() {\n if (!pointerListenerFn) return;\n const opts: AddEventListenerOptions = { capture: true };\n window.removeEventListener('pointerenter', pointerListenerFn, opts);\n window.removeEventListener('pointerover', pointerListenerFn, opts);\n window.removeEventListener('mouseenter', pointerListenerFn, opts);\n window.removeEventListener('mouseover', pointerListenerFn, opts);\n pointerListenerFn = null;\n if (pointerWindowTimer) {\n clearTimeout(pointerWindowTimer);\n pointerWindowTimer = null;\n }\n inPointerWindow = false;\n }\n\n // =========================================================================\n // Layer 0b: Element.prototype.animate() intercept\n //\n // PASS-THROUGH by default so entry/scroll/layout animations land where\n // Framer intends them to land (important — `y: [20, 0]` must reach y:0\n // or the element stays stuck 20px off). ONLY inside the pointer-window\n // do we treat the animation as a hover gesture: create then cancel(),\n // which reverts the element to its baseline and kills visible hover\n // zoom/translate effects.\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 // Widget-internal (our own shadow DOM hover FX) — passthrough always\n if (isWidgetInternal(this)) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n // Hover gesture window: Framer just created this in response to a\n // pointerenter on a non-widget element. Run original then cancel()\n // to revert to baseline. No persisted zoom.\n if (inPointerWindow) {\n const anim = originalAnimate!.call(this, keyframes, options);\n try { anim.cancel(); } catch { /* ignore */ }\n return anim;\n }\n\n // Everything else (entry, scroll, layout, appear): passthrough.\n // CSS injection already caps CSS animation/transition duration so\n // intrinsic motion is effectively instantaneous; WAAPI entry\n // animations are allowed to run their natural course so elements\n // reach their final positioned state.\n return originalAnimate!.call(this, keyframes, options);\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 try {\n anim.finish();\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 0a: Track pointer-window so patchAnimate() can classify hover vs entry\n startPointerTracking();\n\n // Layer 0b: Intercept Element.animate() — only cancels animations created\n // inside the pointer-window (= Framer whileHover). Entry animations pass through.\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 stopPointerTracking();\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":[],"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-BzHTCdxB.js"),
6623
+ "keyboard-nav": () => import("./keyboard-nav-B57Xk_1n.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-sX4g8tF2.js"),
6627
+ "animation-stop": () => import("./animation-stop-Bv6xRU2q.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-B1V2uLzY.js"),
6630
+ "page-structure": () => import("./page-structure-Dnpn3tuh.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)
@@ -9030,4 +9030,4 @@ export {
9030
9030
  init as i,
9031
9031
  t
9032
9032
  };
9033
- //# sourceMappingURL=index-BAnoPX-u.js.map
9033
+ //# sourceMappingURL=index-Bz63wH7t.js.map