@icen.ai/ui 0.10.0 → 0.11.0

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.
Files changed (355) hide show
  1. package/AGENTS.md +79 -309
  2. package/LICENSE +21 -0
  3. package/README.md +43 -54
  4. package/dist/base.css +57 -16
  5. package/dist/behaviors/accordion.mjs +1 -1
  6. package/dist/behaviors/ai-branch.mjs +1 -0
  7. package/dist/behaviors/ai-chat.d.mts +2 -2
  8. package/dist/behaviors/ai-chat.mjs +53 -10
  9. package/dist/behaviors/ai-composer.d.mts +5 -5
  10. package/dist/behaviors/ai-composer.mjs +21 -10
  11. package/dist/behaviors/ai-core.mjs +1 -0
  12. package/dist/behaviors/ai-diff.mjs +1 -0
  13. package/dist/behaviors/ai-feedback.mjs +1 -0
  14. package/dist/behaviors/ai-panel.d.mts +2 -2
  15. package/dist/behaviors/ai-panel.mjs +1 -0
  16. package/dist/behaviors/ai-provider.d.mts +1 -1
  17. package/dist/behaviors/ai-provider.mjs +1 -0
  18. package/dist/behaviors/ai-threads.mjs +1 -0
  19. package/dist/behaviors/ai-tool.d.mts +1 -1
  20. package/dist/behaviors/ai-tool.mjs +57 -24
  21. package/dist/behaviors/ai-tools.mjs +937 -28
  22. package/dist/behaviors/autocomplete.d.mts +1 -1
  23. package/dist/behaviors/autocomplete.mjs +1 -0
  24. package/dist/behaviors/back-top.mjs +1 -0
  25. package/dist/behaviors/carousel.mjs +8 -1
  26. package/dist/behaviors/cascader.mjs +14 -0
  27. package/dist/behaviors/charts.mjs +56 -20
  28. package/dist/behaviors/code-block.mjs +9 -1
  29. package/dist/behaviors/command-palette.mjs +3 -3
  30. package/dist/behaviors/context-menu.d.mts +2 -2
  31. package/dist/behaviors/context-menu.mjs +1 -0
  32. package/dist/behaviors/controls.d.mts +8 -8
  33. package/dist/behaviors/controls.mjs +37 -6
  34. package/dist/behaviors/copy.mjs +1 -0
  35. package/dist/behaviors/datatable.d.mts +3 -3
  36. package/dist/behaviors/datatable.mjs +76 -11
  37. package/dist/behaviors/date-picker.mjs +1 -0
  38. package/dist/behaviors/events.d.mts +10 -10
  39. package/dist/behaviors/events.mjs +11 -1
  40. package/dist/behaviors/form-validate.d.mts +10 -1
  41. package/dist/behaviors/form-validate.mjs +266 -4611
  42. package/dist/behaviors/i18n.d.mts +1 -0
  43. package/dist/behaviors/i18n.mjs +2 -0
  44. package/dist/behaviors/input.mjs +3 -0
  45. package/dist/behaviors/kb-access.d.mts +2 -2
  46. package/dist/behaviors/kb-access.mjs +8 -2
  47. package/dist/behaviors/kb-acl.d.mts +2 -2
  48. package/dist/behaviors/kb-acl.mjs +1 -0
  49. package/dist/behaviors/kb-answer.d.mts +2 -2
  50. package/dist/behaviors/kb-answer.mjs +56 -23
  51. package/dist/behaviors/kb-audit.d.mts +2 -2
  52. package/dist/behaviors/kb-audit.mjs +1 -0
  53. package/dist/behaviors/kb-canvas.d.mts +3 -3
  54. package/dist/behaviors/kb-canvas.mjs +1 -0
  55. package/dist/behaviors/kb-chain.d.mts +2 -2
  56. package/dist/behaviors/kb-chain.mjs +1 -0
  57. package/dist/behaviors/kb-checkpoint.d.mts +2 -2
  58. package/dist/behaviors/kb-checkpoint.mjs +1 -0
  59. package/dist/behaviors/kb-chunks.d.mts +2 -2
  60. package/dist/behaviors/kb-chunks.mjs +1 -0
  61. package/dist/behaviors/kb-citation.d.mts +2 -2
  62. package/dist/behaviors/kb-citation.mjs +20 -6
  63. package/dist/behaviors/kb-clarify.d.mts +2 -2
  64. package/dist/behaviors/kb-clarify.mjs +1 -0
  65. package/dist/behaviors/kb-conflict.d.mts +2 -2
  66. package/dist/behaviors/kb-conflict.mjs +1 -0
  67. package/dist/behaviors/kb-connector.d.mts +2 -2
  68. package/dist/behaviors/kb-connector.mjs +1 -0
  69. package/dist/behaviors/kb-core.d.mts +1 -1
  70. package/dist/behaviors/kb-core.mjs +1 -0
  71. package/dist/behaviors/kb-eval.d.mts +2 -2
  72. package/dist/behaviors/kb-eval.mjs +8 -2
  73. package/dist/behaviors/kb-explain.d.mts +2 -2
  74. package/dist/behaviors/kb-explain.mjs +13 -2
  75. package/dist/behaviors/kb-filter.d.mts +2 -2
  76. package/dist/behaviors/kb-filter.mjs +8 -2
  77. package/dist/behaviors/kb-gap.d.mts +2 -2
  78. package/dist/behaviors/kb-gap.mjs +1 -0
  79. package/dist/behaviors/kb-hittest.d.mts +2 -2
  80. package/dist/behaviors/kb-hittest.mjs +2 -1
  81. package/dist/behaviors/kb-metadata.mjs +6 -0
  82. package/dist/behaviors/kb-passage.d.mts +2 -2
  83. package/dist/behaviors/kb-passage.mjs +1 -0
  84. package/dist/behaviors/kb-pipeline.d.mts +2 -2
  85. package/dist/behaviors/kb-pipeline.mjs +1 -0
  86. package/dist/behaviors/kb-qa.mjs +1 -0
  87. package/dist/behaviors/kb-rerank.d.mts +2 -2
  88. package/dist/behaviors/kb-rerank.mjs +1 -0
  89. package/dist/behaviors/kb-retrieval.d.mts +2 -2
  90. package/dist/behaviors/kb-retrieval.mjs +18 -4
  91. package/dist/behaviors/kb-review.d.mts +2 -2
  92. package/dist/behaviors/kb-review.mjs +8 -2
  93. package/dist/behaviors/kb-sandbox.d.mts +2 -2
  94. package/dist/behaviors/kb-sandbox.mjs +7 -1
  95. package/dist/behaviors/kb-segment.d.mts +2 -2
  96. package/dist/behaviors/kb-segment.mjs +2 -1
  97. package/dist/behaviors/kb-select.mjs +8 -2
  98. package/dist/behaviors/kb-sources.d.mts +2 -2
  99. package/dist/behaviors/kb-sources.mjs +1 -0
  100. package/dist/behaviors/kb-sql.d.mts +2 -2
  101. package/dist/behaviors/kb-sql.mjs +1 -0
  102. package/dist/behaviors/kb-trace.d.mts +2 -2
  103. package/dist/behaviors/kb-trace.mjs +9 -3
  104. package/dist/behaviors/kb-visibility.d.mts +2 -2
  105. package/dist/behaviors/kb-visibility.mjs +1 -0
  106. package/dist/behaviors/kb-who-can.d.mts +2 -2
  107. package/dist/behaviors/kb-who-can.mjs +8 -2
  108. package/dist/behaviors/mentions.d.mts +1 -1
  109. package/dist/behaviors/mentions.mjs +1 -0
  110. package/dist/behaviors/modal.d.mts +1 -1
  111. package/dist/behaviors/modal.mjs +1 -0
  112. package/dist/behaviors/notification.d.mts +2 -2
  113. package/dist/behaviors/notification.mjs +14 -3
  114. package/dist/behaviors/panel.mjs +1 -0
  115. package/dist/behaviors/scroll-area.d.mts +17 -0
  116. package/dist/behaviors/scroll-area.mjs +59 -0
  117. package/dist/behaviors/select.mjs +8 -2
  118. package/dist/behaviors/slider.mjs +3 -3
  119. package/dist/behaviors/split-pane.mjs +2 -0
  120. package/dist/behaviors/suggestions.mjs +1 -0
  121. package/dist/behaviors/tabs.mjs +10 -0
  122. package/dist/behaviors/tag-input.mjs +1 -0
  123. package/dist/behaviors/theme-switcher.d.mts +2 -2
  124. package/dist/behaviors/theme-switcher.mjs +17 -2
  125. package/dist/behaviors/theme.mjs +16 -2
  126. package/dist/behaviors/toast.d.mts +2 -2
  127. package/dist/behaviors/toast.mjs +1 -0
  128. package/dist/behaviors/tree-select.mjs +14 -0
  129. package/dist/behaviors/tree.mjs +4 -4
  130. package/dist/behaviors/upload.mjs +1 -0
  131. package/dist/behaviors/url-safety.d.mts +8 -0
  132. package/dist/behaviors/url-safety.mjs +11 -0
  133. package/dist/components/accordion.d.mts +2 -0
  134. package/dist/components/ai-branch.d.mts +2 -0
  135. package/dist/components/ai-chat.css +40 -33
  136. package/dist/components/ai-chat.d.mts +2 -0
  137. package/dist/components/ai-composer.d.mts +2 -0
  138. package/dist/components/ai-context.d.mts +2 -0
  139. package/dist/components/ai-context.mjs +1 -0
  140. package/dist/components/ai-diff.css +6 -6
  141. package/dist/components/ai-diff.d.mts +2 -0
  142. package/dist/components/ai-feedback.d.mts +2 -0
  143. package/dist/components/ai-files.d.mts +2 -0
  144. package/dist/components/ai-message.d.mts +2 -0
  145. package/dist/components/ai-panel.css +12 -10
  146. package/dist/components/ai-reasoning.d.mts +2 -0
  147. package/dist/components/ai-subagent.d.mts +2 -0
  148. package/dist/components/ai-subagent.mjs +1 -0
  149. package/dist/components/ai-threads.d.mts +2 -0
  150. package/dist/components/ai-todo.d.mts +2 -0
  151. package/dist/components/ai-todo.mjs +1 -0
  152. package/dist/components/ai-tool-call.d.mts +2 -0
  153. package/dist/components/ai-tool-call.mjs +1 -0
  154. package/dist/components/ai-tool.css +16 -16
  155. package/dist/components/ai-usage.d.mts +2 -0
  156. package/dist/components/alert.d.mts +2 -0
  157. package/dist/components/autocomplete.css +12 -12
  158. package/dist/components/autocomplete.d.mts +2 -0
  159. package/dist/components/avatar.d.mts +2 -0
  160. package/dist/components/back-top.css +47 -16
  161. package/dist/components/back-top.d.mts +2 -0
  162. package/dist/components/badge.css +1 -1
  163. package/dist/components/badge.d.mts +2 -0
  164. package/dist/components/breadcrumb.css +26 -8
  165. package/dist/components/breadcrumb.d.mts +2 -0
  166. package/dist/components/btn.css +67 -62
  167. package/dist/components/btn.d.mts +2 -0
  168. package/dist/components/card.css +22 -22
  169. package/dist/components/card.d.mts +2 -0
  170. package/dist/components/carousel.d.mts +2 -0
  171. package/dist/components/cascader.css +56 -35
  172. package/dist/components/cascader.d.mts +2 -0
  173. package/dist/components/chart-area.css +46 -0
  174. package/dist/components/chart-area.d.mts +2 -0
  175. package/dist/components/chart-bar.css +66 -19
  176. package/dist/components/chart-bar.d.mts +2 -0
  177. package/dist/components/chart-calendar.d.mts +2 -0
  178. package/dist/components/chart-gauge.css +23 -3
  179. package/dist/components/chart-gauge.d.mts +2 -0
  180. package/dist/components/chart-graph.css +15 -3
  181. package/dist/components/chart-graph.d.mts +2 -0
  182. package/dist/components/chart-heatmap.css +117 -95
  183. package/dist/components/chart-heatmap.d.mts +2 -0
  184. package/dist/components/chart-line.css +54 -0
  185. package/dist/components/chart-line.d.mts +2 -0
  186. package/dist/components/chart-map.d.mts +2 -0
  187. package/dist/components/chart-pie.css +29 -0
  188. package/dist/components/chart-pie.d.mts +2 -0
  189. package/dist/components/chart-radar.css +50 -1
  190. package/dist/components/chart-radar.d.mts +2 -0
  191. package/dist/components/chart-scatter.css +39 -2
  192. package/dist/components/chart-scatter.d.mts +2 -0
  193. package/dist/components/chart-sparkline.css +20 -0
  194. package/dist/components/chart-sparkline.d.mts +2 -0
  195. package/dist/components/chart-stack.css +16 -5
  196. package/dist/components/chart-stack.d.mts +2 -0
  197. package/dist/components/charts.css +80 -35
  198. package/dist/components/charts.d.mts +2 -0
  199. package/dist/components/code-block.css +10 -8
  200. package/dist/components/code-block.d.mts +2 -0
  201. package/dist/components/command-palette.css +45 -38
  202. package/dist/components/command-palette.d.mts +2 -0
  203. package/dist/components/content.css +62 -57
  204. package/dist/components/context-menu.d.mts +2 -0
  205. package/dist/components/copy.css +10 -10
  206. package/dist/components/copy.d.mts +2 -0
  207. package/dist/components/datatable.css +72 -59
  208. package/dist/components/datatable.d.mts +2 -0
  209. package/dist/components/date-picker.css +26 -26
  210. package/dist/components/date-picker.d.mts +2 -0
  211. package/dist/components/desc.d.mts +2 -0
  212. package/dist/components/dropdown.d.mts +2 -0
  213. package/dist/components/empty.css +16 -16
  214. package/dist/components/empty.d.mts +2 -0
  215. package/dist/components/feedback.css +31 -29
  216. package/dist/components/form-validate.css +20 -6
  217. package/dist/components/form-validate.d.mts +2 -0
  218. package/dist/components/form.css +17 -14
  219. package/dist/components/form.d.mts +2 -0
  220. package/dist/components/icon.css +21 -10
  221. package/dist/components/icon.d.mts +2 -0
  222. package/dist/components/input.css +22 -22
  223. package/dist/components/input.d.mts +2 -0
  224. package/dist/components/kb-access.d.mts +2 -0
  225. package/dist/components/kb-acl.d.mts +2 -0
  226. package/dist/components/kb-agent.css +134 -55
  227. package/dist/components/kb-answer.d.mts +2 -0
  228. package/dist/components/kb-audit.d.mts +2 -0
  229. package/dist/components/kb-canvas.d.mts +2 -0
  230. package/dist/components/kb-chain.d.mts +2 -0
  231. package/dist/components/kb-checkpoint.d.mts +2 -0
  232. package/dist/components/kb-chunks.d.mts +2 -0
  233. package/dist/components/kb-citation.d.mts +2 -0
  234. package/dist/components/kb-clarify.d.mts +2 -0
  235. package/dist/components/kb-conflict.d.mts +2 -0
  236. package/dist/components/kb-connector.d.mts +2 -0
  237. package/dist/components/kb-data.css +192 -80
  238. package/dist/components/kb-eval.d.mts +2 -0
  239. package/dist/components/kb-explain.d.mts +2 -0
  240. package/dist/components/kb-filter.d.mts +2 -0
  241. package/dist/components/kb-gap.d.mts +2 -0
  242. package/dist/components/kb-ground.css +165 -73
  243. package/dist/components/kb-hittest.d.mts +2 -0
  244. package/dist/components/kb-ingest.css +308 -113
  245. package/dist/components/kb-metadata.d.mts +2 -0
  246. package/dist/components/kb-ops.css +189 -75
  247. package/dist/components/kb-passage.d.mts +2 -0
  248. package/dist/components/kb-perm.css +158 -87
  249. package/dist/components/kb-pipeline.d.mts +2 -0
  250. package/dist/components/kb-qa.d.mts +2 -0
  251. package/dist/components/kb-rerank.d.mts +2 -0
  252. package/dist/components/kb-retrieval.d.mts +2 -0
  253. package/dist/components/kb-review.d.mts +2 -0
  254. package/dist/components/kb-sandbox.d.mts +2 -0
  255. package/dist/components/kb-search.css +353 -116
  256. package/dist/components/kb-segment.d.mts +2 -0
  257. package/dist/components/kb-sources.d.mts +2 -0
  258. package/dist/components/kb-sql.d.mts +2 -0
  259. package/dist/components/kb-trace.d.mts +2 -0
  260. package/dist/components/kb-visibility.d.mts +2 -0
  261. package/dist/components/kb-who-can.d.mts +2 -0
  262. package/dist/components/kb.css +60 -36
  263. package/dist/components/kb.d.mts +2 -0
  264. package/dist/components/kbd.d.mts +2 -0
  265. package/dist/components/layout.css +10 -10
  266. package/dist/components/layout.d.mts +2 -0
  267. package/dist/components/list.d.mts +2 -0
  268. package/dist/components/material-chinese.css +10 -0
  269. package/dist/components/material-soviet.css +10 -0
  270. package/dist/components/material.css +61 -18
  271. package/dist/components/media-card.d.mts +2 -0
  272. package/dist/components/media.css +22 -27
  273. package/dist/components/mentions.css +18 -17
  274. package/dist/components/mentions.d.mts +2 -0
  275. package/dist/components/menu.css +32 -28
  276. package/dist/components/modal.css +30 -27
  277. package/dist/components/modal.d.mts +2 -0
  278. package/dist/components/nav.css +48 -44
  279. package/dist/components/nav.d.mts +2 -0
  280. package/dist/components/notification.css +31 -25
  281. package/dist/components/notification.d.mts +2 -0
  282. package/dist/components/pagination.css +15 -13
  283. package/dist/components/pagination.d.mts +2 -0
  284. package/dist/components/panel.css +19 -20
  285. package/dist/components/panel.d.mts +2 -0
  286. package/dist/components/pill.css +8 -7
  287. package/dist/components/pill.d.mts +2 -0
  288. package/dist/components/popover.css +32 -23
  289. package/dist/components/popover.d.mts +2 -0
  290. package/dist/components/progress.d.mts +2 -0
  291. package/dist/components/rating.d.mts +2 -0
  292. package/dist/components/result.d.mts +2 -0
  293. package/dist/components/scroll-area.css +84 -112
  294. package/dist/components/scroll-area.d.mts +2 -0
  295. package/dist/components/scroll-area.mjs +1 -0
  296. package/dist/components/segmented.css +47 -29
  297. package/dist/components/segmented.d.mts +2 -0
  298. package/dist/components/select.css +80 -41
  299. package/dist/components/select.d.mts +2 -0
  300. package/dist/components/sidebar.css +42 -38
  301. package/dist/components/sidebar.d.mts +2 -0
  302. package/dist/components/skeleton.d.mts +2 -0
  303. package/dist/components/slider.css +26 -22
  304. package/dist/components/slider.d.mts +2 -0
  305. package/dist/components/spinner.d.mts +2 -0
  306. package/dist/components/split-pane.css +16 -7
  307. package/dist/components/split-pane.d.mts +2 -0
  308. package/dist/components/stat.css +17 -16
  309. package/dist/components/stat.d.mts +2 -0
  310. package/dist/components/steps.css +26 -26
  311. package/dist/components/steps.d.mts +2 -0
  312. package/dist/components/switch.css +78 -39
  313. package/dist/components/switch.d.mts +2 -0
  314. package/dist/components/table.css +54 -32
  315. package/dist/components/table.d.mts +2 -0
  316. package/dist/components/tabs.css +53 -32
  317. package/dist/components/tabs.d.mts +2 -0
  318. package/dist/components/tag-input.css +12 -8
  319. package/dist/components/tag-input.d.mts +2 -0
  320. package/dist/components/tag.css +20 -12
  321. package/dist/components/tag.d.mts +2 -0
  322. package/dist/components/theme-switcher.css +7 -7
  323. package/dist/components/theme-switcher.d.mts +2 -0
  324. package/dist/components/timeline.d.mts +2 -0
  325. package/dist/components/toast.css +34 -30
  326. package/dist/components/toast.d.mts +2 -0
  327. package/dist/components/toolbar.css +19 -18
  328. package/dist/components/toolbar.d.mts +2 -0
  329. package/dist/components/tooltip.css +9 -8
  330. package/dist/components/tooltip.d.mts +2 -0
  331. package/dist/components/tree-select.css +63 -40
  332. package/dist/components/tree-select.d.mts +2 -0
  333. package/dist/components/tree.d.mts +2 -0
  334. package/dist/components/upload.css +9 -11
  335. package/dist/components/upload.d.mts +2 -0
  336. package/dist/index.d.mts +85 -84
  337. package/dist/index.mjs +14764 -14311
  338. package/dist/react.d.mts +18 -18
  339. package/dist/react.mjs +135 -36
  340. package/dist/registry.json +795 -64
  341. package/dist/tokens/colors.css +6 -0
  342. package/dist/tokens/design.css +130 -30
  343. package/dist/tokens/dtcg.json +6189 -1461
  344. package/dist/tokens/figma.variables.json +4107 -345
  345. package/dist/tokens/pixel.css +3 -0
  346. package/dist/tokens/scrollbars.css +40 -0
  347. package/dist/tokens/tokens-studio.json +5191 -271
  348. package/dist/tokens.css +304 -81
  349. package/dist/ui.css +4050 -2148
  350. package/dist/vue.d.mts +17 -17
  351. package/dist/vue.mjs +129 -34
  352. package/docs/spec/design-philosophy.md +5 -5
  353. package/docs/spec/design-primitives.md +10 -10
  354. package/docs/spec/scrollbars.md +46 -0
  355. package/package.json +16 -3
