// icon.jsx — safe Icon for lucide UMD v0.395 // lucide.icons[Key] is the array form: ["svg", attrs, [["path", {...}], ...]] // We build SVG markup ourselves at mount time (no DOM mutation after render). const Icon = ({ name, size = 18, stroke = 2, className, style }) => { const html = React.useMemo(() => { const lib = window.lucide && window.lucide.icons; if (!lib) return ''; const key = name .split('-') .map(s => s.charAt(0).toUpperCase() + s.slice(1)) .join(''); const node = lib[key] || lib[name]; if (!node) return ''; // Some lucide builds expose IconNode form: { toSvg } | array form if (node && typeof node.toSvg === 'function') { return node.toSvg({ width: size, height: size, 'stroke-width': stroke }); } if (!Array.isArray(node)) return ''; const renderNode = (n) => { if (!Array.isArray(n)) return ''; const [tag, attrs, children] = n; const attrStr = Object.entries(attrs || {}) .map(([k, v]) => `${k}="${String(v).replace(/"/g, '"')}"`) .join(' '); const inner = Array.isArray(children) ? children.map(renderNode).join('') : ''; return `<${tag} ${attrStr}>${inner}`; }; // Top level: ["svg", attrs, children] const [, attrs, children] = node; const merged = { ...(attrs || {}), width: size, height: size, 'stroke-width': stroke, }; const attrStr = Object.entries(merged) .map(([k, v]) => `${k}="${String(v).replace(/"/g, '"')}"`) .join(' '); const inner = Array.isArray(children) ? children.map(renderNode).join('') : ''; return `${inner}`; }, [name, size, stroke]); return ( ); }; window.Icon = Icon;