@seed-ship/mcp-ui-solid 2.2.10 → 2.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,9 +4,10 @@ const web = require("solid-js/web");
4
4
  var _tmpl$ = /* @__PURE__ */ web.template(`<div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"><div class="flex items-center gap-3"><div class="w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-md shadow-sm text-xl"></div><div><h4 class="text-sm font-medium text-gray-900 dark:text-white truncate max-w-[200px]"></h4><p class="text-xs text-gray-500 dark:text-gray-400"><!$><!/> • <!$><!/></p></div></div><a class="px-3 py-1.5 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/40 rounded-md transition-colors flex items-center gap-1"><svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>Download`);
5
5
  const ArtifactRenderer = (props) => {
6
6
  const getIcon = () => {
7
- if (props.params.mimeType.includes("csv")) return "📊";
8
- if (props.params.mimeType.includes("json")) return "{}";
9
- if (props.params.mimeType.includes("pdf")) return "📄";
7
+ var _a, _b, _c;
8
+ if ((_a = props.params.mimeType) == null ? void 0 : _a.includes("csv")) return "📊";
9
+ if ((_b = props.params.mimeType) == null ? void 0 : _b.includes("json")) return "{}";
10
+ if ((_c = props.params.mimeType) == null ? void 0 : _c.includes("pdf")) return "📄";
10
11
  return "📁";
11
12
  };
12
13
  const formatSize = (bytes) => {
@@ -1 +1 @@
1
- {"version":3,"file":"ArtifactRenderer.cjs","sources":["../../src/components/ArtifactRenderer.tsx"],"sourcesContent":["import { Component } from 'solid-js'\n\nexport interface ArtifactComponentParams {\n url: string\n filename: string\n mimeType: string\n size?: number\n description?: string\n}\n\nexport const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> = (props) => {\n const getIcon = () => {\n if (props.params.mimeType.includes('csv')) return '📊'\n if (props.params.mimeType.includes('json')) return '{}'\n if (props.params.mimeType.includes('pdf')) return '📄'\n return '📁'\n }\n\n const formatSize = (bytes?: number) => {\n if (!bytes) return ''\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n\n return (\n <div class=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors\">\n <div class=\"flex items-center gap-3\">\n <div class=\"w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-md shadow-sm text-xl\">\n {getIcon()}\n </div>\n <div>\n <h4 class=\"text-sm font-medium text-gray-900 dark:text-white truncate max-w-[200px]\">\n {props.params.filename}\n </h4>\n <p class=\"text-xs text-gray-500 dark:text-gray-400\">\n {formatSize(props.params.size)} • {props.params.description || 'Generated artifact'}\n </p>\n </div>\n </div>\n\n <a\n href={props.params.url}\n download={props.params.filename}\n class=\"px-3 py-1.5 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/40 rounded-md transition-colors flex items-center gap-1\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Download\n </a>\n </div>\n )\n}\n"],"names":["ArtifactRenderer","props","getIcon","params","mimeType","includes","formatSize","bytes","toFixed","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$9","_co$","_$getNextMarker","_el$7","_el$0","_el$1","_co$2","_el$10","_$insert","filename","size","description","_$effect","_p$","_v$","url","_v$2","e","_$setAttribute","t","undefined"],"mappings":";;;;AAUO,MAAMA,mBAAoEC,CAAAA,UAAU;AACvF,QAAMC,UAAUA,MAAM;AAClB,QAAID,MAAME,OAAOC,SAASC,SAAS,KAAK,EAAG,QAAO;AAClD,QAAIJ,MAAME,OAAOC,SAASC,SAAS,MAAM,EAAG,QAAO;AACnD,QAAIJ,MAAME,OAAOC,SAASC,SAAS,KAAK,EAAG,QAAO;AAClD,WAAO;AAAA,EACX;AAEA,QAAMC,aAAaA,CAACC,UAAmB;AACnC,QAAI,CAACA,MAAO,QAAO;AACnB,QAAIA,QAAQ,KAAM,QAAO,GAAGA,KAAK;AACjC,QAAIA,QAAQ,OAAO,KAAM,QAAO,IAAIA,QAAQ,MAAMC,QAAQ,CAAC,CAAC;AAC5D,WAAO,IAAID,SAAS,OAAO,OAAOC,QAAQ,CAAC,CAAC;AAAA,EAChD;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,mBAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAE,aAAAC,QAAAF,MAAAF,YAAAK,QAAAD,MAAAD,aAAAG,QAAAD,MAAAL,YAAA,CAAAO,OAAAC,IAAA,IAAAC,IAAAA,cAAAH,MAAAH,WAAA,GAAAO,QAAAH,MAAAJ,aAAAQ,QAAAD,MAAAP,aAAA,CAAAS,OAAAC,KAAA,IAAAJ,IAAAA,cAAAE,MAAAR,WAAA,GAAAW,SAAAf,MAAAI;AAAAY,QAAAA,OAAAd,OAIiBZ,OAAO;AAAA0B,QAAAA,OAAAX,OAAA,MAIHhB,MAAME,OAAO0B,QAAQ;AAAAD,eAAAV,OAAA,MAGrBZ,WAAWL,MAAME,OAAO2B,IAAI,GAACV,OAAAC,IAAA;AAAAO,eAAAV,OAAA,MAAKjB,MAAME,OAAO4B,eAAe,sBAAoBN,OAAAC,KAAA;AAAAM,QAAAA,OAAAC,CAAAA,QAAA;AAAA,UAAAC,MAMrFjC,MAAME,OAAOgC,KAAGC,OACZnC,MAAME,OAAO0B;AAAQK,cAAAD,IAAAI,KAAAC,IAAAA,aAAAX,QAAA,QAAAM,IAAAI,IAAAH,GAAA;AAAAE,eAAAH,IAAAM,KAAAD,IAAAA,aAAAX,QAAA,YAAAM,IAAAM,IAAAH,IAAA;AAAA,aAAAH;AAAAA,IAAA,GAAA;AAAA,MAAAI,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAA,WAAA/B;AAAAA,EAAA,GAAA;AAU/C;;"}
1
+ {"version":3,"file":"ArtifactRenderer.cjs","sources":["../../src/components/ArtifactRenderer.tsx"],"sourcesContent":["import { Component } from 'solid-js'\n\nexport interface ArtifactComponentParams {\n url: string\n filename: string\n mimeType: string\n size?: number\n description?: string\n}\n\nexport const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> = (props) => {\n const getIcon = () => {\n if (props.params.mimeType?.includes('csv')) return '📊'\n if (props.params.mimeType?.includes('json')) return '{}'\n if (props.params.mimeType?.includes('pdf')) return '📄'\n return '📁'\n }\n\n const formatSize = (bytes?: number) => {\n if (!bytes) return ''\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n\n return (\n <div class=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors\">\n <div class=\"flex items-center gap-3\">\n <div class=\"w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-md shadow-sm text-xl\">\n {getIcon()}\n </div>\n <div>\n <h4 class=\"text-sm font-medium text-gray-900 dark:text-white truncate max-w-[200px]\">\n {props.params.filename}\n </h4>\n <p class=\"text-xs text-gray-500 dark:text-gray-400\">\n {formatSize(props.params.size)} • {props.params.description || 'Generated artifact'}\n </p>\n </div>\n </div>\n\n <a\n href={props.params.url}\n download={props.params.filename}\n class=\"px-3 py-1.5 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/40 rounded-md transition-colors flex items-center gap-1\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Download\n </a>\n </div>\n )\n}\n"],"names":["ArtifactRenderer","props","getIcon","params","mimeType","includes","formatSize","bytes","toFixed","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$9","_co$","_$getNextMarker","_el$7","_el$0","_el$1","_co$2","_el$10","_$insert","filename","size","description","_$effect","_p$","_v$","url","_v$2","e","_$setAttribute","t","undefined"],"mappings":";;;;AAUO,MAAMA,mBAAoEC,CAAAA,UAAU;AACvF,QAAMC,UAAUA,MAAM;;AAClB,SAAID,WAAME,OAAOC,aAAbH,mBAAuBI,SAAS,OAAQ,QAAO;AACnD,SAAIJ,WAAME,OAAOC,aAAbH,mBAAuBI,SAAS,QAAS,QAAO;AACpD,SAAIJ,WAAME,OAAOC,aAAbH,mBAAuBI,SAAS,OAAQ,QAAO;AACnD,WAAO;AAAA,EACX;AAEA,QAAMC,aAAaA,CAACC,UAAmB;AACnC,QAAI,CAACA,MAAO,QAAO;AACnB,QAAIA,QAAQ,KAAM,QAAO,GAAGA,KAAK;AACjC,QAAIA,QAAQ,OAAO,KAAM,QAAO,IAAIA,QAAQ,MAAMC,QAAQ,CAAC,CAAC;AAC5D,WAAO,IAAID,SAAS,OAAO,OAAOC,QAAQ,CAAC,CAAC;AAAA,EAChD;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,mBAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAE,aAAAC,QAAAF,MAAAF,YAAAK,QAAAD,MAAAD,aAAAG,QAAAD,MAAAL,YAAA,CAAAO,OAAAC,IAAA,IAAAC,IAAAA,cAAAH,MAAAH,WAAA,GAAAO,QAAAH,MAAAJ,aAAAQ,QAAAD,MAAAP,aAAA,CAAAS,OAAAC,KAAA,IAAAJ,IAAAA,cAAAE,MAAAR,WAAA,GAAAW,SAAAf,MAAAI;AAAAY,QAAAA,OAAAd,OAIiBZ,OAAO;AAAA0B,QAAAA,OAAAX,OAAA,MAIHhB,MAAME,OAAO0B,QAAQ;AAAAD,eAAAV,OAAA,MAGrBZ,WAAWL,MAAME,OAAO2B,IAAI,GAACV,OAAAC,IAAA;AAAAO,eAAAV,OAAA,MAAKjB,MAAME,OAAO4B,eAAe,sBAAoBN,OAAAC,KAAA;AAAAM,QAAAA,OAAAC,CAAAA,QAAA;AAAA,UAAAC,MAMrFjC,MAAME,OAAOgC,KAAGC,OACZnC,MAAME,OAAO0B;AAAQK,cAAAD,IAAAI,KAAAC,IAAAA,aAAAX,QAAA,QAAAM,IAAAI,IAAAH,GAAA;AAAAE,eAAAH,IAAAM,KAAAD,IAAAA,aAAAX,QAAA,YAAAM,IAAAM,IAAAH,IAAA;AAAA,aAAAH;AAAAA,IAAA,GAAA;AAAA,MAAAI,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAA,WAAA/B;AAAAA,EAAA,GAAA;AAU/C;;"}
@@ -2,9 +2,10 @@ import { getNextElement, template, getNextMarker, insert, effect, setAttribute }
2
2
  var _tmpl$ = /* @__PURE__ */ template(`<div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"><div class="flex items-center gap-3"><div class="w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-md shadow-sm text-xl"></div><div><h4 class="text-sm font-medium text-gray-900 dark:text-white truncate max-w-[200px]"></h4><p class="text-xs text-gray-500 dark:text-gray-400"><!$><!/> • <!$><!/></p></div></div><a class="px-3 py-1.5 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/40 rounded-md transition-colors flex items-center gap-1"><svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>Download`);
3
3
  const ArtifactRenderer = (props) => {
4
4
  const getIcon = () => {
5
- if (props.params.mimeType.includes("csv")) return "📊";
6
- if (props.params.mimeType.includes("json")) return "{}";
7
- if (props.params.mimeType.includes("pdf")) return "📄";
5
+ var _a, _b, _c;
6
+ if ((_a = props.params.mimeType) == null ? void 0 : _a.includes("csv")) return "📊";
7
+ if ((_b = props.params.mimeType) == null ? void 0 : _b.includes("json")) return "{}";
8
+ if ((_c = props.params.mimeType) == null ? void 0 : _c.includes("pdf")) return "📄";
8
9
  return "📁";
9
10
  };
10
11
  const formatSize = (bytes) => {
@@ -1 +1 @@
1
- {"version":3,"file":"ArtifactRenderer.js","sources":["../../src/components/ArtifactRenderer.tsx"],"sourcesContent":["import { Component } from 'solid-js'\n\nexport interface ArtifactComponentParams {\n url: string\n filename: string\n mimeType: string\n size?: number\n description?: string\n}\n\nexport const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> = (props) => {\n const getIcon = () => {\n if (props.params.mimeType.includes('csv')) return '📊'\n if (props.params.mimeType.includes('json')) return '{}'\n if (props.params.mimeType.includes('pdf')) return '📄'\n return '📁'\n }\n\n const formatSize = (bytes?: number) => {\n if (!bytes) return ''\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n\n return (\n <div class=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors\">\n <div class=\"flex items-center gap-3\">\n <div class=\"w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-md shadow-sm text-xl\">\n {getIcon()}\n </div>\n <div>\n <h4 class=\"text-sm font-medium text-gray-900 dark:text-white truncate max-w-[200px]\">\n {props.params.filename}\n </h4>\n <p class=\"text-xs text-gray-500 dark:text-gray-400\">\n {formatSize(props.params.size)} • {props.params.description || 'Generated artifact'}\n </p>\n </div>\n </div>\n\n <a\n href={props.params.url}\n download={props.params.filename}\n class=\"px-3 py-1.5 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/40 rounded-md transition-colors flex items-center gap-1\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Download\n </a>\n </div>\n )\n}\n"],"names":["ArtifactRenderer","props","getIcon","params","mimeType","includes","formatSize","bytes","toFixed","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$9","_co$","_$getNextMarker","_el$7","_el$0","_el$1","_co$2","_el$10","_$insert","filename","size","description","_$effect","_p$","_v$","url","_v$2","e","_$setAttribute","t","undefined"],"mappings":";;AAUO,MAAMA,mBAAoEC,CAAAA,UAAU;AACvF,QAAMC,UAAUA,MAAM;AAClB,QAAID,MAAME,OAAOC,SAASC,SAAS,KAAK,EAAG,QAAO;AAClD,QAAIJ,MAAME,OAAOC,SAASC,SAAS,MAAM,EAAG,QAAO;AACnD,QAAIJ,MAAME,OAAOC,SAASC,SAAS,KAAK,EAAG,QAAO;AAClD,WAAO;AAAA,EACX;AAEA,QAAMC,aAAaA,CAACC,UAAmB;AACnC,QAAI,CAACA,MAAO,QAAO;AACnB,QAAIA,QAAQ,KAAM,QAAO,GAAGA,KAAK;AACjC,QAAIA,QAAQ,OAAO,KAAM,QAAO,IAAIA,QAAQ,MAAMC,QAAQ,CAAC,CAAC;AAC5D,WAAO,IAAID,SAAS,OAAO,OAAOC,QAAQ,CAAC,CAAC;AAAA,EAChD;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAE,aAAAC,QAAAF,MAAAF,YAAAK,QAAAD,MAAAD,aAAAG,QAAAD,MAAAL,YAAA,CAAAO,OAAAC,IAAA,IAAAC,cAAAH,MAAAH,WAAA,GAAAO,QAAAH,MAAAJ,aAAAQ,QAAAD,MAAAP,aAAA,CAAAS,OAAAC,KAAA,IAAAJ,cAAAE,MAAAR,WAAA,GAAAW,SAAAf,MAAAI;AAAAY,WAAAd,OAIiBZ,OAAO;AAAA0B,WAAAX,OAAA,MAIHhB,MAAME,OAAO0B,QAAQ;AAAAD,WAAAV,OAAA,MAGrBZ,WAAWL,MAAME,OAAO2B,IAAI,GAACV,OAAAC,IAAA;AAAAO,WAAAV,OAAA,MAAKjB,MAAME,OAAO4B,eAAe,sBAAoBN,OAAAC,KAAA;AAAAM,WAAAC,CAAAA,QAAA;AAAA,UAAAC,MAMrFjC,MAAME,OAAOgC,KAAGC,OACZnC,MAAME,OAAO0B;AAAQK,cAAAD,IAAAI,KAAAC,aAAAX,QAAA,QAAAM,IAAAI,IAAAH,GAAA;AAAAE,eAAAH,IAAAM,KAAAD,aAAAX,QAAA,YAAAM,IAAAM,IAAAH,IAAA;AAAA,aAAAH;AAAAA,IAAA,GAAA;AAAA,MAAAI,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAA,WAAA/B;AAAAA,EAAA,GAAA;AAU/C;"}
1
+ {"version":3,"file":"ArtifactRenderer.js","sources":["../../src/components/ArtifactRenderer.tsx"],"sourcesContent":["import { Component } from 'solid-js'\n\nexport interface ArtifactComponentParams {\n url: string\n filename: string\n mimeType: string\n size?: number\n description?: string\n}\n\nexport const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> = (props) => {\n const getIcon = () => {\n if (props.params.mimeType?.includes('csv')) return '📊'\n if (props.params.mimeType?.includes('json')) return '{}'\n if (props.params.mimeType?.includes('pdf')) return '📄'\n return '📁'\n }\n\n const formatSize = (bytes?: number) => {\n if (!bytes) return ''\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n\n return (\n <div class=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors\">\n <div class=\"flex items-center gap-3\">\n <div class=\"w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-md shadow-sm text-xl\">\n {getIcon()}\n </div>\n <div>\n <h4 class=\"text-sm font-medium text-gray-900 dark:text-white truncate max-w-[200px]\">\n {props.params.filename}\n </h4>\n <p class=\"text-xs text-gray-500 dark:text-gray-400\">\n {formatSize(props.params.size)} • {props.params.description || 'Generated artifact'}\n </p>\n </div>\n </div>\n\n <a\n href={props.params.url}\n download={props.params.filename}\n class=\"px-3 py-1.5 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/40 rounded-md transition-colors flex items-center gap-1\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Download\n </a>\n </div>\n )\n}\n"],"names":["ArtifactRenderer","props","getIcon","params","mimeType","includes","formatSize","bytes","toFixed","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$9","_co$","_$getNextMarker","_el$7","_el$0","_el$1","_co$2","_el$10","_$insert","filename","size","description","_$effect","_p$","_v$","url","_v$2","e","_$setAttribute","t","undefined"],"mappings":";;AAUO,MAAMA,mBAAoEC,CAAAA,UAAU;AACvF,QAAMC,UAAUA,MAAM;;AAClB,SAAID,WAAME,OAAOC,aAAbH,mBAAuBI,SAAS,OAAQ,QAAO;AACnD,SAAIJ,WAAME,OAAOC,aAAbH,mBAAuBI,SAAS,QAAS,QAAO;AACpD,SAAIJ,WAAME,OAAOC,aAAbH,mBAAuBI,SAAS,OAAQ,QAAO;AACnD,WAAO;AAAA,EACX;AAEA,QAAMC,aAAaA,CAACC,UAAmB;AACnC,QAAI,CAACA,MAAO,QAAO;AACnB,QAAIA,QAAQ,KAAM,QAAO,GAAGA,KAAK;AACjC,QAAIA,QAAQ,OAAO,KAAM,QAAO,IAAIA,QAAQ,MAAMC,QAAQ,CAAC,CAAC;AAC5D,WAAO,IAAID,SAAS,OAAO,OAAOC,QAAQ,CAAC,CAAC;AAAA,EAChD;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAE,aAAAC,QAAAF,MAAAF,YAAAK,QAAAD,MAAAD,aAAAG,QAAAD,MAAAL,YAAA,CAAAO,OAAAC,IAAA,IAAAC,cAAAH,MAAAH,WAAA,GAAAO,QAAAH,MAAAJ,aAAAQ,QAAAD,MAAAP,aAAA,CAAAS,OAAAC,KAAA,IAAAJ,cAAAE,MAAAR,WAAA,GAAAW,SAAAf,MAAAI;AAAAY,WAAAd,OAIiBZ,OAAO;AAAA0B,WAAAX,OAAA,MAIHhB,MAAME,OAAO0B,QAAQ;AAAAD,WAAAV,OAAA,MAGrBZ,WAAWL,MAAME,OAAO2B,IAAI,GAACV,OAAAC,IAAA;AAAAO,WAAAV,OAAA,MAAKjB,MAAME,OAAO4B,eAAe,sBAAoBN,OAAAC,KAAA;AAAAM,WAAAC,CAAAA,QAAA;AAAA,UAAAC,MAMrFjC,MAAME,OAAOgC,KAAGC,OACZnC,MAAME,OAAO0B;AAAQK,cAAAD,IAAAI,KAAAC,aAAAX,QAAA,QAAAM,IAAAI,IAAAH,GAAA;AAAAE,eAAAH,IAAAM,KAAAD,aAAAX,QAAA,YAAAM,IAAAM,IAAAH,IAAA;AAAA,aAAAH;AAAAA,IAAA,GAAA;AAAA,MAAAI,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAA,WAAA/B;AAAAA,EAAA,GAAA;AAU/C;"}
@@ -20,7 +20,12 @@ const CodeBlockRenderer = (props) => {
20
20
  if (!hljs) {
21
21
  try {
22
22
  const module2 = await Promise.resolve().then(() => require("../node_modules/.pnpm/highlight.js@11.11.1/node_modules/highlight.js/es/index.cjs"));
23
- hljs = module2.default || module2;
23
+ const resolved = module2.default || module2;
24
+ if (typeof (resolved == null ? void 0 : resolved.highlight) === "function") {
25
+ hljs = resolved;
26
+ } else {
27
+ console.warn("highlight.js loaded but missing highlight() method");
28
+ }
24
29
  setIsHljsLoaded(true);
25
30
  } catch (e) {
26
31
  console.warn("Failed to load highlight.js", e);
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockRenderer.cjs","sources":["../../src/components/CodeBlockRenderer.tsx"],"sourcesContent":["/**\n * CodeBlockRenderer - Syntax highlighted code block\n * Sprint 6: Code & Maps\n * Sprint Ultimate: Theme Synchronization (U.1)\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show, For } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport type { UIComponent, CodeComponentParams } from '../types'\nimport { ExpandableWrapper } from './ExpandableWrapper'\n\n// Lazy load highlight.js\nlet hljs: any = null\n// Track if styles have been loaded globally\nlet stylesLoaded = false\n\nexport interface CodeBlockRendererProps {\n /**\n * UIComponent containing code params\n */\n component?: UIComponent\n\n /**\n * Direct code params\n */\n params?: CodeComponentParams\n}\n\nexport const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {\n const [highlightedCode, setHighlightedCode] = createSignal<string>('')\n const [isCopied, setIsCopied] = createSignal(false)\n const [isHljsLoaded, setIsHljsLoaded] = createSignal(false)\n const [activeTheme, setActiveTheme] = createSignal<'light' | 'dark'>('dark')\n const [wordWrap, setWordWrap] = createSignal(false)\n\n const params = () => props.params || (props.component?.params as CodeComponentParams)\n\n // Load highlight.js on mount\n createEffect(async () => {\n if (!hljs) {\n try {\n // Use the full highlight.js bundle with all languages for simplicity\n const module = await import('highlight.js')\n hljs = module.default || module\n setIsHljsLoaded(true)\n } catch (e) {\n console.warn('Failed to load highlight.js', e)\n // Continue without highlighting - fallback to plain text\n setIsHljsLoaded(true)\n }\n } else {\n setIsHljsLoaded(true)\n }\n })\n\n // Theme management - Sprint Ultimate U.1: Reactive theme synchronization\n // Load both theme stylesheets once, then toggle via data-attribute\n createEffect(async () => {\n if (isServer || stylesLoaded) return\n\n // Load both themes upfront for instant switching\n try {\n await Promise.all([\n import('highlight.js/styles/github.css'),\n import('highlight.js/styles/github-dark.css')\n ])\n stylesLoaded = true\n } catch (e) {\n console.warn('Failed to load highlight.js themes', e)\n }\n })\n\n // Reactive theme detection - listens to system preference changes\n createEffect(() => {\n if (isServer) return\n\n // Priority 1: Explicit theme from params\n const paramTheme = params()?.theme\n if (paramTheme) {\n setActiveTheme(paramTheme)\n return\n }\n\n // Priority 2: System preference with live updates\n // Check if matchMedia is available (not in all test environments)\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n setActiveTheme(mediaQuery.matches ? 'dark' : 'light')\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only update if no explicit theme in params\n if (!params()?.theme) {\n setActiveTheme(e.matches ? 'dark' : 'light')\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n onCleanup(() => mediaQuery.removeEventListener('change', handleChange))\n }\n })\n\n // Apply highlighting\n createEffect(() => {\n const code = params()?.code || ''\n const language = params()?.language || ''\n\n if (hljs && isHljsLoaded()) {\n try {\n let result\n if (language && hljs.getLanguage(language)) {\n result = hljs.highlight(code, { language }).value\n } else {\n result = hljs.highlightAuto(code).value\n }\n setHighlightedCode(result)\n } catch (e) {\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n } else {\n // Fallback: simple escaping\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n })\n\n // Line numbers generation\n const lineNumbers = () => {\n if (params()?.showLineNumbers === false) return []\n const code = params()?.code || ''\n const lines = code.split('\\n')\n const start = params()?.startLine || 1\n return lines.map((_, i) => start + i)\n }\n\n const handleCopy = async () => {\n const code = params()?.code\n if (code) {\n try {\n await navigator.clipboard.writeText(code)\n setIsCopied(true)\n setTimeout(() => setIsCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy code', e)\n }\n }\n }\n\n return (\n <ExpandableWrapper title={params()?.filename || params()?.language || 'Code'} copyData={params()?.code} copyLabel=\"Copy code\">\n <div class=\"w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col\">\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0\">\n <div class=\"font-mono text-xs text-gray-600 dark:text-gray-400\">\n {params()?.filename || params()?.language || 'Code'}\n </div>\n <div class=\"flex items-center gap-2\">\n {/* Word wrap toggle */}\n <button\n onClick={() => setWordWrap(!wordWrap())}\n class={`focus:outline-none transition-colors ${wordWrap() ? 'text-blue-500 dark:text-blue-400' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}`}\n aria-label=\"Toggle word wrap\"\n title={wordWrap() ? 'Disable word wrap' : 'Enable word wrap'}\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4\" />\n </svg>\n </button>\n {/* Copy button */}\n <button\n onClick={handleCopy}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Copy code\"\n title=\"Copy code\"\n >\n <Show when={isCopied()} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n }>\n <svg class=\"w-4 h-4 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </Show>\n </button>\n </div>\n </div>\n\n {/* Code Area */}\n <div\n class=\"relative overflow-auto flex\"\n style={params()?.maxHeight ? { 'max-height': params()?.maxHeight } : {}}\n >\n {/* Line Numbers */}\n <Show when={params()?.showLineNumbers !== false}>\n <div class=\"flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5\">\n <For each={lineNumbers()}>\n {(num) => <div class=\"px-2\">{num}</div>}\n </For>\n </div>\n </Show>\n\n {/* Code Content - Sprint Ultimate U.1: data-theme for reactive theming */}\n <pre\n class=\"flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5\"\n style={wordWrap() ? { 'white-space': 'pre-wrap', 'word-break': 'break-all' } : {}}\n data-theme={activeTheme()}\n >\n <code\n class={`hljs ${params()?.language ? `language-${params()?.language}` : ''}`}\n innerHTML={highlightedCode()}\n />\n </pre>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["hljs","stylesLoaded","CodeBlockRenderer","props","highlightedCode","setHighlightedCode","createSignal","isCopied","setIsCopied","isHljsLoaded","setIsHljsLoaded","activeTheme","setActiveTheme","wordWrap","setWordWrap","params","component","createEffect","module","default","e","console","warn","isServer","Promise","all","paramTheme","theme","window","matchMedia","mediaQuery","matches","handleChange","addEventListener","onCleanup","removeEventListener","code","language","result","getLanguage","highlight","value","highlightAuto","replace","lineNumbers","showLineNumbers","lines","split","start","startLine","map","_","i","handleCopy","navigator","clipboard","writeText","setTimeout","error","_$createComponent","ExpandableWrapper","title","filename","copyData","copyLabel","children","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$10","_el$11","_co$","_$getNextMarker","_el$0","_el$1","_$insert","$$click","Show","when","fallback","_tmpl$4","_tmpl$","_el$9","_tmpl$2","For","each","num","_el$13","_tmpl$5","_$effect","_p$","_v$","_v$2","_v$3","maxHeight","_v$4","_v$5","_v$6","_v$7","_$className","t","_$setAttribute","a","_$style","o","n","s","_$setProperty","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"CodeBlockRenderer.cjs","sources":["../../src/components/CodeBlockRenderer.tsx"],"sourcesContent":["/**\n * CodeBlockRenderer - Syntax highlighted code block\n * Sprint 6: Code & Maps\n * Sprint Ultimate: Theme Synchronization (U.1)\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show, For } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport type { UIComponent, CodeComponentParams } from '../types'\nimport { ExpandableWrapper } from './ExpandableWrapper'\n\n// Lazy load highlight.js\nlet hljs: any = null\n// Track if styles have been loaded globally\nlet stylesLoaded = false\n\nexport interface CodeBlockRendererProps {\n /**\n * UIComponent containing code params\n */\n component?: UIComponent\n\n /**\n * Direct code params\n */\n params?: CodeComponentParams\n}\n\nexport const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {\n const [highlightedCode, setHighlightedCode] = createSignal<string>('')\n const [isCopied, setIsCopied] = createSignal(false)\n const [isHljsLoaded, setIsHljsLoaded] = createSignal(false)\n const [activeTheme, setActiveTheme] = createSignal<'light' | 'dark'>('dark')\n const [wordWrap, setWordWrap] = createSignal(false)\n\n const params = () => props.params || (props.component?.params as CodeComponentParams)\n\n // Load highlight.js on mount\n createEffect(async () => {\n if (!hljs) {\n try {\n // Use the full highlight.js bundle with all languages for simplicity\n const module = await import('highlight.js')\n const resolved = module.default || module\n // Guard: verify the resolved module has the expected API\n if (typeof resolved?.highlight === 'function') {\n hljs = resolved\n } else {\n console.warn('highlight.js loaded but missing highlight() method')\n }\n setIsHljsLoaded(true)\n } catch (e) {\n console.warn('Failed to load highlight.js', e)\n // Continue without highlighting - fallback to plain text\n setIsHljsLoaded(true)\n }\n } else {\n setIsHljsLoaded(true)\n }\n })\n\n // Theme management - Sprint Ultimate U.1: Reactive theme synchronization\n // Load both theme stylesheets once, then toggle via data-attribute\n createEffect(async () => {\n if (isServer || stylesLoaded) return\n\n // Load both themes upfront for instant switching\n try {\n await Promise.all([\n import('highlight.js/styles/github.css'),\n import('highlight.js/styles/github-dark.css')\n ])\n stylesLoaded = true\n } catch (e) {\n console.warn('Failed to load highlight.js themes', e)\n }\n })\n\n // Reactive theme detection - listens to system preference changes\n createEffect(() => {\n if (isServer) return\n\n // Priority 1: Explicit theme from params\n const paramTheme = params()?.theme\n if (paramTheme) {\n setActiveTheme(paramTheme)\n return\n }\n\n // Priority 2: System preference with live updates\n // Check if matchMedia is available (not in all test environments)\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n setActiveTheme(mediaQuery.matches ? 'dark' : 'light')\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only update if no explicit theme in params\n if (!params()?.theme) {\n setActiveTheme(e.matches ? 'dark' : 'light')\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n onCleanup(() => mediaQuery.removeEventListener('change', handleChange))\n }\n })\n\n // Apply highlighting\n createEffect(() => {\n const code = params()?.code || ''\n const language = params()?.language || ''\n\n if (hljs && isHljsLoaded()) {\n try {\n let result\n if (language && hljs.getLanguage(language)) {\n result = hljs.highlight(code, { language }).value\n } else {\n result = hljs.highlightAuto(code).value\n }\n setHighlightedCode(result)\n } catch (e) {\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n } else {\n // Fallback: simple escaping\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n })\n\n // Line numbers generation\n const lineNumbers = () => {\n if (params()?.showLineNumbers === false) return []\n const code = params()?.code || ''\n const lines = code.split('\\n')\n const start = params()?.startLine || 1\n return lines.map((_, i) => start + i)\n }\n\n const handleCopy = async () => {\n const code = params()?.code\n if (code) {\n try {\n await navigator.clipboard.writeText(code)\n setIsCopied(true)\n setTimeout(() => setIsCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy code', e)\n }\n }\n }\n\n return (\n <ExpandableWrapper title={params()?.filename || params()?.language || 'Code'} copyData={params()?.code} copyLabel=\"Copy code\">\n <div class=\"w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col\">\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0\">\n <div class=\"font-mono text-xs text-gray-600 dark:text-gray-400\">\n {params()?.filename || params()?.language || 'Code'}\n </div>\n <div class=\"flex items-center gap-2\">\n {/* Word wrap toggle */}\n <button\n onClick={() => setWordWrap(!wordWrap())}\n class={`focus:outline-none transition-colors ${wordWrap() ? 'text-blue-500 dark:text-blue-400' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}`}\n aria-label=\"Toggle word wrap\"\n title={wordWrap() ? 'Disable word wrap' : 'Enable word wrap'}\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4\" />\n </svg>\n </button>\n {/* Copy button */}\n <button\n onClick={handleCopy}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Copy code\"\n title=\"Copy code\"\n >\n <Show when={isCopied()} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n }>\n <svg class=\"w-4 h-4 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </Show>\n </button>\n </div>\n </div>\n\n {/* Code Area */}\n <div\n class=\"relative overflow-auto flex\"\n style={params()?.maxHeight ? { 'max-height': params()?.maxHeight } : {}}\n >\n {/* Line Numbers */}\n <Show when={params()?.showLineNumbers !== false}>\n <div class=\"flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5\">\n <For each={lineNumbers()}>\n {(num) => <div class=\"px-2\">{num}</div>}\n </For>\n </div>\n </Show>\n\n {/* Code Content - Sprint Ultimate U.1: data-theme for reactive theming */}\n <pre\n class=\"flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5\"\n style={wordWrap() ? { 'white-space': 'pre-wrap', 'word-break': 'break-all' } : {}}\n data-theme={activeTheme()}\n >\n <code\n class={`hljs ${params()?.language ? `language-${params()?.language}` : ''}`}\n innerHTML={highlightedCode()}\n />\n </pre>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["hljs","stylesLoaded","CodeBlockRenderer","props","highlightedCode","setHighlightedCode","createSignal","isCopied","setIsCopied","isHljsLoaded","setIsHljsLoaded","activeTheme","setActiveTheme","wordWrap","setWordWrap","params","component","createEffect","module","resolved","default","highlight","console","warn","e","isServer","Promise","all","paramTheme","theme","window","matchMedia","mediaQuery","matches","handleChange","addEventListener","onCleanup","removeEventListener","code","language","result","getLanguage","value","highlightAuto","replace","lineNumbers","showLineNumbers","lines","split","start","startLine","map","_","i","handleCopy","navigator","clipboard","writeText","setTimeout","error","_$createComponent","ExpandableWrapper","title","filename","copyData","copyLabel","children","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$10","_el$11","_co$","_$getNextMarker","_el$0","_el$1","_$insert","$$click","Show","when","fallback","_tmpl$4","_tmpl$","_el$9","_tmpl$2","For","each","num","_el$13","_tmpl$5","_$effect","_p$","_v$","_v$2","_v$3","maxHeight","_v$4","_v$5","_v$6","_v$7","_$className","t","_$setAttribute","a","_$style","o","n","s","_$setProperty","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockRenderer.d.ts","sourceRoot":"","sources":["../../src/components/CodeBlockRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAoD,MAAM,UAAU,CAAA;AAEtF,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAQhE,MAAM,WAAW,sBAAsB;IACnC;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,mBAAmB,CAAA;CAC/B;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,sBAAsB,CA2L/D,CAAA"}
1
+ {"version":3,"file":"CodeBlockRenderer.d.ts","sourceRoot":"","sources":["../../src/components/CodeBlockRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAoD,MAAM,UAAU,CAAA;AAEtF,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAQhE,MAAM,WAAW,sBAAsB;IACnC;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,mBAAmB,CAAA;CAC/B;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,sBAAsB,CAiM/D,CAAA"}
@@ -18,7 +18,12 @@ const CodeBlockRenderer = (props) => {
18
18
  if (!hljs) {
19
19
  try {
20
20
  const module = await import("../node_modules/.pnpm/highlight.js@11.11.1/node_modules/highlight.js/es/index.js");
21
- hljs = module.default || module;
21
+ const resolved = module.default || module;
22
+ if (typeof (resolved == null ? void 0 : resolved.highlight) === "function") {
23
+ hljs = resolved;
24
+ } else {
25
+ console.warn("highlight.js loaded but missing highlight() method");
26
+ }
22
27
  setIsHljsLoaded(true);
23
28
  } catch (e) {
24
29
  console.warn("Failed to load highlight.js", e);
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockRenderer.js","sources":["../../src/components/CodeBlockRenderer.tsx"],"sourcesContent":["/**\n * CodeBlockRenderer - Syntax highlighted code block\n * Sprint 6: Code & Maps\n * Sprint Ultimate: Theme Synchronization (U.1)\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show, For } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport type { UIComponent, CodeComponentParams } from '../types'\nimport { ExpandableWrapper } from './ExpandableWrapper'\n\n// Lazy load highlight.js\nlet hljs: any = null\n// Track if styles have been loaded globally\nlet stylesLoaded = false\n\nexport interface CodeBlockRendererProps {\n /**\n * UIComponent containing code params\n */\n component?: UIComponent\n\n /**\n * Direct code params\n */\n params?: CodeComponentParams\n}\n\nexport const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {\n const [highlightedCode, setHighlightedCode] = createSignal<string>('')\n const [isCopied, setIsCopied] = createSignal(false)\n const [isHljsLoaded, setIsHljsLoaded] = createSignal(false)\n const [activeTheme, setActiveTheme] = createSignal<'light' | 'dark'>('dark')\n const [wordWrap, setWordWrap] = createSignal(false)\n\n const params = () => props.params || (props.component?.params as CodeComponentParams)\n\n // Load highlight.js on mount\n createEffect(async () => {\n if (!hljs) {\n try {\n // Use the full highlight.js bundle with all languages for simplicity\n const module = await import('highlight.js')\n hljs = module.default || module\n setIsHljsLoaded(true)\n } catch (e) {\n console.warn('Failed to load highlight.js', e)\n // Continue without highlighting - fallback to plain text\n setIsHljsLoaded(true)\n }\n } else {\n setIsHljsLoaded(true)\n }\n })\n\n // Theme management - Sprint Ultimate U.1: Reactive theme synchronization\n // Load both theme stylesheets once, then toggle via data-attribute\n createEffect(async () => {\n if (isServer || stylesLoaded) return\n\n // Load both themes upfront for instant switching\n try {\n await Promise.all([\n import('highlight.js/styles/github.css'),\n import('highlight.js/styles/github-dark.css')\n ])\n stylesLoaded = true\n } catch (e) {\n console.warn('Failed to load highlight.js themes', e)\n }\n })\n\n // Reactive theme detection - listens to system preference changes\n createEffect(() => {\n if (isServer) return\n\n // Priority 1: Explicit theme from params\n const paramTheme = params()?.theme\n if (paramTheme) {\n setActiveTheme(paramTheme)\n return\n }\n\n // Priority 2: System preference with live updates\n // Check if matchMedia is available (not in all test environments)\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n setActiveTheme(mediaQuery.matches ? 'dark' : 'light')\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only update if no explicit theme in params\n if (!params()?.theme) {\n setActiveTheme(e.matches ? 'dark' : 'light')\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n onCleanup(() => mediaQuery.removeEventListener('change', handleChange))\n }\n })\n\n // Apply highlighting\n createEffect(() => {\n const code = params()?.code || ''\n const language = params()?.language || ''\n\n if (hljs && isHljsLoaded()) {\n try {\n let result\n if (language && hljs.getLanguage(language)) {\n result = hljs.highlight(code, { language }).value\n } else {\n result = hljs.highlightAuto(code).value\n }\n setHighlightedCode(result)\n } catch (e) {\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n } else {\n // Fallback: simple escaping\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n })\n\n // Line numbers generation\n const lineNumbers = () => {\n if (params()?.showLineNumbers === false) return []\n const code = params()?.code || ''\n const lines = code.split('\\n')\n const start = params()?.startLine || 1\n return lines.map((_, i) => start + i)\n }\n\n const handleCopy = async () => {\n const code = params()?.code\n if (code) {\n try {\n await navigator.clipboard.writeText(code)\n setIsCopied(true)\n setTimeout(() => setIsCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy code', e)\n }\n }\n }\n\n return (\n <ExpandableWrapper title={params()?.filename || params()?.language || 'Code'} copyData={params()?.code} copyLabel=\"Copy code\">\n <div class=\"w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col\">\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0\">\n <div class=\"font-mono text-xs text-gray-600 dark:text-gray-400\">\n {params()?.filename || params()?.language || 'Code'}\n </div>\n <div class=\"flex items-center gap-2\">\n {/* Word wrap toggle */}\n <button\n onClick={() => setWordWrap(!wordWrap())}\n class={`focus:outline-none transition-colors ${wordWrap() ? 'text-blue-500 dark:text-blue-400' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}`}\n aria-label=\"Toggle word wrap\"\n title={wordWrap() ? 'Disable word wrap' : 'Enable word wrap'}\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4\" />\n </svg>\n </button>\n {/* Copy button */}\n <button\n onClick={handleCopy}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Copy code\"\n title=\"Copy code\"\n >\n <Show when={isCopied()} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n }>\n <svg class=\"w-4 h-4 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </Show>\n </button>\n </div>\n </div>\n\n {/* Code Area */}\n <div\n class=\"relative overflow-auto flex\"\n style={params()?.maxHeight ? { 'max-height': params()?.maxHeight } : {}}\n >\n {/* Line Numbers */}\n <Show when={params()?.showLineNumbers !== false}>\n <div class=\"flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5\">\n <For each={lineNumbers()}>\n {(num) => <div class=\"px-2\">{num}</div>}\n </For>\n </div>\n </Show>\n\n {/* Code Content - Sprint Ultimate U.1: data-theme for reactive theming */}\n <pre\n class=\"flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5\"\n style={wordWrap() ? { 'white-space': 'pre-wrap', 'word-break': 'break-all' } : {}}\n data-theme={activeTheme()}\n >\n <code\n class={`hljs ${params()?.language ? `language-${params()?.language}` : ''}`}\n innerHTML={highlightedCode()}\n />\n </pre>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["hljs","stylesLoaded","CodeBlockRenderer","props","highlightedCode","setHighlightedCode","createSignal","isCopied","setIsCopied","isHljsLoaded","setIsHljsLoaded","activeTheme","setActiveTheme","wordWrap","setWordWrap","params","component","createEffect","module","default","e","console","warn","isServer","Promise","all","paramTheme","theme","window","matchMedia","mediaQuery","matches","handleChange","addEventListener","onCleanup","removeEventListener","code","language","result","getLanguage","highlight","value","highlightAuto","replace","lineNumbers","showLineNumbers","lines","split","start","startLine","map","_","i","handleCopy","navigator","clipboard","writeText","setTimeout","error","_$createComponent","ExpandableWrapper","title","filename","copyData","copyLabel","children","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$10","_el$11","_co$","_$getNextMarker","_el$0","_el$1","_$insert","$$click","Show","when","fallback","_tmpl$4","_tmpl$","_el$9","_tmpl$2","For","each","num","_el$13","_tmpl$5","_$effect","_p$","_v$","_v$2","_v$3","maxHeight","_v$4","_v$5","_v$6","_v$7","_$className","t","_$setAttribute","a","_$style","o","n","s","_$setProperty","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"CodeBlockRenderer.js","sources":["../../src/components/CodeBlockRenderer.tsx"],"sourcesContent":["/**\n * CodeBlockRenderer - Syntax highlighted code block\n * Sprint 6: Code & Maps\n * Sprint Ultimate: Theme Synchronization (U.1)\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show, For } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport type { UIComponent, CodeComponentParams } from '../types'\nimport { ExpandableWrapper } from './ExpandableWrapper'\n\n// Lazy load highlight.js\nlet hljs: any = null\n// Track if styles have been loaded globally\nlet stylesLoaded = false\n\nexport interface CodeBlockRendererProps {\n /**\n * UIComponent containing code params\n */\n component?: UIComponent\n\n /**\n * Direct code params\n */\n params?: CodeComponentParams\n}\n\nexport const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {\n const [highlightedCode, setHighlightedCode] = createSignal<string>('')\n const [isCopied, setIsCopied] = createSignal(false)\n const [isHljsLoaded, setIsHljsLoaded] = createSignal(false)\n const [activeTheme, setActiveTheme] = createSignal<'light' | 'dark'>('dark')\n const [wordWrap, setWordWrap] = createSignal(false)\n\n const params = () => props.params || (props.component?.params as CodeComponentParams)\n\n // Load highlight.js on mount\n createEffect(async () => {\n if (!hljs) {\n try {\n // Use the full highlight.js bundle with all languages for simplicity\n const module = await import('highlight.js')\n const resolved = module.default || module\n // Guard: verify the resolved module has the expected API\n if (typeof resolved?.highlight === 'function') {\n hljs = resolved\n } else {\n console.warn('highlight.js loaded but missing highlight() method')\n }\n setIsHljsLoaded(true)\n } catch (e) {\n console.warn('Failed to load highlight.js', e)\n // Continue without highlighting - fallback to plain text\n setIsHljsLoaded(true)\n }\n } else {\n setIsHljsLoaded(true)\n }\n })\n\n // Theme management - Sprint Ultimate U.1: Reactive theme synchronization\n // Load both theme stylesheets once, then toggle via data-attribute\n createEffect(async () => {\n if (isServer || stylesLoaded) return\n\n // Load both themes upfront for instant switching\n try {\n await Promise.all([\n import('highlight.js/styles/github.css'),\n import('highlight.js/styles/github-dark.css')\n ])\n stylesLoaded = true\n } catch (e) {\n console.warn('Failed to load highlight.js themes', e)\n }\n })\n\n // Reactive theme detection - listens to system preference changes\n createEffect(() => {\n if (isServer) return\n\n // Priority 1: Explicit theme from params\n const paramTheme = params()?.theme\n if (paramTheme) {\n setActiveTheme(paramTheme)\n return\n }\n\n // Priority 2: System preference with live updates\n // Check if matchMedia is available (not in all test environments)\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n setActiveTheme(mediaQuery.matches ? 'dark' : 'light')\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only update if no explicit theme in params\n if (!params()?.theme) {\n setActiveTheme(e.matches ? 'dark' : 'light')\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n onCleanup(() => mediaQuery.removeEventListener('change', handleChange))\n }\n })\n\n // Apply highlighting\n createEffect(() => {\n const code = params()?.code || ''\n const language = params()?.language || ''\n\n if (hljs && isHljsLoaded()) {\n try {\n let result\n if (language && hljs.getLanguage(language)) {\n result = hljs.highlight(code, { language }).value\n } else {\n result = hljs.highlightAuto(code).value\n }\n setHighlightedCode(result)\n } catch (e) {\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n } else {\n // Fallback: simple escaping\n setHighlightedCode(code.replace(/</g, '&lt;').replace(/>/g, '&gt;'))\n }\n })\n\n // Line numbers generation\n const lineNumbers = () => {\n if (params()?.showLineNumbers === false) return []\n const code = params()?.code || ''\n const lines = code.split('\\n')\n const start = params()?.startLine || 1\n return lines.map((_, i) => start + i)\n }\n\n const handleCopy = async () => {\n const code = params()?.code\n if (code) {\n try {\n await navigator.clipboard.writeText(code)\n setIsCopied(true)\n setTimeout(() => setIsCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy code', e)\n }\n }\n }\n\n return (\n <ExpandableWrapper title={params()?.filename || params()?.language || 'Code'} copyData={params()?.code} copyLabel=\"Copy code\">\n <div class=\"w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col\">\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0\">\n <div class=\"font-mono text-xs text-gray-600 dark:text-gray-400\">\n {params()?.filename || params()?.language || 'Code'}\n </div>\n <div class=\"flex items-center gap-2\">\n {/* Word wrap toggle */}\n <button\n onClick={() => setWordWrap(!wordWrap())}\n class={`focus:outline-none transition-colors ${wordWrap() ? 'text-blue-500 dark:text-blue-400' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}`}\n aria-label=\"Toggle word wrap\"\n title={wordWrap() ? 'Disable word wrap' : 'Enable word wrap'}\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4\" />\n </svg>\n </button>\n {/* Copy button */}\n <button\n onClick={handleCopy}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Copy code\"\n title=\"Copy code\"\n >\n <Show when={isCopied()} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n }>\n <svg class=\"w-4 h-4 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </Show>\n </button>\n </div>\n </div>\n\n {/* Code Area */}\n <div\n class=\"relative overflow-auto flex\"\n style={params()?.maxHeight ? { 'max-height': params()?.maxHeight } : {}}\n >\n {/* Line Numbers */}\n <Show when={params()?.showLineNumbers !== false}>\n <div class=\"flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5\">\n <For each={lineNumbers()}>\n {(num) => <div class=\"px-2\">{num}</div>}\n </For>\n </div>\n </Show>\n\n {/* Code Content - Sprint Ultimate U.1: data-theme for reactive theming */}\n <pre\n class=\"flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5\"\n style={wordWrap() ? { 'white-space': 'pre-wrap', 'word-break': 'break-all' } : {}}\n data-theme={activeTheme()}\n >\n <code\n class={`hljs ${params()?.language ? `language-${params()?.language}` : ''}`}\n innerHTML={highlightedCode()}\n />\n </pre>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["hljs","stylesLoaded","CodeBlockRenderer","props","highlightedCode","setHighlightedCode","createSignal","isCopied","setIsCopied","isHljsLoaded","setIsHljsLoaded","activeTheme","setActiveTheme","wordWrap","setWordWrap","params","component","createEffect","module","resolved","default","highlight","console","warn","e","isServer","Promise","all","paramTheme","theme","window","matchMedia","mediaQuery","matches","handleChange","addEventListener","onCleanup","removeEventListener","code","language","result","getLanguage","value","highlightAuto","replace","lineNumbers","showLineNumbers","lines","split","start","startLine","map","_","i","handleCopy","navigator","clipboard","writeText","setTimeout","error","_$createComponent","ExpandableWrapper","title","filename","copyData","copyLabel","children","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$8","_el$10","_el$11","_co$","_$getNextMarker","_el$0","_el$1","_$insert","$$click","Show","when","fallback","_tmpl$4","_tmpl$","_el$9","_tmpl$2","For","each","num","_el$13","_tmpl$5","_$effect","_p$","_v$","_v$2","_v$3","maxHeight","_v$4","_v$5","_v$6","_v$7","_$className","t","_$setAttribute","a","_$style","o","n","s","_$setProperty","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":"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"}
@@ -180,6 +180,7 @@ function validateGridPosition(position) {
180
180
  };
181
181
  }
182
182
  function validateChartComponent(params, limits = DEFAULT_RESOURCE_LIMITS) {
183
+ var _a, _b;
183
184
  const errors = [];
184
185
  if (!(params == null ? void 0 : params.data)) {
185
186
  return { valid: false, errors: [{ path: "params.data", message: "Missing chart data object", code: "MISSING_DATA" }] };
@@ -187,11 +188,17 @@ function validateChartComponent(params, limits = DEFAULT_RESOURCE_LIMITS) {
187
188
  if (!Array.isArray(params.data.datasets)) {
188
189
  return { valid: false, errors: [{ path: "params.data.datasets", message: "Missing or invalid datasets array", code: "MISSING_DATASETS" }] };
189
190
  }
190
- if (!Array.isArray(params.data.labels)) {
191
- return { valid: false, errors: [{ path: "params.data.labels", message: "Missing or invalid labels array", code: "MISSING_LABELS" }] };
191
+ const chartType = params.type || "bar";
192
+ const firstDataPoint = (_b = (_a = params.data.datasets[0]) == null ? void 0 : _a.data) == null ? void 0 : _b[0];
193
+ const hasObjectData = typeof firstDataPoint === "object" && firstDataPoint !== null && "x" in firstDataPoint;
194
+ const isPointChart = chartType === "scatter" || chartType === "bubble" || hasObjectData;
195
+ if (!isPointChart) {
196
+ if (!Array.isArray(params.data.labels)) {
197
+ return { valid: false, errors: [{ path: "params.data.labels", message: "Missing or invalid labels array", code: "MISSING_LABELS" }] };
198
+ }
192
199
  }
193
200
  const totalDataPoints = params.data.datasets.reduce(
194
- (sum, dataset) => sum + dataset.data.length,
201
+ (sum, dataset) => sum + (Array.isArray(dataset.data) ? dataset.data.length : 0),
195
202
  0
196
203
  );
197
204
  if (totalDataPoints > limits.maxDataPoints) {
@@ -201,24 +208,38 @@ function validateChartComponent(params, limits = DEFAULT_RESOURCE_LIMITS) {
201
208
  code: "RESOURCE_LIMIT_EXCEEDED"
202
209
  });
203
210
  }
204
- const expectedLength = params.data.labels.length;
205
- for (const [index, dataset] of params.data.datasets.entries()) {
206
- if (dataset.data.length !== expectedLength) {
207
- errors.push({
208
- path: `params.data.datasets[${index}]`,
209
- message: `Dataset length mismatch: expected ${expectedLength}, got ${dataset.data.length}`,
210
- code: "DATA_LENGTH_MISMATCH"
211
- });
211
+ if (!isPointChart && Array.isArray(params.data.labels)) {
212
+ const expectedLength = params.data.labels.length;
213
+ for (const [index, dataset] of params.data.datasets.entries()) {
214
+ if (Array.isArray(dataset.data) && dataset.data.length > 0 && dataset.data.length !== expectedLength) {
215
+ errors.push({
216
+ path: `params.data.datasets[${index}]`,
217
+ message: `Dataset length mismatch: expected ${expectedLength}, got ${dataset.data.length}`,
218
+ code: "DATA_LENGTH_MISMATCH"
219
+ });
220
+ }
212
221
  }
213
222
  }
214
223
  for (const [index, dataset] of params.data.datasets.entries()) {
224
+ if (!Array.isArray(dataset.data)) continue;
215
225
  for (const [dataIndex, value] of dataset.data.entries()) {
216
- if (typeof value !== "number" || !Number.isFinite(value)) {
217
- errors.push({
218
- path: `params.data.datasets[${index}].data[${dataIndex}]`,
219
- message: `Invalid data value: ${value} (must be finite number)`,
220
- code: "INVALID_DATA_TYPE"
221
- });
226
+ if (isPointChart) {
227
+ const vObj = value;
228
+ if (typeof value !== "object" || value === null || vObj.x == null || typeof vObj.y !== "number") {
229
+ errors.push({
230
+ path: `params.data.datasets[${index}].data[${dataIndex}]`,
231
+ message: `Invalid point data: expected {x, y} object`,
232
+ code: "INVALID_POINT_DATA"
233
+ });
234
+ }
235
+ } else {
236
+ if (typeof value !== "number" || !Number.isFinite(value)) {
237
+ errors.push({
238
+ path: `params.data.datasets[${index}].data[${dataIndex}]`,
239
+ message: `Invalid data value: ${value} (must be finite number)`,
240
+ code: "INVALID_DATA_TYPE"
241
+ });
242
+ }
222
243
  }
223
244
  }
224
245
  }
@@ -432,6 +453,73 @@ function validateComponent(component, options) {
432
453
  }
433
454
  break;
434
455
  }
456
+ case "video": {
457
+ const videoParams = component.params;
458
+ if (!videoParams.url) {
459
+ errors.push({ path: "params", message: "Video component must have url", code: "INVALID_VIDEO" });
460
+ } else {
461
+ const videoResult = validateIframeDomain(videoParams.url, {
462
+ policy: options == null ? void 0 : options.iframePolicy,
463
+ customDomains: options == null ? void 0 : options.customIframeDomains
464
+ });
465
+ if (!videoResult.valid) {
466
+ errors.push(...videoResult.errors || []);
467
+ }
468
+ }
469
+ break;
470
+ }
471
+ case "carousel": {
472
+ const carouselParams = component.params;
473
+ if (!Array.isArray(carouselParams.items) || carouselParams.items.length === 0) {
474
+ errors.push({ path: "params.items", message: "Carousel must have non-empty items array", code: "EMPTY_CAROUSEL" });
475
+ }
476
+ break;
477
+ }
478
+ case "image-gallery": {
479
+ const galleryParams = component.params;
480
+ if (!Array.isArray(galleryParams.images) || galleryParams.images.length === 0) {
481
+ errors.push({ path: "params.images", message: "Gallery must have non-empty images array", code: "EMPTY_GALLERY" });
482
+ }
483
+ break;
484
+ }
485
+ case "form": {
486
+ const formParams = component.params;
487
+ if (!Array.isArray(formParams.fields) || formParams.fields.length === 0) {
488
+ errors.push({ path: "params.fields", message: "Form must have non-empty fields array", code: "EMPTY_FORM" });
489
+ }
490
+ break;
491
+ }
492
+ case "action-group": {
493
+ const agParams = component.params;
494
+ if (!Array.isArray(agParams.actions) || agParams.actions.length === 0) {
495
+ errors.push({ path: "params.actions", message: "Action group must have non-empty actions array", code: "EMPTY_ACTION_GROUP" });
496
+ }
497
+ break;
498
+ }
499
+ case "code": {
500
+ const codeParams = component.params;
501
+ if (!codeParams.code) {
502
+ errors.push({ path: "params.code", message: "Code component must have code content", code: "INVALID_CODE" });
503
+ }
504
+ break;
505
+ }
506
+ case "map": {
507
+ const mapParams = component.params;
508
+ if (!mapParams.center && (!Array.isArray(mapParams.markers) || mapParams.markers.length === 0)) {
509
+ errors.push({ path: "params", message: "Map must have center or markers", code: "INVALID_MAP" });
510
+ }
511
+ break;
512
+ }
513
+ case "modal": {
514
+ break;
515
+ }
516
+ case "artifact": {
517
+ const artifactParams = component.params;
518
+ if (!artifactParams.content) {
519
+ errors.push({ path: "params.content", message: "Artifact must have content", code: "INVALID_ARTIFACT" });
520
+ }
521
+ break;
522
+ }
435
523
  default:
436
524
  if (!KNOWN_COMPONENT_TYPES.has(component.type)) {
437
525
  errors.push({