// @ai-invariant: This is a high-risk module. Preserve its core logic and minimize external side effects during modification. /*************** Facilitates the dynamic loading and hydration of Lordicon elements based on viewport visibility. Do not handle raw content parsing for icons. Do not manage global application state or configuration. Do not perform network requests outside of JSON prefetching. RFC-1097: step 6 — compass.migrate codemod run Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order. RFC-1097: sweep — werkstatt-engine clean Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics. RFC-1175 AC-5: scheduleTask statically imported (single orchestrator chunk); prefetchJsonOnce skips data: URIs — icon JSONs reach the DOM as data: URIs via ?url + vite assetsInlineLimit, needing no network prefetch. ***************/ import { scheduleTask } from "./scheduler.ts"; async function initLordIcon(): Promise { const { defineElement } = await import("@lordicon/element"); defineElement(); } let lordIconLoaderPromise: Promise | null = null; const jsonPrefetchCache = new Map>(); const ensureLordIconLoaded = () => { if (!lordIconLoaderPromise) { lordIconLoaderPromise = new Promise((resolve) => { void (async () => { scheduleTask(async () => { await initLordIcon(); resolve(); }); })(); }); } return lordIconLoaderPromise; }; const prefetchJsonOnce = (url: string) => { // RFC-1175: inlined data: URIs need no prefetch — the bytes are in the DOM. if (url.startsWith("data:")) return Promise.resolve(); const existing = jsonPrefetchCache.get(url); if (existing) return existing; const p = fetch(url, { cache: "force-cache" }) .then(() => {}) .catch(() => {}); jsonPrefetchCache.set(url, p); return p; }; export function initLordIconOnDemand(): void { const icons = Array.from(document.querySelectorAll("lord-icon")); if (!icons.length) return; const hydrateIcon = async (icon: HTMLElement) => { // 1. Ensure library is loaded/loading ensureLordIconLoaded(); // 2. Swap src if needed const src = icon.getAttribute("data-src"); if (src && !icon.getAttribute("src")) { void prefetchJsonOnce(src); icon.setAttribute("src", src); } }; if (typeof IntersectionObserver !== "function") { // Fallback: load everything immediately ensureLordIconLoaded(); icons.forEach((icon) => { const src = icon.getAttribute("data-src"); if (src) icon.setAttribute("src", src); }); return; } const observer = new IntersectionObserver( (entries) => { for (const entry of entries) { if (entry.isIntersecting) { const icon = entry.target as HTMLElement; hydrateIcon(icon); observer.unobserve(icon); } } }, { rootMargin: "100px" }, // Smaller margin to defer loading of far-off icons ); for (const icon of icons) { observer.observe(icon); } }