(doc: Document, target: string, animated: string[])
| 468 | |
| 469 | // Animated-target selectors of `target`'s DOM ancestors (in order, parent-first). |
| 470 | function animatedAncestors(doc: Document, target: string, animated: string[]): string[] { |
| 471 | let el: Element | null = null; |
| 472 | try { |
| 473 | el = doc.querySelector(target); |
| 474 | } catch { |
| 475 | return []; |
| 476 | } |
| 477 | const out: string[] = []; |
| 478 | for (let n = el?.parentElement ?? null; n; n = n.parentElement) { |
| 479 | for (const sel of animated) { |
| 480 | if (sel !== target && !out.includes(sel) && safeMatches(n, sel)) out.push(sel); |
| 481 | } |
| 482 | } |
| 483 | return out; |
| 484 | } |
| 485 | |
| 486 | // Compact extent summary of an element's motion: each animated property's min..max |
| 487 | // across all its keyframes. Ranges (not endpoints) so a CLOSED loop — a figure-8 |
no test coverage detected