// Minimal CSS syntax highlighter for the docs (shared). // It converts plain-text CSS inside `.css-view` into highlighted HTML using // the existing demo.css token classes: .kwd .str .num .punc .com .attr .val .fun (function () { function escapeHtml(s) { return String(s) .replace(/&/g, '&') .replace(//g, '>'); } function highlightCSS(input) { let s = escapeHtml(input); // Comments s = s.replace(/\/\*[\s\S]*?\*\//g, (m) => `${m}`); // Strings s = s.replace(/("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/g, (m) => `${m}`); // @rules s = s.replace(/(^|\s)(@[\w-]+)/g, (m, p1, p2) => `${p1}${p2}`); // Hex colors s = s.replace(/(#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8}))/g, (m) => `${m}`); // Numbers with units (very rough, but good enough visually) s = s.replace(/(\b\d+(?:\.\d+)?)(%|px|rem|em|vh|vw|vmin|vmax|deg|turn|s|ms)?\b/g, (m, n, unit) => { return `${n}${unit || ''}`; }); // Property names: "prop: value" s = s.replace(/(^|\n)(\s*)([a-zA-Z_-][\w-]*)(\s*):/g, (m, p1, ws, prop, ws2) => { return `${p1}${ws}${prop}${ws2}:`; }); // Highlight braces / punctuation s = s.replace(/([{}();,])/g, (m) => `${m}`); // Selectors (line before "{"), skip @rules s = s.replace(/(^|\n)([^\n{]+?)(\s*)(\{<\/span>)/g, (m, p1, sel, ws, brace) => { const trimmed = sel.trimStart(); if (trimmed.startsWith('@')) return `${p1}${sel}${ws}${brace}`; return `${p1}${sel}${ws}${brace}`; }); // Values: after ":" until ";" or "}" (best-effort, runs after punctuation) s = s.replace(/(:<\/span>)([^;\n}]+)(?=(;|\}))/g, (m, colon, val) => { // avoid re-highlighting spans if (val.includes('${val}`; }); return s; } function enhance() { const blocks = document.querySelectorAll('.css-view'); blocks.forEach((el) => { try { if (el.dataset.highlighted === '1') return; const text = el.textContent || ''; // If already contains spans, assume it's already highlighted. if (el.innerHTML.includes(' { const tab = e.target && e.target.closest ? e.target.closest('.tab') : null; if (!tab) return; const label = (tab.textContent || '').trim().toLowerCase(); if (label === 'css') { // Defer so the tab switch can toggle DOM/classes first setTimeout(enhance, 0); } }, true ); // Observe DOM changes to catch dynamically added `.css-view` blocks. try { const mo = new MutationObserver(() => { // Cheap debounce via microtask Promise.resolve().then(enhance); }); mo.observe(document.documentElement, { subtree: true, childList: true, characterData: true }); } catch (_) {} })();