@@ -21,6 +21,7 @@ var ICEN_LOCALE_ZH_CN = {
21
21
  "aiChat.roleTool": "\u5DE5",
22
22
  "aiChat.roleUser": "\u6211",
23
23
  "aiChat.thinking": "\u601D\u8003 {p0}",
24
+ "aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
24
25
  /* ── aiComposer ── */
25
26
  "aiComposer.attachAgent": "\u4EE3\u7406",
26
27
  "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
@@ -1241,6 +1242,15 @@ function svgIcon(svg) {
1241
1242
  return parseSvg(svg);
1242
1243
  }
1243
1244
 
1245
+ // src/behaviors/url-safety.ts
1246
+ function safeUrl(uri) {
1247
+ const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
1248
+ if (!s) return void 0;
1249
+ if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
1250
+ if (/^data:\s*text\/html/.test(s)) return void 0;
1251
+ return uri;
1252
+ }
1253
+
1244
1254
  // src/behaviors/ai-chat.ts
1245
1255
  var ICON_COPY = iconHTML("copy");
1246
1256
  var ICON_RETRY = iconHTML("refresh");
@@ -1250,10 +1260,9 @@ var ROLE_AVATAR = {
1250
1260
  system: t("aiChat.roleSystem"),
1251
1261
  tool: t("aiChat.roleTool")
1252
1262
  };
1253
- function safeHref(uri) {
1254
- const s = uri.trim().toLowerCase();
1255
- if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
1256
- return uri;
1263
+ function safeContentUrl(part) {
1264
+ const src = aiContentUrl(part);
1265
+ return src ? safeUrl(src) : void 0;
1257
1266
  }
1258
1267
  function renderAiContentPart(part) {
1259
1268
  if (part.type === "text") {
@@ -1263,7 +1272,7 @@ function renderAiContentPart(part) {
1263
1272
  return span;
1264
1273
  }
1265
1274
  if (part.type === "image") {
1266
- const src = aiContentUrl(part);
1275
+ const src = safeContentUrl(part);
1267
1276
  if (!src) return void 0;
1268
1277
  const img = document.createElement("img");
1269
1278
  img.className = "icen-ai-msg-media icen-ai-msg-media--image";
@@ -1273,7 +1282,7 @@ function renderAiContentPart(part) {
1273
1282
  return img;
1274
1283
  }
1275
1284
  if (part.type === "audio") {
1276
- const src = aiContentUrl(part);
1285
+ const src = safeContentUrl(part);
1277
1286
  if (!src) return void 0;
1278
1287
  const audio = document.createElement("audio");
1279
1288
  audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
@@ -1282,7 +1291,7 @@ function renderAiContentPart(part) {
1282
1291
  return audio;
1283
1292
  }
1284
1293
  if (part.type === "video") {
1285
- const src = aiContentUrl(part);
1294
+ const src = safeContentUrl(part);
1286
1295
  if (!src) return void 0;
1287
1296
  const video = document.createElement("video");
1288
1297
  video.className = "icen-ai-msg-media icen-ai-msg-media--video";
@@ -1294,7 +1303,7 @@ function renderAiContentPart(part) {
1294
1303
  if (part.type === "file") {
1295
1304
  const chip = h("span", "icen-ai-msg-file");
1296
1305
  chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
1297
- const href2 = part.url ? safeHref(part.url) : void 0;
1306
+ const href2 = part.url ? safeUrl(part.url) : void 0;
1298
1307
  if (href2 && /^(https?:|data:)/i.test(href2)) {
1299
1308
  const a2 = document.createElement("a");
1300
1309
  a2.className = "icen-ai-msg-file-link";
@@ -1307,7 +1316,7 @@ function renderAiContentPart(part) {
1307
1316
  }
1308
1317
  const a = document.createElement("a");
1309
1318
  a.className = "icen-ai-msg-link";
1310
- const href = safeHref(part.uri);
1319
+ const href = safeUrl(part.uri);
1311
1320
  if (href) a.href = href;
1312
1321
  a.textContent = part.name ?? part.uri;
1313
1322
  a.title = part.uri;
@@ -1534,7 +1543,8 @@ function withChrome(el, opts, hasLegend, paint, state, extras) {
1534
1543
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
1535
1544
  });
1536
1545
  syncEye();
1537
- head.append(title, eye);
1546
+ if (hasLegend) head.append(title, eye);
1547
+ else head.append(title);
1538
1548
  el.append(head, body);
1539
1549
  paint(body);
1540
1550
  }
@@ -1635,7 +1645,7 @@ function renderVBar(el, opts) {
1635
1645
  wrap.appendChild(track);
1636
1646
  }
1637
1647
  body.append(wrap, labelsRow(labelsUsed));
1638
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1648
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1639
1649
  });
1640
1650
  attachChartInteraction(el, "vbar");
1641
1651
  return el;
@@ -1730,8 +1740,10 @@ function renderDonut(el, opts) {
1730
1740
  "stroke-width": "14"
1731
1741
  }));
1732
1742
  let offset = 0;
1743
+ const gap = opts.segments.length > 1 ? 2.5 : 0;
1733
1744
  opts.segments.forEach((seg, segIndex) => {
1734
- const dash = seg.value / total * circumference;
1745
+ const arcLength = Math.max(0, seg.value / total * circumference);
1746
+ const dash = arcLength - Math.min(gap, arcLength * 0.1);
1735
1747
  const arc = svgEl("circle", {
1736
1748
  cx: "60",
1737
1749
  cy: "60",
@@ -1745,7 +1757,7 @@ function renderDonut(el, opts) {
1745
1757
  });
1746
1758
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
1747
1759
  svg.appendChild(arc);
1748
- offset += dash;
1760
+ offset += arcLength;
1749
1761
  });
1750
1762
  const legend = document.createElement("div");
1751
1763
  legend.className = "icen-chart-legend";
@@ -1780,8 +1792,9 @@ function renderLine(el, opts) {
1780
1792
  const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
1781
1793
  const defs = svgEl("defs", {});
1782
1794
  for (let i = 0; i < 4; i++) {
1783
- const y = pad + i * (height - pad * 2) / 3;
1795
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1784
1796
  svg.appendChild(svgEl("line", {
1797
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1785
1798
  x1: String(pad),
1786
1799
  x2: String(width - pad),
1787
1800
  y1: String(y),
@@ -1865,7 +1878,7 @@ function renderLine(el, opts) {
1865
1878
  if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
1866
1879
  wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
1867
1880
  body.appendChild(wrap);
1868
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1881
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1869
1882
  });
1870
1883
  if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
1871
1884
  attachChartInteraction(el, "line");
@@ -1972,7 +1985,7 @@ function renderRadar(el, opts) {
1972
1985
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
1973
1986
  svg.appendChild(dot);
1974
1987
  }
1975
- legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 }), label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
1988
+ legendItems.push({ key: `${si}:${s.name || t("charts.seriesName", { p0: si + 1 })}`, label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
1976
1989
  });
1977
1990
  wrap.appendChild(svg);
1978
1991
  body.appendChild(wrap);
@@ -1994,6 +2007,11 @@ function niceCeil(v) {
1994
2007
  else nice = 10;
1995
2008
  return nice * base;
1996
2009
  }
2010
+ function tickPrecision(min, max, steps) {
2011
+ const span = Math.abs(max - min);
2012
+ if (!Number.isFinite(span) || span <= 0) return 0;
2013
+ return Math.max(0, Math.ceil(-Math.log10(span / steps)));
2014
+ }
1997
2015
  function isoDate(d) {
1998
2016
  const m = String(d.getMonth() + 1).padStart(2, "0");
1999
2017
  const day = String(d.getDate()).padStart(2, "0");
@@ -2089,7 +2107,8 @@ function renderSparkline(el, opts) {
2089
2107
  const tone = toneVar(opts.tone);
2090
2108
  const points = values.map((value, i) => ({
2091
2109
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
2092
- y: height - pad - value / max * (height - pad * 2),
2110
+ /* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
2111
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
2093
2112
  value
2094
2113
  }));
2095
2114
  const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
@@ -2214,6 +2233,7 @@ function renderCalendar(el, opts) {
2214
2233
  weekdayRow.appendChild(s);
2215
2234
  });
2216
2235
  const max = maxOf(entries.map((e) => e.value));
2236
+ entries.sort((a, b) => a.date.localeCompare(b.date));
2217
2237
  const pad = padFirstWeek(grid, entries[0].date, weekStart);
2218
2238
  let lastMonth = -1;
2219
2239
  entries.forEach((entry, i) => {
@@ -2272,8 +2292,9 @@ function renderScatter(el, opts) {
2272
2292
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
2273
2293
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
2274
2294
  for (let i = 0; i <= 3; i++) {
2275
- const y = pad + i * (height - pad * 2) / 3;
2295
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
2276
2296
  svg.appendChild(svgEl("line", {
2297
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
2277
2298
  x1: String(pad),
2278
2299
  x2: String(width - pad),
2279
2300
  y1: String(y),
@@ -2289,12 +2310,13 @@ function renderScatter(el, opts) {
2289
2310
  "font-size": "8",
2290
2311
  fill: "var(--icen-token-text-faint)"
2291
2312
  });
2292
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2313
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
2293
2314
  svg.appendChild(txt);
2294
2315
  }
2295
2316
  for (let i = 0; i <= 4; i++) {
2296
- const x = pad + i * (width - pad * 2) / 4;
2317
+ const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
2297
2318
  svg.appendChild(svgEl("line", {
2319
+ class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
2298
2320
  x1: String(x),
2299
2321
  x2: String(x),
2300
2322
  y1: String(pad),
@@ -2311,7 +2333,7 @@ function renderScatter(el, opts) {
2311
2333
  "font-size": "8",
2312
2334
  fill: "var(--icen-token-text-faint)"
2313
2335
  });
2314
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2336
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
2315
2337
  svg.appendChild(txt);
2316
2338
  }
2317
2339
  if (opts.yLabel) {
@@ -2675,6 +2697,7 @@ function renderChartSkeleton(body) {
2675
2697
  body.appendChild(box);
2676
2698
  }
2677
2699
  var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2700
+ var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
2678
2701
  function markToneVar(tone) {
2679
2702
  switch (tone) {
2680
2703
  case "success":
@@ -2810,7 +2833,7 @@ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2810
2833
  y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2811
2834
  "text-anchor": "middle",
2812
2835
  "font-size": "8",
2813
- fill: CHART_MARK_ACCENT
2836
+ fill: CHART_MARK_ACCENT_TEXT
2814
2837
  });
2815
2838
  label.textContent = mark.text ?? mark.label;
2816
2839
  g.appendChild(label);
@@ -3368,6 +3391,12 @@ function renderChart(el, raw) {
3368
3391
  const graphic = root.querySelector('[role="img"]');
3369
3392
  if (graphic && !graphic.getAttribute("aria-label")) {
3370
3393
  graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3394
+ } else if (!graphic) {
3395
+ const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
3396
+ if (dom) {
3397
+ dom.setAttribute("role", "img");
3398
+ dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3399
+ }
3371
3400
  }
3372
3401
  }
3373
3402
  if (loading) return;
@@ -3605,8 +3634,12 @@ function buildApproval() {
3605
3634
  }
3606
3635
  function applyTint(item, model) {
3607
3636
  const tint = getAiKind(model.kind).tint;
3608
- if (tint) item.style.setProperty("--ai-item-tint", `var(--icen-token-${tint})`);
3609
- else item.style.removeProperty("--ai-item-tint");
3637
+ if (tint) {
3638
+ const slot = tint === "muted" ? "text-muted" : tint;
3639
+ item.style.setProperty("--ai-item-tint", `var(--icen-token-${slot})`);
3640
+ } else {
3641
+ item.style.removeProperty("--ai-item-tint");
3642
+ }
3610
3643
  }
3611
3644
  function applyKindVisual(parts, model) {
3612
3645
  const kind = getAiKind(model.kind);