prime8dev

prime8dev
git clone https://git.prime8.dev/prime8dev.git
Log | Files | Refs | README | LICENSE

reveal.js (2236B)


      1 const SKIP = new Set(["STYLE", "SCRIPT", "TEMPLATE", "NOSCRIPT"]);
      2 const ATOMIC = new Set(["PRE", "IMG", "SVG", "VIDEO", "CANVAS", "IFRAME", "TABLE"]);
      3 const BLOCKISH = /^(block|flex|grid|list-item|table|flow-root)$/;
      4 const BUDGET_MS = 450;
      5 const MAX_STEP_MS = 14;
      6 
      7 const pending = new Map();
      8 
      9 export function revealLines(root) {
     10   if (!root || window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
     11 
     12   for (const [r] of pending) {
     13     if (r === root || r.contains(root) || root.contains(r)) cleanup(r);
     14   }
     15 
     16   const lines = collectLines(root).filter(onScreen);
     17   if (lines.length === 0) return;
     18 
     19   const step = Math.min(MAX_STEP_MS, BUDGET_MS / lines.length);
     20   root.style.setProperty("--line-ms", `${step}ms`);
     21   lines.forEach((el, i) => {
     22     el.style.setProperty("--line", String(i));
     23     el.classList.add("line-in");
     24   });
     25 
     26   const timer = window.setTimeout(() => cleanup(root), step * lines.length + 50);
     27   pending.set(root, { lines, timer });
     28 }
     29 
     30 function cleanup(root) {
     31   const entry = pending.get(root);
     32   if (!entry) return;
     33   pending.delete(root);
     34   window.clearTimeout(entry.timer);
     35   root.style.removeProperty("--line-ms");
     36   for (const el of entry.lines) {
     37     el.classList.remove("line-in");
     38     el.style.removeProperty("--line");
     39   }
     40   // hidden lines drop focus, so anything that wants it can take it back now
     41   document.dispatchEvent(new CustomEvent("reveal:done"));
     42 }
     43 
     44 function onScreen(el) {
     45   const r = el.getBoundingClientRect();
     46   return r.bottom > 0 && r.top < window.innerHeight && r.width > 0;
     47 }
     48 
     49 function collectLines(root) {
     50   const lines = [];
     51   const walk = (el) => {
     52     for (const child of el.children) {
     53       if (SKIP.has(child.tagName)) continue;
     54       if (getComputedStyle(child).display === "none") continue;
     55       if (isLine(child)) {
     56         lines.push(child);
     57       } else {
     58         walk(child);
     59       }
     60     }
     61   };
     62   walk(root);
     63   return lines;
     64 }
     65 
     66 function isLine(el) {
     67   if (ATOMIC.has(el.tagName.toUpperCase())) return true;
     68   if (el.classList.contains("tags") || el.classList.contains("tag")) return true;
     69   for (const child of el.children) {
     70     if (SKIP.has(child.tagName)) continue;
     71     if (BLOCKISH.test(getComputedStyle(child).display)) return false;
     72   }
     73   return true;
     74 }