@icen.ai/ui 0.9.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 (431) hide show
  1. package/AGENTS.md +82 -254
  2. package/LICENSE +21 -0
  3. package/README.md +60 -96
  4. package/dist/base.css +258 -188
  5. package/dist/behaviors/accordion.mjs +8 -8
  6. package/dist/behaviors/ai-branch.d.mts +1 -1
  7. package/dist/behaviors/ai-branch.mjs +1011 -94
  8. package/dist/behaviors/ai-chat.d.mts +9 -9
  9. package/dist/behaviors/ai-chat.mjs +1122 -169
  10. package/dist/behaviors/ai-composer.d.mts +47 -15
  11. package/dist/behaviors/ai-composer.mjs +2018 -534
  12. package/dist/behaviors/ai-core.d.mts +1 -1
  13. package/dist/behaviors/ai-core.mjs +1017 -107
  14. package/dist/behaviors/ai-diff.mjs +1020 -127
  15. package/dist/behaviors/ai-feedback.d.mts +1 -1
  16. package/dist/behaviors/ai-feedback.mjs +1036 -126
  17. package/dist/behaviors/ai-panel.d.mts +10 -10
  18. package/dist/behaviors/ai-panel.mjs +1285 -266
  19. package/dist/behaviors/ai-provider.d.mts +1 -1
  20. package/dist/behaviors/ai-provider.mjs +1004 -101
  21. package/dist/behaviors/ai-threads.d.mts +1 -1
  22. package/dist/behaviors/ai-threads.mjs +1069 -154
  23. package/dist/behaviors/ai-tool.d.mts +3 -3
  24. package/dist/behaviors/ai-tool.mjs +2087 -413
  25. package/dist/behaviors/ai-tools.d.mts +89 -16
  26. package/dist/behaviors/ai-tools.mjs +5365 -380
  27. package/dist/behaviors/autocomplete.d.mts +53 -0
  28. package/dist/behaviors/autocomplete.mjs +1601 -0
  29. package/dist/behaviors/back-top.d.mts +1 -1
  30. package/dist/behaviors/back-top.mjs +952 -14
  31. package/dist/behaviors/carousel.d.mts +1 -1
  32. package/dist/behaviors/carousel.mjs +914 -12
  33. package/dist/behaviors/cascader.d.mts +48 -0
  34. package/dist/behaviors/cascader.mjs +1867 -0
  35. package/dist/behaviors/charts.d.mts +72 -8
  36. package/dist/behaviors/charts.mjs +1953 -272
  37. package/dist/behaviors/code-block.d.mts +36 -0
  38. package/dist/behaviors/code-block.mjs +1619 -0
  39. package/dist/behaviors/command-palette.d.mts +9 -6
  40. package/dist/behaviors/command-palette.mjs +164 -62
  41. package/dist/behaviors/context-menu.d.mts +10 -9
  42. package/dist/behaviors/context-menu.mjs +1113 -44
  43. package/dist/behaviors/controls.d.mts +21 -21
  44. package/dist/behaviors/controls.mjs +1024 -134
  45. package/dist/behaviors/copy.d.mts +21 -2
  46. package/dist/behaviors/copy.mjs +1207 -42
  47. package/dist/behaviors/datatable.d.mts +55 -5
  48. package/dist/behaviors/datatable.mjs +2033 -212
  49. package/dist/behaviors/date-picker.d.mts +0 -1
  50. package/dist/behaviors/date-picker.mjs +1341 -293
  51. package/dist/behaviors/design.d.mts +54 -0
  52. package/dist/behaviors/design.mjs +109 -0
  53. package/dist/behaviors/dropdown.d.mts +5 -6
  54. package/dist/behaviors/dropdown.mjs +262 -110
  55. package/dist/behaviors/events.d.mts +127 -10
  56. package/dist/behaviors/events.mjs +58 -3
  57. package/dist/behaviors/feedback.d.mts +30 -0
  58. package/dist/behaviors/feedback.mjs +296 -0
  59. package/dist/behaviors/focus.d.mts +8 -0
  60. package/dist/behaviors/focus.mjs +24 -0
  61. package/dist/behaviors/form-validate.d.mts +111 -0
  62. package/dist/behaviors/form-validate.mjs +1746 -0
  63. package/dist/behaviors/i18n.d.mts +790 -0
  64. package/dist/behaviors/i18n.mjs +1713 -0
  65. package/dist/behaviors/icons.d.mts +93 -0
  66. package/dist/behaviors/icons.mjs +113 -0
  67. package/dist/behaviors/input.d.mts +9 -1
  68. package/dist/behaviors/input.mjs +1059 -60
  69. package/dist/behaviors/kb-access.d.mts +3 -3
  70. package/dist/behaviors/kb-access.mjs +2135 -239
  71. package/dist/behaviors/kb-acl.d.mts +8 -8
  72. package/dist/behaviors/kb-acl.mjs +1120 -179
  73. package/dist/behaviors/kb-answer.d.mts +2 -2
  74. package/dist/behaviors/kb-answer.mjs +2120 -435
  75. package/dist/behaviors/kb-audit.d.mts +3 -3
  76. package/dist/behaviors/kb-audit.mjs +1077 -154
  77. package/dist/behaviors/kb-canvas.d.mts +3 -3
  78. package/dist/behaviors/kb-canvas.mjs +1101 -177
  79. package/dist/behaviors/kb-chain.d.mts +2 -2
  80. package/dist/behaviors/kb-chain.mjs +1023 -100
  81. package/dist/behaviors/kb-checkpoint.d.mts +3 -3
  82. package/dist/behaviors/kb-checkpoint.mjs +1320 -169
  83. package/dist/behaviors/kb-chunks.d.mts +2 -2
  84. package/dist/behaviors/kb-chunks.mjs +1153 -213
  85. package/dist/behaviors/kb-citation.d.mts +3 -3
  86. package/dist/behaviors/kb-citation.mjs +1221 -185
  87. package/dist/behaviors/kb-clarify.d.mts +2 -2
  88. package/dist/behaviors/kb-clarify.mjs +1059 -130
  89. package/dist/behaviors/kb-conflict.d.mts +2 -2
  90. package/dist/behaviors/kb-conflict.mjs +1042 -119
  91. package/dist/behaviors/kb-connector.d.mts +2 -2
  92. package/dist/behaviors/kb-connector.mjs +1105 -176
  93. package/dist/behaviors/kb-core.d.mts +7 -2
  94. package/dist/behaviors/kb-core.mjs +1078 -162
  95. package/dist/behaviors/kb-eval.d.mts +2 -2
  96. package/dist/behaviors/kb-eval.mjs +1977 -144
  97. package/dist/behaviors/kb-explain.d.mts +3 -3
  98. package/dist/behaviors/kb-explain.mjs +1037 -104
  99. package/dist/behaviors/kb-filter.d.mts +2 -2
  100. package/dist/behaviors/kb-filter.mjs +2014 -178
  101. package/dist/behaviors/kb-gap.d.mts +3 -3
  102. package/dist/behaviors/kb-gap.mjs +1044 -121
  103. package/dist/behaviors/kb-hittest.d.mts +3 -3
  104. package/dist/behaviors/kb-hittest.mjs +1095 -151
  105. package/dist/behaviors/kb-metadata.mjs +1058 -130
  106. package/dist/behaviors/kb-passage.d.mts +4 -4
  107. package/dist/behaviors/kb-passage.mjs +1102 -161
  108. package/dist/behaviors/kb-pipeline.d.mts +4 -4
  109. package/dist/behaviors/kb-pipeline.mjs +1083 -162
  110. package/dist/behaviors/kb-qa.mjs +1089 -160
  111. package/dist/behaviors/kb-rerank.d.mts +2 -2
  112. package/dist/behaviors/kb-rerank.mjs +1048 -114
  113. package/dist/behaviors/kb-retrieval.d.mts +2 -2
  114. package/dist/behaviors/kb-retrieval.mjs +2079 -226
  115. package/dist/behaviors/kb-review.d.mts +2 -2
  116. package/dist/behaviors/kb-review.mjs +1996 -159
  117. package/dist/behaviors/kb-sandbox.d.mts +3 -3
  118. package/dist/behaviors/kb-sandbox.mjs +1033 -105
  119. package/dist/behaviors/kb-segment.d.mts +2 -2
  120. package/dist/behaviors/kb-segment.mjs +1112 -179
  121. package/dist/behaviors/kb-select.d.mts +24 -0
  122. package/dist/behaviors/kb-select.mjs +1995 -0
  123. package/dist/behaviors/kb-sources.d.mts +3 -3
  124. package/dist/behaviors/kb-sources.mjs +1085 -170
  125. package/dist/behaviors/kb-sql.d.mts +3 -3
  126. package/dist/behaviors/kb-sql.mjs +1144 -226
  127. package/dist/behaviors/kb-trace.d.mts +3 -3
  128. package/dist/behaviors/kb-trace.mjs +1051 -131
  129. package/dist/behaviors/kb-visibility.d.mts +2 -2
  130. package/dist/behaviors/kb-visibility.mjs +1087 -158
  131. package/dist/behaviors/kb-who-can.d.mts +2 -2
  132. package/dist/behaviors/kb-who-can.mjs +1980 -137
  133. package/dist/behaviors/mentions.d.mts +93 -0
  134. package/dist/behaviors/mentions.mjs +2153 -0
  135. package/dist/behaviors/modal.d.mts +4 -3
  136. package/dist/behaviors/modal.mjs +1056 -33
  137. package/dist/behaviors/nav.d.mts +1 -1
  138. package/dist/behaviors/nav.mjs +6 -6
  139. package/dist/behaviors/notification.d.mts +16 -8
  140. package/dist/behaviors/notification.mjs +1629 -268
  141. package/dist/behaviors/panel.d.mts +4 -0
  142. package/dist/behaviors/panel.mjs +995 -0
  143. package/dist/behaviors/popover.d.mts +28 -5
  144. package/dist/behaviors/popover.mjs +225 -24
  145. package/dist/behaviors/scroll-area.d.mts +17 -0
  146. package/dist/behaviors/scroll-area.mjs +59 -0
  147. package/dist/behaviors/select.d.mts +5 -2
  148. package/dist/behaviors/select.mjs +1416 -117
  149. package/dist/behaviors/sidebar.d.mts +1 -1
  150. package/dist/behaviors/sidebar.mjs +13 -13
  151. package/dist/behaviors/slider.d.mts +1 -1
  152. package/dist/behaviors/slider.mjs +12 -12
  153. package/dist/behaviors/split-pane.d.mts +1 -1
  154. package/dist/behaviors/split-pane.mjs +9 -7
  155. package/dist/behaviors/suggestions.d.mts +27 -0
  156. package/dist/behaviors/suggestions.mjs +1090 -0
  157. package/dist/behaviors/svg-parse.d.mts +14 -0
  158. package/dist/behaviors/svg-parse.mjs +37 -0
  159. package/dist/behaviors/tabs.d.mts +2 -2
  160. package/dist/behaviors/tabs.mjs +35 -25
  161. package/dist/behaviors/tag-input.d.mts +23 -5
  162. package/dist/behaviors/tag-input.mjs +1360 -104
  163. package/dist/behaviors/theme-switcher.d.mts +24 -0
  164. package/dist/behaviors/theme-switcher.mjs +1996 -0
  165. package/dist/behaviors/theme.d.mts +15 -8
  166. package/dist/behaviors/theme.mjs +406 -30
  167. package/dist/behaviors/toast.d.mts +24 -25
  168. package/dist/behaviors/toast.mjs +1267 -88
  169. package/dist/behaviors/tooltip.d.mts +4 -0
  170. package/dist/behaviors/tooltip.mjs +378 -0
  171. package/dist/behaviors/tree-select.d.mts +69 -0
  172. package/dist/behaviors/tree-select.mjs +1921 -0
  173. package/dist/behaviors/tree.d.mts +1 -1
  174. package/dist/behaviors/tree.mjs +18 -18
  175. package/dist/behaviors/upload.d.mts +3 -2
  176. package/dist/behaviors/upload.mjs +1077 -66
  177. package/dist/behaviors/url-safety.d.mts +8 -0
  178. package/dist/behaviors/url-safety.mjs +11 -0
  179. package/dist/cli.mjs +5 -6
  180. package/dist/components/accordion.d.mts +2 -0
  181. package/dist/components/ai-branch.d.mts +2 -0
  182. package/dist/components/ai-chat.css +682 -582
  183. package/dist/components/ai-chat.d.mts +2 -0
  184. package/dist/components/ai-composer.d.mts +2 -0
  185. package/dist/components/ai-context.d.mts +2 -0
  186. package/dist/components/ai-context.mjs +1 -0
  187. package/dist/components/ai-diff.css +153 -132
  188. package/dist/components/ai-diff.d.mts +2 -0
  189. package/dist/components/ai-feedback.d.mts +2 -0
  190. package/dist/components/ai-files.d.mts +2 -0
  191. package/dist/components/ai-message.d.mts +2 -0
  192. package/dist/components/ai-panel.css +353 -343
  193. package/dist/components/ai-reasoning.d.mts +2 -0
  194. package/dist/components/ai-subagent.d.mts +2 -0
  195. package/dist/components/ai-subagent.mjs +1 -0
  196. package/dist/components/ai-threads.d.mts +2 -0
  197. package/dist/components/ai-todo.d.mts +2 -0
  198. package/dist/components/ai-todo.mjs +1 -0
  199. package/dist/components/ai-tool-call.d.mts +2 -0
  200. package/dist/components/ai-tool-call.mjs +1 -0
  201. package/dist/components/ai-tool.css +397 -242
  202. package/dist/components/ai-usage.d.mts +2 -0
  203. package/dist/components/alert.d.mts +2 -0
  204. package/dist/components/autocomplete.css +61 -0
  205. package/dist/components/autocomplete.d.mts +2 -0
  206. package/dist/components/autocomplete.mjs +3 -0
  207. package/dist/components/avatar.d.mts +2 -0
  208. package/dist/components/back-top.css +74 -40
  209. package/dist/components/back-top.d.mts +2 -0
  210. package/dist/components/badge.css +44 -41
  211. package/dist/components/badge.d.mts +2 -0
  212. package/dist/components/breadcrumb.css +85 -46
  213. package/dist/components/breadcrumb.d.mts +2 -0
  214. package/dist/components/btn.css +105 -94
  215. package/dist/components/btn.d.mts +2 -0
  216. package/dist/components/card.css +124 -113
  217. package/dist/components/card.d.mts +2 -0
  218. package/dist/components/carousel.d.mts +2 -0
  219. package/dist/components/cascader.css +332 -0
  220. package/dist/components/cascader.d.mts +2 -0
  221. package/dist/components/cascader.mjs +3 -0
  222. package/dist/components/chart-area.css +54 -2
  223. package/dist/components/chart-area.d.mts +2 -0
  224. package/dist/components/chart-bar.css +147 -38
  225. package/dist/components/chart-bar.d.mts +2 -0
  226. package/dist/components/chart-calendar.d.mts +2 -0
  227. package/dist/components/chart-gauge.css +36 -13
  228. package/dist/components/chart-gauge.d.mts +2 -0
  229. package/dist/components/chart-graph.css +35 -20
  230. package/dist/components/chart-graph.d.mts +2 -0
  231. package/dist/components/chart-heatmap.css +67 -39
  232. package/dist/components/chart-heatmap.d.mts +2 -0
  233. package/dist/components/chart-line.css +62 -3
  234. package/dist/components/chart-line.d.mts +2 -0
  235. package/dist/components/chart-map.d.mts +2 -0
  236. package/dist/components/chart-pie.css +38 -6
  237. package/dist/components/chart-pie.d.mts +2 -0
  238. package/dist/components/chart-radar.css +57 -5
  239. package/dist/components/chart-radar.d.mts +2 -0
  240. package/dist/components/chart-scatter.css +47 -7
  241. package/dist/components/chart-scatter.d.mts +2 -0
  242. package/dist/components/chart-sparkline.css +25 -2
  243. package/dist/components/chart-sparkline.d.mts +2 -0
  244. package/dist/components/chart-stack.css +27 -13
  245. package/dist/components/chart-stack.d.mts +2 -0
  246. package/dist/components/charts.css +220 -84
  247. package/dist/components/charts.d.mts +2 -0
  248. package/dist/components/code-block.css +420 -0
  249. package/dist/components/code-block.d.mts +2 -0
  250. package/dist/components/code-block.mjs +4 -0
  251. package/dist/components/command-palette.css +150 -122
  252. package/dist/components/command-palette.d.mts +2 -0
  253. package/dist/components/content.css +274 -263
  254. package/dist/components/context-menu.d.mts +2 -0
  255. package/dist/components/copy.css +73 -45
  256. package/dist/components/copy.d.mts +2 -0
  257. package/dist/components/datatable.css +457 -202
  258. package/dist/components/datatable.d.mts +2 -0
  259. package/dist/components/date-picker.css +136 -105
  260. package/dist/components/date-picker.d.mts +2 -0
  261. package/dist/components/desc.d.mts +2 -0
  262. package/dist/components/dropdown.d.mts +2 -0
  263. package/dist/components/empty.css +72 -69
  264. package/dist/components/empty.d.mts +2 -0
  265. package/dist/components/feedback.css +211 -191
  266. package/dist/components/form-validate.css +134 -0
  267. package/dist/components/form-validate.d.mts +2 -0
  268. package/dist/components/form-validate.mjs +3 -0
  269. package/dist/components/form.css +157 -131
  270. package/dist/components/form.d.mts +2 -0
  271. package/dist/components/icon.css +113 -0
  272. package/dist/components/icon.d.mts +2 -0
  273. package/dist/components/icon.mjs +3 -0
  274. package/dist/components/input.css +163 -108
  275. package/dist/components/input.d.mts +2 -0
  276. package/dist/components/kb-access.d.mts +2 -0
  277. package/dist/components/kb-acl.d.mts +2 -0
  278. package/dist/components/kb-agent.css +300 -206
  279. package/dist/components/kb-answer.d.mts +2 -0
  280. package/dist/components/kb-audit.d.mts +2 -0
  281. package/dist/components/kb-canvas.d.mts +2 -0
  282. package/dist/components/kb-chain.d.mts +2 -0
  283. package/dist/components/kb-checkpoint.d.mts +2 -0
  284. package/dist/components/kb-chunks.d.mts +2 -0
  285. package/dist/components/kb-citation.d.mts +2 -0
  286. package/dist/components/kb-clarify.d.mts +2 -0
  287. package/dist/components/kb-conflict.d.mts +2 -0
  288. package/dist/components/kb-connector.d.mts +2 -0
  289. package/dist/components/kb-data.css +431 -315
  290. package/dist/components/kb-eval.d.mts +2 -0
  291. package/dist/components/kb-explain.d.mts +2 -0
  292. package/dist/components/kb-filter.d.mts +2 -0
  293. package/dist/components/kb-gap.d.mts +2 -0
  294. package/dist/components/kb-ground.css +333 -229
  295. package/dist/components/kb-hittest.d.mts +2 -0
  296. package/dist/components/kb-ingest.css +613 -434
  297. package/dist/components/kb-metadata.d.mts +2 -0
  298. package/dist/components/kb-ops.css +422 -302
  299. package/dist/components/kb-passage.d.mts +2 -0
  300. package/dist/components/kb-perm.css +374 -314
  301. package/dist/components/kb-pipeline.d.mts +2 -0
  302. package/dist/components/kb-qa.d.mts +2 -0
  303. package/dist/components/kb-rerank.d.mts +2 -0
  304. package/dist/components/kb-retrieval.d.mts +2 -0
  305. package/dist/components/kb-review.d.mts +2 -0
  306. package/dist/components/kb-sandbox.d.mts +2 -0
  307. package/dist/components/kb-search.css +653 -459
  308. package/dist/components/kb-segment.d.mts +2 -0
  309. package/dist/components/kb-sources.d.mts +2 -0
  310. package/dist/components/kb-sql.d.mts +2 -0
  311. package/dist/components/kb-trace.d.mts +2 -0
  312. package/dist/components/kb-visibility.d.mts +2 -0
  313. package/dist/components/kb-who-can.d.mts +2 -0
  314. package/dist/components/kb.css +170 -135
  315. package/dist/components/kb.d.mts +2 -0
  316. package/dist/components/kbd.d.mts +2 -0
  317. package/dist/components/layout.css +86 -83
  318. package/dist/components/layout.d.mts +2 -0
  319. package/dist/components/list.d.mts +2 -0
  320. package/dist/components/material-chinese.css +83 -0
  321. package/dist/components/material-soviet.css +86 -0
  322. package/dist/components/material.css +318 -0
  323. package/dist/components/media-card.d.mts +2 -0
  324. package/dist/components/media.css +225 -176
  325. package/dist/components/mentions.css +190 -0
  326. package/dist/components/mentions.d.mts +2 -0
  327. package/dist/components/mentions.mjs +3 -0
  328. package/dist/components/menu.css +121 -109
  329. package/dist/components/modal.css +116 -118
  330. package/dist/components/modal.d.mts +2 -0
  331. package/dist/components/nav.css +136 -129
  332. package/dist/components/nav.d.mts +2 -0
  333. package/dist/components/notification.css +247 -177
  334. package/dist/components/notification.d.mts +2 -0
  335. package/dist/components/pagination.css +62 -57
  336. package/dist/components/pagination.d.mts +2 -0
  337. package/dist/components/panel.css +70 -68
  338. package/dist/components/panel.d.mts +2 -0
  339. package/dist/components/panel.mjs +1 -0
  340. package/dist/components/pill.css +83 -72
  341. package/dist/components/pill.d.mts +2 -0
  342. package/dist/components/popover.css +80 -57
  343. package/dist/components/popover.d.mts +2 -0
  344. package/dist/components/progress.d.mts +2 -0
  345. package/dist/components/rating.d.mts +2 -0
  346. package/dist/components/result.d.mts +2 -0
  347. package/dist/components/scroll-area.css +29 -54
  348. package/dist/components/scroll-area.d.mts +2 -0
  349. package/dist/components/scroll-area.mjs +1 -0
  350. package/dist/components/segmented.css +167 -146
  351. package/dist/components/segmented.d.mts +2 -0
  352. package/dist/components/select.css +250 -191
  353. package/dist/components/select.d.mts +2 -0
  354. package/dist/components/sidebar.css +157 -143
  355. package/dist/components/sidebar.d.mts +2 -0
  356. package/dist/components/skeleton.d.mts +2 -0
  357. package/dist/components/slider.css +135 -128
  358. package/dist/components/slider.d.mts +2 -0
  359. package/dist/components/spinner.d.mts +2 -0
  360. package/dist/components/split-pane.css +120 -108
  361. package/dist/components/split-pane.d.mts +2 -0
  362. package/dist/components/stat.css +116 -109
  363. package/dist/components/stat.d.mts +2 -0
  364. package/dist/components/steps.css +114 -108
  365. package/dist/components/steps.d.mts +2 -0
  366. package/dist/components/switch.css +192 -149
  367. package/dist/components/switch.d.mts +2 -0
  368. package/dist/components/table.css +158 -112
  369. package/dist/components/table.d.mts +2 -0
  370. package/dist/components/tabs.css +143 -116
  371. package/dist/components/tabs.d.mts +2 -0
  372. package/dist/components/tag-input.css +52 -133
  373. package/dist/components/tag-input.d.mts +2 -0
  374. package/dist/components/tag.css +90 -72
  375. package/dist/components/tag.d.mts +2 -0
  376. package/dist/components/theme-switcher.css +105 -0
  377. package/dist/components/theme-switcher.d.mts +2 -0
  378. package/dist/components/theme-switcher.mjs +3 -0
  379. package/dist/components/timeline.d.mts +2 -0
  380. package/dist/components/toast.css +115 -97
  381. package/dist/components/toast.d.mts +2 -0
  382. package/dist/components/toolbar.css +47 -43
  383. package/dist/components/toolbar.d.mts +2 -0
  384. package/dist/components/tooltip.css +103 -43
  385. package/dist/components/tooltip.d.mts +2 -0
  386. package/dist/components/tooltip.mjs +1 -0
  387. package/dist/components/tree-select.css +439 -0
  388. package/dist/components/tree-select.d.mts +2 -0
  389. package/dist/components/tree-select.mjs +3 -0
  390. package/dist/components/tree.d.mts +2 -0
  391. package/dist/components/upload.css +138 -97
  392. package/dist/components/upload.d.mts +2 -0
  393. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  394. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  395. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  396. package/dist/fonts/OFL.txt +96 -0
  397. package/dist/fonts/README.md +14 -0
  398. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  399. package/dist/index.d.mts +85 -70
  400. package/dist/index.mjs +17330 -5773
  401. package/dist/react.d.mts +91 -0
  402. package/dist/react.mjs +8307 -0
  403. package/dist/registry.json +918 -70
  404. package/dist/tokens/chinese.css +44 -0
  405. package/dist/tokens/colors.css +371 -1222
  406. package/dist/tokens/design.css +209 -0
  407. package/dist/tokens/dtcg.json +15926 -0
  408. package/dist/tokens/figma.variables.json +10779 -0
  409. package/dist/tokens/icon-masks.css +78 -0
  410. package/dist/tokens/pixel.css +53 -0
  411. package/dist/tokens/scrollbars.css +40 -0
  412. package/dist/tokens/soviet.css +44 -0
  413. package/dist/tokens/style-profiles.css +36 -547
  414. package/dist/tokens/themes.json +308 -0
  415. package/dist/tokens/tokens-studio.json +11648 -0
  416. package/dist/tokens/typography.css +21 -18
  417. package/dist/tokens.css +1783 -1806
  418. package/dist/ui.css +14796 -10750
  419. package/dist/vue.d.mts +344 -0
  420. package/dist/vue.mjs +7876 -0
  421. package/docs/spec/ai-input-experience.md +75 -0
  422. package/docs/spec/ai-native.md +238 -147
  423. package/docs/spec/design-philosophy.md +189 -0
  424. package/docs/spec/design-primitives.md +196 -0
  425. package/docs/spec/kb-family.md +147 -115
  426. package/docs/spec/scrollbars.md +46 -0
  427. package/package.json +56 -8
  428. package/dist/retro-effects.css +0 -255
  429. package/dist/tokens/retro-effects.css +0 -255
  430. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  431. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -5,6 +5,945 @@ function emitIcen(source, type, detail) {
5
5
  );
6
6
  }
7
7
 
8
+ // src/behaviors/icons.ts
9
+ var ICON_PATHS = {
10
+ file: "M6 2.5h5.5L16 7v9.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-12a2 2 0 0 1 2-2ZM11.5 2.5V7H16",
11
+ folder: "M3 5a1.5 1.5 0 0 1 1.5-1.5H8l2 2h5.5A1.5 1.5 0 0 1 17 7v8a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 3 15Z",
12
+ globe: "M17.5 10a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0ZM2.5 10h15M10 2.5c-4 4-4 11 0 15 4-4 4-11 0-15Z",
13
+ document: "M6 2.5h5.5L16 7v9.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-12a2 2 0 0 1 2-2ZM11.5 2.5V7H16M7 10.5h6M7 13.5h6",
14
+ agent: "M10 6V3M8 3h2M5 6h10a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2ZM1.5 10h1.5M17 10h1.5M7 10v2M13 10v2M8 14h4",
15
+ paperclip: "M14 7 8.3 12.7a1.6 1.6 0 0 1-2.3-2.3l6.3-6.3a3.2 3.2 0 0 1 4.5 4.5l-7 7a4.7 4.7 0 0 1-6.7-6.7l7-7",
16
+ stop: "M6.5 5h7A1.5 1.5 0 0 1 15 6.5v7a1.5 1.5 0 0 1-1.5 1.5h-7A1.5 1.5 0 0 1 5 13.5v-7A1.5 1.5 0 0 1 6.5 5Z",
17
+ terminal: "M5 3.5h10a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2ZM6 7l3 3-3 3M11 13h3",
18
+ branch: "M6 6v8M14 6v2a4 4 0 0 1-4 4H6M8 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM8 16a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM16 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z",
19
+ "line-numbers": "M3 5h2M3 10h2M3 15h2M8 5h9M8 10h9M8 15h9",
20
+ wrap: "M3 5h14M3 10h10a3 3 0 0 1 0 6h-3M12.5 13.5 10 16l2.5 2.5",
21
+ calendar: "M5.5 4h9A2.5 2.5 0 0 1 17 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 3 14.5v-8A2.5 2.5 0 0 1 5.5 4ZM6.5 2.5v3M13.5 2.5v3M3 8h14M6.5 11h.1M10 11h.1M13.5 11h.1M6.5 14h.1M10 14h.1",
22
+ close: "M6 6l8 8M14 6l-8 8",
23
+ check: "M4.5 10.2l3.6 3.6 7.4-7.6",
24
+ "chevron-down": "M5.5 7.75 10 12.25l4.5-4.5",
25
+ "chevron-up": "M5.5 12.25 10 7.75l4.5 4.5",
26
+ "chevron-right": "M7.75 5.5 12.25 10l-4.5 4.5",
27
+ "chevron-left": "M12.25 5.5 7.75 10l4.5 4.5",
28
+ "arrow-right": "M3.5 10h13M11 4.5l5.5 5.5-5.5 5.5",
29
+ "arrow-left": "M16.5 10h-13M9 4.5 3.5 10 9 15.5",
30
+ "arrow-up": "M10 16.5v-13M4.5 9 10 3.5 15.5 9",
31
+ "arrow-down": "M10 3.5v13M4.5 11l5.5 5.5 5.5-5.5",
32
+ plus: "M10 4v12M4 10h12",
33
+ minus: "M4 10h12",
34
+ sort: "M6 15V4M3 7l3-3 3 3M14 5v11M11 13l3 3 3-3",
35
+ search: "M13.3 13.3 17 17M14.5 8.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0",
36
+ sun: "M13.5 10a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0M10 1.75v1.5M10 16.75v1.5M1.75 10h1.5M16.75 10h1.5M4.17 4.17l1.06 1.06M14.77 14.77l1.06 1.06M4.17 15.83l1.06-1.06M14.77 5.23l1.06-1.06",
37
+ moon: "M17.25 11.15A7.5 7.5 0 0 1 8.85 2.75a7.5 7.5 0 1 0 8.4 8.4Z",
38
+ modern: "M6.5 3h7A3.5 3.5 0 0 1 17 6.5v7a3.5 3.5 0 0 1-3.5 3.5h-7A3.5 3.5 0 0 1 3 13.5v-7A3.5 3.5 0 0 1 6.5 3ZM7 10l3-3 3 3-3 3Z",
39
+ pixel: "M3 3h5v5H3ZM12 3h5v5h-5ZM3 12h5v5H3ZM12 12h5v5h-5Z",
40
+ chinese: "M3 8c3 0 5-2 7-5 2 3 4 5 7 5M4 8h12M6 8v8m8-8v8M3 16h14M8 16v-5h4v5",
41
+ soviet: "M3 17h14M5 17V8h4v9m0-12h6v12M7 8V5h2m2 3h2m-2 3h2m-2 3h2M10 5V3h4v2",
42
+ more: "M4 9.9v.2M10 9.9v.2M16 9.9v.2",
43
+ copy: "M7 7h8a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V7ZM13 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2",
44
+ edit: "M11.5 4.5l4 4M4 12l9-9a1.4 1.4 0 0 1 2 0l2 2a1.4 1.4 0 0 1 0 2l-9 9-5 1Z",
45
+ link: "M8 6l2-2a4.2 4.2 0 0 1 6 6l-2 2M12 14l-2 2a4.2 4.2 0 0 1-6-6l2-2M7 13l6-6",
46
+ trash: "M3.5 5.5h13M7 5.5V3h6v2.5M5 5.5l.7 11.5h8.6L15 5.5M8 9v5M12 9v5",
47
+ spinner: "M10 3a7 7 0 1 1-7 7",
48
+ "circle-check": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM6 10l2.7 2.7 5.3-5.4",
49
+ "circle-error": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM7.2 7.2l5.6 5.6M12.8 7.2l-5.6 5.6",
50
+ "circle-info": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM10 9v5M10 6.1v.15",
51
+ "triangle-alert": "M8.7 3.5a1.5 1.5 0 0 1 2.6 0l6.4 11.3a1.5 1.5 0 0 1-1.3 2.2H3.6a1.5 1.5 0 0 1-1.3-2.2ZM10 7.2v4.4M10 14v.15",
52
+ refresh: "M16.5 7.2A7 7 0 0 0 4.3 5.9L2.5 8M2.5 3.5V8H7M3.5 12.8a7 7 0 0 0 12.2 1.3l1.8-2.1M13 12h4.5v4.5",
53
+ external: "M11.5 3H17v5.5M17 3l-8 8M8 3H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-3",
54
+ home: "M3.5 10.25 10 4l6.5 6.25M5.75 8.75v7a.75.75 0 0 0 .75.75h7.5a.75.75 0 0 0 .75-.75v-7",
55
+ settings: "M3.5 5.5h13M3.5 10h13M3.5 14.5h13M7 4v3M12.5 8.5v3M8 13v3",
56
+ star: "M10 2.5l2.4 5.1 5.6.4-4.2 3.7 1.3 5.5-5.1-3-5.1 3 1.3-5.5L1.8 8l5.6-.4Z",
57
+ eye: "M2.2 10s3-5.4 7.8-5.4S17.8 10 17.8 10s-3 5.4-7.8 5.4S2.2 10 2.2 10ZM10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8Z",
58
+ "eye-off": "M2.2 10s3-5.4 7.8-5.4S17.8 10 17.8 10s-3 5.4-7.8 5.4S2.2 10 2.2 10ZM10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8ZM3.5 3.5l13 13",
59
+ inbox: "M3.5 12.25h3.7l1.5 2.5h2.6l1.5-2.5h3.7M4.7 5.5l-1.2 6.75v3.25a1.5 1.5 0 0 0 1.5 1.5h10a1.5 1.5 0 0 0 1.5-1.5v-3.25L15.3 5.5a1.3 1.3 0 0 0-1.25-1H5.95a1.3 1.3 0 0 0-1.25 1Z",
60
+ bell: "M10 3.5a4.5 4.5 0 0 1 4.5 4.5c0 4.5 1.8 5.7 2.5 6.5H3c.7-.8 2.5-2 2.5-6.5A4.5 4.5 0 0 1 10 3.5ZM8.5 16.5a1.6 1.6 0 0 0 3 0",
61
+ users: "M13.8 16.5v-1.5a3.5 3.5 0 0 0-3.5-3.5H6.3a3.5 3.5 0 0 0-3.5 3.5v1.5M8.3 8.9a2.7 2.7 0 1 0 0-5.4 2.7 2.7 0 0 0 0 5.4ZM16.5 16.5v-1.3a3.3 3.3 0 0 0-2.3-3.1M12.3 3.7a2.7 2.7 0 0 1 0 5.2",
62
+ activity: "M17 10h-2.6l-2 5.8L8 4.2 6 10H3",
63
+ "trend-up": "M3.5 14.5l4.2-4.2 2.8 2.8 5.9-5.9M12.4 7.2h4.2v4.2",
64
+ "trend-down": "M3.5 5.5l4.2 4.2 2.8-2.8 5.9 5.9M12.4 12.8h4.2V8.6",
65
+ rocket: "M10 2.5c2 1.5 3.2 4 3.2 6.8 0 1.5-.3 2.9-.8 4.2H7.6c-.5-1.3-.8-2.7-.8-4.2 0-2.8 1.2-5.3 3.2-6.8ZM10 8.6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM7.6 12.5 5.6 15.4c-.9.3-1.6 1-2 2M12.4 12.5l2 2.9c.9.3 1.6 1 2 2M8.7 13.8c0 1.8.5 3.1 1.3 4.2.8-1.1 1.3-2.4 1.3-4.2",
66
+ bold: "M6.5 4h4.2a3 3 0 0 1 0 6H6.5M6.5 10h5a3 3 0 0 1 0 6H6.5M6.5 4v12",
67
+ italic: "M8.5 4.5h7M4.5 15.5h7M12.5 4.5l-5 11",
68
+ underline: "M6 4v5.5a4 4 0 0 0 8 0V4M4.5 16h11",
69
+ "align-left": "M3.5 4.5h13M3.5 10h8.5M3.5 15.5h11",
70
+ "align-center": "M3.5 4.5h13M5.75 10h8.5M4.5 15.5h11",
71
+ "align-right": "M3.5 4.5h13M8 10h8.5M5.5 15.5h11",
72
+ list: "M6.5 5h10M6.5 10h10M6.5 15h10M3.5 5h.01M3.5 10h.01M3.5 15h.01",
73
+ server: "M3 3h14a1.5 1.5 0 0 1 1.5 1.5v2A1.5 1.5 0 0 1 17 8H3a1.5 1.5 0 0 1-1.5-1.5v-2A1.5 1.5 0 0 1 3 3ZM3 12h14a1.5 1.5 0 0 1 1.5 1.5v2A1.5 1.5 0 0 1 17 17H3a1.5 1.5 0 0 1-1.5-1.5v-2A1.5 1.5 0 0 1 3 12ZM5 5.5h.01M5 14.5h.01",
74
+ sparkle: "M10 2.5l1.6 4.3 4.3 1.6-4.3 1.6L10 14.3l-1.6-4.3-4.3-1.6 4.3-1.6ZM15.5 12.5l.8 2.1 2.1.8-2.1.8-.8 2.1-.8-2.1-2.1-.8 2.1-.8Z",
75
+ play: "M6.5 4.8v10.4c0 .9 1 1.5 1.8 1l8.3-5.2a1.2 1.2 0 0 0 0-2L8.3 3.8a1.2 1.2 0 0 0-1.8 1Z",
76
+ "chart-line": "M3.5 3.5v13h13M6.5 12l2.8-2.8 2.2 2.2 4-4.4",
77
+ layers: "M10 3.2 3.6 6.5 10 9.8l6.4-3.3ZM4.5 10.4 10 13.2l5.5-2.8M4.5 13.6 10 16.4l5.5-2.8",
78
+ box: "M17 6 10 3.2 3 6v8l7 2.8 7-2.8ZM3 6l7 2.8L17 6M10 9v7.8",
79
+ filter: "M4 4.5h12l-4.4 5.1v5l-3.2-1.6V9.6Z",
80
+ columns: "M3.5 4h13v12h-13ZM8.2 4v12M12.8 4v12",
81
+ download: "M10 3.5v8M6.8 8.3 10 11.5l3.2-3.2M4 15v2.5a1.5 1.5 0 0 0 1.5 1.5h9a1.5 1.5 0 0 0 1.5-1.5V15"
82
+ };
83
+ var custom = /* @__PURE__ */ new Map();
84
+ function iconPath(name) {
85
+ return Object.hasOwn(ICON_PATHS, name) ? ICON_PATHS[name] : custom.get(name) ?? null;
86
+ }
87
+ function iconAttributes(o = {}) {
88
+ const size = Number.isFinite(o.size) && o.size > 0 ? o.size : 16;
89
+ return { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", width: String(size), height: String(size), fill: "none", stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round", "stroke-linejoin": "round", focusable: "false", class: ["icen-symbol", o.className].filter(Boolean).join(" "), ...o.label ? { role: "img", "aria-label": o.label } : { "aria-hidden": "true" } };
90
+ }
91
+ function createIcon(name, o = {}) {
92
+ if (typeof document === "undefined") return null;
93
+ const path = iconPath(name);
94
+ if (!path) return null;
95
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
96
+ for (const [key, value] of Object.entries(iconAttributes(o))) svg.setAttribute(key, value);
97
+ const line = document.createElementNS(svg.namespaceURI, "path");
98
+ line.setAttribute("d", path);
99
+ svg.append(line);
100
+ return svg;
101
+ }
102
+
103
+ // src/behaviors/i18n.ts
104
+ var ICEN_LOCALE_ZH_CN = {
105
+ /* ── aiBranch ── */
106
+ "aiBranch.nextVersion": "\u4E0B\u4E00\u7248\u672C",
107
+ "aiBranch.prevVersion": "\u4E0A\u4E00\u7248\u672C",
108
+ "aiBranch.version": "\u5206\u652F\u7248\u672C",
109
+ /* ── aiChat ── */
110
+ "aiChat.backToBottom": "\u56DE\u5230\u5E95\u90E8",
111
+ "aiChat.backToBottomCount": "\u56DE\u5230\u5E95\u90E8 \xB7 {p0} \u6761\u65B0\u6D88\u606F",
112
+ "aiChat.continue": "\u7EE7\u7EED\u751F\u6210",
113
+ "aiChat.download": "\u4E0B\u8F7D",
114
+ "aiChat.file": "\u6587\u4EF6",
115
+ "aiChat.roleSystem": "\u7CFB",
116
+ "aiChat.roleTool": "\u5DE5",
117
+ "aiChat.roleUser": "\u6211",
118
+ "aiChat.thinking": "\u601D\u8003 {p0}",
119
+ "aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
120
+ /* ── aiComposer ── */
121
+ "aiComposer.attachAgent": "\u4EE3\u7406",
122
+ "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
123
+ "aiComposer.searchLibrary": "\u641C\u7D22\u6280\u80FD\u3001\u5DE5\u5177\u3001\u6587\u4EF6\u4E0E\u547D\u4EE4",
124
+ "aiComposer.all": "\u5168\u90E8",
125
+ "aiComposer.skills": "\u6280\u80FD",
126
+ "aiComposer.tools": "\u5DE5\u5177",
127
+ "aiComposer.libraryHint": "\u4E0A\u4E0B\u6587\u968F\u6D88\u606F\u53D1\u9001 \xB7 \u547D\u4EE4\u5148\u586B\u5165\u8F93\u5165\u6846",
128
+ "aiComposer.commandHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u6267\u884C \xB7 Esc \u8FD4\u56DE",
129
+ "aiComposer.refHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u5F15\u7528 \xB7 Esc \u8FD4\u56DE",
130
+ "aiComposer.noLibraryMatch": "\u6CA1\u6709\u5339\u914D\u7684\u9879\u76EE\uFF0C\u8BD5\u8BD5\u5176\u4ED6\u5173\u952E\u8BCD",
131
+ "aiComposer.filesNeedAdapter": "\u9644\u4EF6\u5C1A\u672A\u63A5\u901A\u4E0A\u4F20\u3002\u8BF7\u914D\u7F6E prepareMessage \u540E\u91CD\u8BD5\uFF0C\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u6B64\u8BF7\u6C42\u4E2D\u3002",
132
+ "aiComposer.attachDoc": "\u6587\u6863",
133
+ "aiComposer.attachFile": "\u6587\u4EF6",
134
+ "aiComposer.attachFolder": "\u6587\u4EF6\u5939",
135
+ "aiComposer.cacheInvalidHint": "\u5207\u6362\u6A21\u578B\u4F1A\u4F7F prompt \u7F13\u5B58\u5931\u6548",
136
+ "aiComposer.commands": "\u547D\u4EE4",
137
+ "aiComposer.currentTodos": "\u5F53\u524D\u5F85\u529E",
138
+ "aiComposer.done": "\u5B8C\u6210",
139
+ "aiComposer.justNow": "\u521A\u521A \xB7 {p0}",
140
+ "aiComposer.modelAria": "\u6A21\u578B {p0}\uFF08{p1}\uFF09",
141
+ "aiComposer.noCommandMatch": "\u65E0\u5339\u914D\u547D\u4EE4",
142
+ "aiComposer.noModelMatch": "\u65E0\u5339\u914D\u6A21\u578B",
143
+ "aiComposer.noRefMatch": "\u65E0\u5339\u914D\u5F15\u7528",
144
+ "aiComposer.placeholder": "\u8F93\u5165\u6D88\u606F\uFF0C/ \u547D\u4EE4 \xB7 @ \u5F15\u7528 \xB7 Enter \u53D1\u9001",
145
+ "aiComposer.refs": "\u5F15\u7528",
146
+ "aiComposer.removeAttachment": "\u79FB\u9664\u9644\u4EF6 {p0}",
147
+ "aiComposer.removeQueued": "\u79FB\u9664\u6392\u961F\u6D88\u606F {p0}",
148
+ "aiComposer.removeRef": "\u79FB\u9664\u5F15\u7528 {p0}",
149
+ "aiComposer.searchModels": "\u641C\u7D22\u6A21\u578B",
150
+ "aiComposer.selectModel": "\u9009\u62E9\u6A21\u578B",
151
+ "aiComposer.send": "\u53D1\u9001",
152
+ "aiComposer.stop": "\u505C\u6B62\u751F\u6210",
153
+ "aiComposer.stopped": "\u5DF2\u505C\u6B62",
154
+ "aiComposer.todoChip": "\u5F53\u524D\u5F85\u529E {p0}/{p1}{p2}",
155
+ "aiComposer.todoHasError": "\uFF08\u6709\u5931\u8D25\u9879\uFF09",
156
+ /* ── aiCore ── */
157
+ "aiCore.kindBrowser": "\u6D4F\u89C8",
158
+ "aiCore.kindChart": "\u56FE\u8868",
159
+ "aiCore.kindDelete": "\u5220\u9664",
160
+ "aiCore.kindEdit": "\u7F16\u8F91",
161
+ "aiCore.kindFetch": "\u8BF7\u6C42",
162
+ "aiCore.kindGlob": "\u5339\u914D",
163
+ "aiCore.kindGrep": "\u641C\u7D22",
164
+ "aiCore.kindNote": "\u7B14\u8BB0",
165
+ "aiCore.kindPlan": "\u8BA1\u5212",
166
+ "aiCore.kindRead": "\u8BFB\u53D6",
167
+ "aiCore.kindSearch": "\u68C0\u7D22",
168
+ "aiCore.kindShell": "\u547D\u4EE4",
169
+ "aiCore.kindSkill": "\u6280\u80FD",
170
+ "aiCore.kindSubagent": "\u5B50\u4EE3\u7406",
171
+ "aiCore.kindTodo": "\u5F85\u529E",
172
+ "aiCore.kindWrite": "\u5199\u5165",
173
+ "aiCore.statusApproval": "\u5F85\u786E\u8BA4",
174
+ "aiCore.statusCancelled": "\u5DF2\u53D6\u6D88",
175
+ "aiCore.statusDone": "\u5B8C\u6210",
176
+ "aiCore.statusError": "\u5931\u8D25",
177
+ "aiCore.statusPending": "\u7B49\u5F85",
178
+ "aiCore.statusRunning": "\u6267\u884C\u4E2D",
179
+ "aiCore.statusStreaming": "\u6D41\u5F0F\u4E2D",
180
+ "aiCore.todoProgress": "{p0}/{p1} \u5B8C\u6210",
181
+ /* ── aiDiff ── */
182
+ "aiDiff.accepted": "\u5DF2\u63A5\u53D7",
183
+ "aiDiff.binary": "\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u663E\u793A\u6587\u672C\u5DEE\u5F02",
184
+ "aiDiff.empty": "\u65E0\u5DEE\u5F02\u5185\u5BB9",
185
+ "aiDiff.rejected": "\u5DF2\u62D2\u7EDD",
186
+ /* ── aiFeedback ── */
187
+ "aiFeedback.helpful": "\u6709\u5E2E\u52A9",
188
+ "aiFeedback.notHelpful": "\u65E0\u5E2E\u52A9",
189
+ "aiFeedback.reasonCitationMismatch": "\u5F15\u7528\u4E0D\u7B26",
190
+ "aiFeedback.reasonOutdated": "\u5185\u5BB9\u8FC7\u65F6",
191
+ "aiFeedback.reasonUnauthorized": "\u8D8A\u6743\u4FE1\u606F",
192
+ "aiFeedback.reasonUnsourced": "\u65E0\u5F15\u7528\u4F9D\u636E",
193
+ "aiFeedback.reasonWrong": "\u7B54\u6848\u6709\u8BEF",
194
+ "aiFeedback.thanks": "\u611F\u8C22\u53CD\u9988\uFF0C\u5DF2\u5173\u8054\u5230\u8BE5\u6761\u56DE\u7B54\u7684\u8FFD\u8E2A\u8BB0\u5F55",
195
+ /* ── aiPanel ── */
196
+ "aiPanel.audit": "\u5BA1\u8BA1",
197
+ "aiPanel.cacheRead": "\u7F13\u5B58\u8BFB",
198
+ "aiPanel.cacheWrite": "\u7F13\u5B58\u5199",
199
+ "aiPanel.callsTokens": "{p0} \u6B21 \xB7 {p1} tok{p2}",
200
+ "aiPanel.clearAudit": "\u6E05\u9664\u5BA1\u8BA1",
201
+ "aiPanel.context": "\u4E0A\u4E0B\u6587",
202
+ "aiPanel.contextWindow": "\u4E0A\u4E0B\u6587\u7A97\u53E3",
203
+ "aiPanel.errorsCount": "{p0} \u5931\u8D25",
204
+ "aiPanel.files": "\u6587\u4EF6 ({p0})",
205
+ "aiPanel.itemStatus": "{p0}\uFF0C\u72B6\u6001\uFF1A{p1}",
206
+ "aiPanel.noAudit": "\u6682\u65E0\u5BA1\u8BA1\u8BB0\u5F55",
207
+ "aiPanel.noUsage": "\u6682\u65E0\u7528\u91CF",
208
+ "aiPanel.reasoning": "\u63A8\u7406",
209
+ "aiPanel.requestsCount": "{p0} \u6B21\u8BF7\u6C42",
210
+ "aiPanel.ringPercent": "\u4E0A\u4E0B\u6587\u7A97\u53E3\u5360\u7528 {p0}%\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
211
+ "aiPanel.ringUsed": "\u5DF2\u7528 {p0}\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
212
+ "aiPanel.taskProgress": "\u4EFB\u52A1\u8FDB\u5EA6",
213
+ "aiPanel.toolsCount": "{p0} \u5DE5\u5177",
214
+ "aiPanel.usage": "\u7528\u91CF",
215
+ "aiPanel.usageAria": "\u7528\u91CF\uFF1A{p0}",
216
+ /* ── aiProvider ── */
217
+ "aiProvider.audioUrlOnly": "\u4EC5 URL \u7684\u97F3\u9891\uFF08input_audio \u9700 base64\uFF0C\u8BF7\u5148\u53D6\u56DE\u5185\u8054\uFF09",
218
+ "aiProvider.audioUrlOnlyAnthropic": "\u4EC5 URL \u7684\u97F3\u9891\uFF08audio \u5757\u9700 base64 source\uFF09",
219
+ "aiProvider.base64File": "base64 \u6587\u4EF6\uFF08file \u90E8\u4EF6\u9700 Files API file_id\uFF0C\u8BF7\u7F6E\u4E8E url \u69FD\uFF09",
220
+ "aiProvider.corsHint": "\uFF1B\u6D4F\u89C8\u5668\u76F4\u8FDE {p0}\uFF08{p1}\uFF09\u5F88\u53EF\u80FD\u88AB CORS \u62E6\u622A\uFF0C\u5EFA\u8BAE\u7ECF\u4EE3\u7406/\u81EA\u5EFA\u7F51\u5173\u8F6C\u53D1",
221
+ "aiProvider.emptyResponse": "\u54CD\u5E94\u4E3A\u7A7A",
222
+ "aiProvider.glmLabel": "GLM\uFF08\u667A\u8C31\uFF09",
223
+ "aiProvider.invalidJson": "\u54CD\u5E94\u4E0D\u662F\u5408\u6CD5 JSON",
224
+ "aiProvider.kimiLabel": "Kimi\uFF08\u6708\u4E4B\u6697\u9762\uFF09",
225
+ "aiProvider.networkFailed": "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF1A{p0}{p1}",
226
+ "aiProvider.nonPdfDocument": "\u975E PDF \u6587\u4EF6\u5757\uFF08document \u5757\u4E3A application/pdf\uFF0C\u6536\u5230 {p0}\uFF09",
227
+ "aiProvider.requestCancelled": "\u8BF7\u6C42\u5DF2\u53D6\u6D88",
228
+ "aiProvider.resourceRef": "[\u8D44\u6E90] {p0} ({p1})",
229
+ "aiProvider.streamError": "\u6D41\u5F0F\u54CD\u5E94\u9519\u8BEF",
230
+ "aiProvider.toolRoleNoCallId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08openai \u65CF\u9700 tool_call_id\uFF09",
231
+ "aiProvider.toolRoleNoUseId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08anthropic \u65CF\u6620\u5C04 tool_result \u9700 tool_use_id\uFF09",
232
+ "aiProvider.unsupported": "{p0} \u7EBF\u534F\u8BAE\u4E0D\u652F\u6301 {p1}",
233
+ "aiProvider.videoUnsupported": "video \u8F93\u5165\uFF08\u65E0\u4E3B\u6D41 chat API \u652F\u6301\uFF09",
234
+ "aiProvider.videoUnsupportedAnthropic": "video \u8F93\u5165",
235
+ /* ── aiThreads ── */
236
+ "aiThreads.actionsAria": "\u4F1A\u8BDD\u64CD\u4F5C",
237
+ "aiThreads.archived": "\u5DF2\u5F52\u6863",
238
+ /* ── aiTool ── */
239
+ "aiTool.allow": "\u5141\u8BB8",
240
+ "aiTool.reject": "\u62D2\u7EDD",
241
+ /* ── aiTools ── */
242
+ "aiTools.chart.area": "line \u591A\u7CFB\u5217\u586B\u5145\u9762\u79EF",
243
+ "aiTools.chart.data": "\u4EFB\u610F\u7EF4\u5EA6\u539F\u59CB\u8BB0\u5F55 + dims \u5B57\u6BB5\u6620\u5C04\uFF08\u81EA\u52A8\u900F\u89C6\u6210 \u7C7B\u76EE \xD7 \u7CFB\u5217\uFF09",
244
+ "aiTools.chart.dates": "\u8D21\u732E\u65E5\u5386 ISO \u65E5\u671F\uFF08\u4E0E values \u914D\u5BF9\uFF09",
245
+ "aiTools.chart.description": "\u5728\u7528\u6237\u754C\u9762\u6E32\u67D3\u4E00\u5F20\u56FE\u8868\u53EF\u89C6\u5316\u3002\u8F93\u5165\u4E00\u4EFD\u56FE\u8868\u89C4\u683C\uFF08\u7EAF JSON\uFF09\uFF1Alabels+values\uFF08\u7C7B\u76EE\u6570\u503C\uFF09\u3001series\uFF08\u591A\u7CFB\u5217\uFF09\u3001segments\uFF08\u5360\u6BD4\uFF09\u3001points\uFF08\u6563\u70B9\u6C14\u6CE1\uFF09\u3001dates\uFF08\u8D21\u732E\u65E5\u5386\uFF09\u4EFB\u7ED9\u5176\u4E00\uFF1Btype \u7F3A\u7701\u65F6\u6309\u6570\u636E\u5F62\u6001\u81EA\u52A8\u9009\u578B\uFF08\u65F6\u95F4\u5E8F\u5217\u2192\u6298\u7EBF\u3001\u5360\u6BD4\u2192\u73AF\u5F62\u3001\u65E5\u671F\u2192\u8D21\u732E\u65E5\u5386\u3001\u5750\u6807\u70B9\u2192\u6563\u70B9\uFF09\u3002\u56FE\u8868\u5E26\u4EA4\u4E92\uFF08\u60AC\u505C\u63D0\u793A/\u70B9\u51FB/\u53F3\u952E\uFF09\u4E0E\u53EF\u9690\u85CF\u56FE\u4F8B\u3002",
246
+ "aiTools.chart.dims": "data[] \u7684\u5B57\u6BB5\u6620\u5C04\uFF1A{label?, series?, value?, x?, y?}",
247
+ "aiTools.chart.format": "\u6570\u503C\u683C\u5F0F\u5316\uFF1A{notation?: compact|percent|ms, unit?}",
248
+ "aiTools.chart.labels": "\u7C7B\u76EE\u8F74\uFF08line/vbar/hbar\uFF09",
249
+ "aiTools.chart.legend": "false = \u521D\u59CB\u9690\u85CF\u56FE\u4F8B",
250
+ "aiTools.chart.lttb": "\u5927\u6570\u636E\u91CF\u964D\u91C7\u6837\uFF1Atrue=\u81EA\u52A8\u4E0A\u9650\uFF0C\u6570\u5B57=\u6700\u5927\u4FDD\u7559\u70B9\u6570\uFF08\u6E32\u67D3\u5C42\u5951\u7EA6\uFF0C\u968F\u56FE\u8868\u91CD\u5EA6\u573A\u666F\u843D\u5730\uFF09",
251
+ "aiTools.chart.marks": "\u6807\u8BB0\u5C42\uFF08\u9608\u503C\u7EBF/\u53C2\u8003\u533A\u95F4/\u5F3A\u8C03\u70B9\uFF09\uFF0C\u5143\u7D20\u4E3A\u7EAF JSON \u63CF\u8FF0\u5B50\uFF08\u6E32\u67D3\u5C42\u5951\u7EA6\uFF0C\u968F\u56FE\u8868\u91CD\u5EA6\u573A\u666F\u843D\u5730\uFF09",
252
+ "aiTools.chart.points": "\u6563\u70B9/\u6C14\u6CE1\uFF1A[{x,y,size?,label?}]",
253
+ "aiTools.chart.radarAxes": "\u96F7\u8FBE\u8F74\u540D",
254
+ "aiTools.chart.segments": "\u5360\u6BD4\u578B\uFF08donut/stack\uFF09\uFF1A[{label,value}]",
255
+ "aiTools.chart.series": "\u591A\u7CFB\u5217\uFF08line/vbar/radar\uFF09",
256
+ "aiTools.chart.stacked": "vbar \u591A\u7CFB\u5217\u5806\u53E0\uFF08\u9ED8\u8BA4\u5206\u7EC4\uFF09",
257
+ "aiTools.chart.title": "\u56FE\u8868\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5934\u90E8\u884C\u5DE6\u4FA7\uFF09",
258
+ "aiTools.chart.tooltip": "false = \u5173\u95ED\u5185\u7F6E\u63D0\u793A",
259
+ "aiTools.chart.type": "\u56FE\u8868\u7C7B\u578B\uFF0C\u7F3A\u7701\u81EA\u52A8\u63A8\u65AD",
260
+ "aiTools.chart.values": "\u5355\u7CFB\u5217\u6570\u503C\uFF08\u4E0E labels \u914D\u5BF9\uFF09",
261
+ "aiTools.chart.zoom": "\u7F29\u653E\u4EA4\u4E92\uFF1A'x'=\u7C7B\u76EE\u8F74\u533A\u95F4\u7F29\u653E\uFF0C'brush'=\u5237\u9009\u7F29\u653E",
262
+ "aiTools.datatable.columns": "\u5217\u5B9A\u4E49\u6570\u7EC4\uFF1A\u6BCF\u9879 { key, title, sortable?, filterable? }\uFF08key \u5BF9\u5E94 rows \u5143\u7D20\u5B57\u6BB5\u540D\uFF09",
263
+ "aiTools.datatable.description": "\u5728\u7528\u6237\u754C\u9762\u6E32\u67D3\u4E00\u4E2A\u53EF\u641C\u7D22\u3001\u5206\u9875\u3001\u53EF\u5BFC\u51FA CSV \u7684\u6570\u636E\u8868\u683C\u3002\u8F93\u5165\u7EAF JSON\uFF1Acolumns \u4E3A\u5217\u5B9A\u4E49\uFF08key/title \u5FC5\u586B\uFF09\uFF0Crows \u4E3A\u884C\u5BF9\u8C61\u6570\u7EC4\uFF08\u5B57\u6BB5\u540D\u5BF9\u9F50\u5217 key\uFF09\u3002\u8FD4\u56DE { title, rows: \u884C\u6570 } \u6458\u8981\u3002",
264
+ "aiTools.datatable.rows": "\u884C\u6570\u636E\u6570\u7EC4\uFF1A\u6BCF\u9879\u4E3A\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u5B57\u6BB5\u540D\u5BF9\u9F50 columns[].key",
265
+ "aiTools.datatable.title": "\u8868\u683C\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5DE5\u5177\u680F\u5DE6\u4FA7\uFF09",
266
+ "aiTools.execFailed": "\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A{p0}",
267
+ "aiTools.execTimeout": "\u6267\u884C\u8D85\u65F6\uFF08{p0}ms\uFF09",
268
+ "aiTools.manifestHeader": "\u53EF\u7528 UI \u5DE5\u5177\uFF08\u8C03\u7528\u540E\u5728\u7528\u6237\u754C\u9762\u6302\u8F7D\u53EF\u89C6\u5316\u7ED3\u679C\uFF09\uFF1A",
269
+ "aiTools.missingRequired": "\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5",
270
+ "aiTools.none": "\uFF08\u65E0\u5DF2\u6CE8\u518C\u7684 UI \u5DE5\u5177\uFF09",
271
+ "aiTools.notInEnum": "\u4E0D\u5728\u5141\u8BB8\u53D6\u503C\u5185\uFF08{p0}\uFF09",
272
+ "aiTools.numMax": "\u6570\u503C {p0} \u5927\u4E8E\u6700\u5927\u503C {p1}",
273
+ "aiTools.numMin": "\u6570\u503C {p0} \u5C0F\u4E8E\u6700\u5C0F\u503C {p1}",
274
+ "aiTools.removeMount": "\u79FB\u9664 {p0} \u6302\u8F7D",
275
+ "aiTools.strMax": "\u957F\u5EA6 {p0} \u8D85\u8FC7\u4E0A\u9650 {p1}",
276
+ "aiTools.strMin": "\u957F\u5EA6 {p0} \u5C0F\u4E8E\u4E0B\u9650 {p1}",
277
+ "aiTools.typeMismatch": "\u671F\u671B {p0}\uFF0C\u5B9E\u5F97 {p1}",
278
+ "aiTools.validationFailed": "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF08{p0} \u9879\uFF09",
279
+ /* ── autocomplete ── */
280
+ "suggestions.loading": "\u6B63\u5728\u67E5\u627E\u5EFA\u8BAE\u2026",
281
+ "suggestions.error": "\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\u5EFA\u8BAE\uFF0C\u8BF7\u91CD\u8BD5\u3002",
282
+ "suggestions.options": "\u5EFA\u8BAE",
283
+ "suggestions.empty": "\u6CA1\u6709\u5339\u914D\u7684\u5EFA\u8BAE",
284
+ "autocomplete.empty": "\u65E0\u5339\u914D\u7ED3\u679C",
285
+ /* ── backTop ── */
286
+ "backTop.label": "\u56DE\u5230\u9876\u90E8",
287
+ /* ── carousel ── */
288
+ "carousel.item": "\u7B2C {p0} \u5F20",
289
+ "carousel.region": "\u8F6E\u64AD",
290
+ "carousel.slide": "\u5E7B\u706F\u7247",
291
+ "carousel.status": "\u7B2C {p0} / {p1} \u5F20",
292
+ /* ── charts ── */
293
+ "charts.calendarWeekdays": ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"],
294
+ "charts.few": "\u5C11",
295
+ "charts.hideLegend": "\u9690\u85CF\u56FE\u4F8B",
296
+ "charts.loading": "\u52A0\u8F7D\u4E2D",
297
+ "charts.many": "\u591A",
298
+ "charts.monthLabel": "{p0}\u6708",
299
+ "charts.noData": "\u6682\u65E0\u6570\u636E",
300
+ "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
301
+ "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
302
+ "charts.type.area": "\u9762\u79EF\u56FE",
303
+ "charts.type.donut": "\u73AF\u5F62\u56FE",
304
+ "charts.type.gauge": "\u4EEA\u8868\u76D8",
305
+ "charts.type.graph": "\u77E5\u8BC6\u56FE\u8C31",
306
+ "charts.type.heatmap": "\u70ED\u529B\u56FE",
307
+ "charts.type.line": "\u6298\u7EBF\u56FE",
308
+ "charts.type.map": "\u5730\u56FE",
309
+ "charts.type.radar": "\u96F7\u8FBE\u56FE",
310
+ "charts.type.scatter": "\u6563\u70B9\u56FE",
311
+ "charts.type.sparkline": "\u8FF7\u4F60\u8D8B\u52BF",
312
+ "charts.seriesName": "\u7CFB\u5217{p0}",
313
+ "charts.showLegend": "\u663E\u793A\u56FE\u4F8B",
314
+ "charts.value": "\u6570\u503C",
315
+ /* ── themeSwitcher ── */
316
+ "themeSwitcher.appearance": "\u5916\u89C2",
317
+ "themeSwitcher.theme": "\u4E3B\u9898",
318
+ "themeSwitcher.primitive": "\u539F\u8BED",
319
+ "themeSwitcher.mode": "\u660E\u6697",
320
+ "themeSwitcher.light": "\u6D45\u8272",
321
+ "themeSwitcher.dark": "\u6DF1\u8272",
322
+ "themeSwitcher.modern": "\u73B0\u4EE3",
323
+ "themeSwitcher.dongyun": "\u4E1C\u97F5",
324
+ "themeSwitcher.jugou": "\u5DE8\u6784",
325
+ "themeSwitcher.piano": "\u94A2\u7434",
326
+ "themeSwitcher.monet": "\u83AB\u5948",
327
+ "themeSwitcher.vangogh": "\u68B5\u9AD8",
328
+ "themeSwitcher.chinese": "\u4E2D\u5F0F",
329
+ "themeSwitcher.soviet": "\u82CF\u5F0F",
330
+ "themeSwitcher.pixel": "\u50CF\u7D20",
331
+ /* ── codeBlock ── */
332
+ "codeBlock.collapse": "\u6536\u8D77",
333
+ "codeBlock.region": "\u4EE3\u7801\u5185\u5BB9",
334
+ "codeBlock.copyFailed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
335
+ "codeBlock.copyRetry": "\u91CD\u8BD5\u590D\u5236",
336
+ "codeBlock.copy": "\u590D\u5236",
337
+ "codeBlock.foldCollapse": "\u6298\u53E0\u4EE3\u7801",
338
+ "codeBlock.foldExpand": "\u5C55\u5F00\u4EE3\u7801",
339
+ "codeBlock.linesTotal": "\u5171 {p0} \u884C",
340
+ "codeBlock.numHide": "\u9690\u85CF\u884C\u53F7",
341
+ "codeBlock.numShow": "\u663E\u793A\u884C\u53F7",
342
+ "codeBlock.tailAria": "\u5C55\u5F00\u6216\u6536\u8D77\u4EE3\u7801",
343
+ "codeBlock.wrapOff": "\u5173\u95ED\u6362\u884C",
344
+ "codeBlock.wrapOn": "\u81EA\u52A8\u6362\u884C",
345
+ /* ── common ── */
346
+ "common.accept": "\u63A5\u53D7",
347
+ "common.add": "\u65B0\u589E",
348
+ "common.all": "\u5168\u90E8",
349
+ "common.approve": "\u6279\u51C6",
350
+ "common.cancel": "\u53D6\u6D88",
351
+ "common.actionFailed": "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002",
352
+ "common.close": "\u5173\u95ED",
353
+ "common.confirm": "\u786E\u8BA4",
354
+ "common.copied": "\u5DF2\u590D\u5236",
355
+ "common.copy": "\u590D\u5236",
356
+ "common.delete": "\u5220\u9664",
357
+ "common.enable": "\u542F\u7528",
358
+ "common.exportCsv": "\u5BFC\u51FA CSV",
359
+ "common.healthy": "\u6B63\u5E38",
360
+ "common.input": "\u8F93\u5165",
361
+ "common.loadingEllipsis": "\u52A0\u8F7D\u4E2D\u2026",
362
+ "common.official": "\u5B98\u65B9",
363
+ "common.output": "\u8F93\u51FA",
364
+ "common.page": "\u7B2C {p0} \u9875",
365
+ "common.reject": "\u62D2\u7EDD",
366
+ "common.remove": "\u79FB\u9664",
367
+ "common.requestAccess": "\u7533\u8BF7\u8BBF\u95EE",
368
+ "common.requestAccessFor": "\u7533\u8BF7\u8BBF\u95EE {p0}",
369
+ "common.restricted": "\u53D7\u9650",
370
+ "common.retry": "\u91CD\u8BD5",
371
+ "common.rows": "{p0} \u884C",
372
+ "common.run": "\u8FD0\u884C",
373
+ "common.steps": "{p0} \u6B65",
374
+ "common.submit": "\u63D0\u4EA4",
375
+ "common.unknown": "\u672A\u77E5",
376
+ /* ── contextMenu ── */
377
+ "contextMenu.back": "\u540E\u9000",
378
+ "contextMenu.copyPageLink": "\u590D\u5236\u9875\u9762\u94FE\u63A5",
379
+ "contextMenu.forward": "\u524D\u8FDB",
380
+ "contextMenu.refresh": "\u5237\u65B0",
381
+ /* ── copy ── */
382
+ "copy.copied": "\u5DF2\u590D\u5236",
383
+ "copy.failed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
384
+ "copy.denied": "clipboard API \u88AB\u62D2\uFF08{p0}\uFF09\u4E14\u56DE\u9000 execCommand \u5931\u8D25",
385
+ "copy.unavailable": "\u526A\u8D34\u677F\u4E0D\u53EF\u7528\uFF08\u65E0 clipboard API \u4E14 execCommand \u56DE\u9000\u5931\u8D25\uFF09",
386
+ "copy.unknown": "\u672A\u77E5\u9519\u8BEF",
387
+ /* ── datatable ── */
388
+ "datatable.clear": "\u6E05\u7A7A",
389
+ "datatable.collapseGroup": "\u6298\u53E0\u5206\u7EC4 {p0}",
390
+ "datatable.columnSettingsAria": "\u5217\u8BBE\u7F6E",
391
+ "datatable.countUnit": "{p0} \u6761",
392
+ "datatable.editHint": "\u7F16\u8F91\u300C{p0}\u300D\uFF1A\u53CC\u51FB\u6216\u6309 Enter",
393
+ "datatable.editHintWithValue": "{p0}\uFF08\u53CC\u51FB\u6216\u6309 Enter \u7F16\u8F91\u300C{p1}\u300D\uFF09",
394
+ "datatable.empty": "\u6682\u65E0\u6570\u636E",
395
+ "datatable.emptyValue": "\uFF08\u7A7A\uFF09",
396
+ "datatable.expandGroup": "\u5C55\u5F00\u5206\u7EC4 {p0}",
397
+ "datatable.expandRow": "\u5C55\u5F00\u884C",
398
+ "datatable.filterChipAria": "\u7B5B\u9009\u300C{p0}\u300D",
399
+ "datatable.pageSizeAria": "\u6BCF\u9875\u6761\u6570",
400
+ "datatable.paginationAria": "\u5206\u9875",
401
+ "datatable.reset": "\u91CD\u7F6E",
402
+ "datatable.resizeAria": "\u8C03\u6574\u300C{p0}\u300D\u5217\u5BBD",
403
+ "datatable.searchAria": "\u641C\u7D22\u8868\u683C",
404
+ "datatable.searchPlaceholder": "\u641C\u7D22\u2026",
405
+ "datatable.selectAll": "\u5168\u9009",
406
+ "datatable.selectRow": "\u9009\u62E9\u8BE5\u884C",
407
+ "datatable.selectedCount": "\u5DF2\u9009 {p0} \u9879",
408
+ "datatable.totalCount": "\u5171 {p0} \u6761",
409
+ "datatable.totalLabel": "\u5408\u8BA1",
410
+ /* ── datePicker ── */
411
+ "datePicker.noDates": "\u6CA1\u6709\u53EF\u9009\u65E5\u671F",
412
+ "datePicker.clear": "\u6E05\u9664",
413
+ "datePicker.nextMonth": "\u4E0B\u4E00\u6708",
414
+ "datePicker.prevMonth": "\u4E0A\u4E00\u6708",
415
+ "datePicker.selectDate": "\u9009\u62E9\u65E5\u671F",
416
+ "datePicker.today": "\u4ECA\u5929",
417
+ "datePicker.weekdays": ["\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u65E5"],
418
+ "datePicker.weekdaysSunFirst": ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"],
419
+ "datePicker.yearMonth": "{p0} \u5E74 {p1} \u6708",
420
+ /* ── formValidate ── */
421
+ "formValidate.email": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u90AE\u7BB1\u5730\u5740",
422
+ "formValidate.invalid": "\u8F93\u5165\u4E0D\u5408\u6CD5",
423
+ "formValidate.matches": "\u4E24\u6B21\u8F93\u5165\u4E0D\u4E00\u81F4",
424
+ "formValidate.max": "\u4E0D\u80FD\u5927\u4E8E {max}",
425
+ "formValidate.maxlength": "\u6700\u591A\u8F93\u5165 {max} \u4E2A\u5B57\u7B26",
426
+ "formValidate.min": "\u4E0D\u80FD\u5C0F\u4E8E {min}",
427
+ "formValidate.minlength": "\u81F3\u5C11\u8F93\u5165 {min} \u4E2A\u5B57\u7B26",
428
+ "formValidate.number": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57",
429
+ "formValidate.pattern": "\u8F93\u5165\u683C\u5F0F\u4E0D\u6B63\u786E",
430
+ "formValidate.required": "\u6B64\u9879\u4E3A\u5FC5\u586B\u9879",
431
+ "formValidate.selectPlaceholder": "\u8BF7\u9009\u62E9",
432
+ "formValidate.step": "\u6570\u503C\u5FC5\u987B\u662F {step} \u7684\u500D\u6570",
433
+ "formValidate.summary": "\u8868\u5355\u6709 {p0} \u9879\u5185\u5BB9\u9700\u8981\u4FEE\u6B63\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u65B0\u63D0\u4EA4",
434
+ "formValidate.tool.description": "\u5411\u7528\u6237\u6E32\u67D3\u4E00\u4E2A\u7ED3\u6784\u5316\u8868\u5355\u6536\u96C6\u8F93\u5165",
435
+ "formValidate.tool.fields": "\u5B57\u6BB5\u5217\u8868",
436
+ "formValidate.tool.help": "\u5B57\u6BB5\u4E0B\u65B9\u7684\u5E2E\u52A9\u6587\u6848",
437
+ "formValidate.tool.label": "\u5B57\u6BB5\u6807\u7B7E",
438
+ "formValidate.tool.max": "\u6700\u5927\u503C\uFF08number \u7528\uFF09",
439
+ "formValidate.tool.min": "\u6700\u5C0F\u503C\uFF08number \u7528\uFF09",
440
+ "formValidate.tool.name": "\u5B57\u6BB5\u540D\uFF08\u63D0\u4EA4\u503C\u7684 key\uFF09",
441
+ "formValidate.tool.options": "select \u9009\u9879\uFF08\u5B57\u7B26\u4E32\u6216 {label,value}\uFF09",
442
+ "formValidate.tool.pattern": "\u6B63\u5219\u7EA6\u675F\uFF08HTML pattern \u8BED\u6CD5\uFF0C\u6574\u4E32\u5339\u914D\uFF09",
443
+ "formValidate.tool.required": "\u662F\u5426\u5FC5\u586B",
444
+ "formValidate.tool.submitText": "\u63D0\u4EA4\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4\u300C\u63D0\u4EA4\u300D",
445
+ "formValidate.tool.title": "\u8868\u5355\u6807\u9898\uFF08\u53EF\u9009\uFF09",
446
+ "formValidate.tool.type": "\u63A7\u4EF6\u7C7B\u578B\uFF0C\u9ED8\u8BA4 text",
447
+ "formValidate.url": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u94FE\u63A5\u5730\u5740",
448
+ /* ── input ── */
449
+ "input.clearSearch": "\u6E05\u7A7A\u641C\u7D22",
450
+ "input.hidePassword": "\u9690\u85CF\u5BC6\u7801",
451
+ "input.otpPosition": "\u7B2C {p0} \u4F4D\uFF0C\u5171 {p1} \u4F4D",
452
+ "panel.expand": "\u5C55\u5F00",
453
+ "panel.collapse": "\u6298\u53E0",
454
+ "input.showPassword": "\u663E\u793A\u5BC6\u7801",
455
+ /* ── kbAccess ── */
456
+ "kbAccess.approveTip": "\u6279\u51C6\u8BE5\u8BBF\u95EE\u7533\u8BF7",
457
+ "kbAccess.approvedBadge": "\u5DF2\u6279\u51C6 \xB7 {p0}",
458
+ "kbAccess.approverNotePlaceholder": "\u7ED9\u8BF7\u6C42\u4EBA\u7684\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
459
+ "kbAccess.daysLeft": "{p0} \u5929\u540E",
460
+ "kbAccess.defaultSubject": "\u8BE5\u5185\u5BB9",
461
+ "kbAccess.deniedHint": "\u672A\u901A\u8FC7\u2014\u2014\u53EF\u8C03\u6574\u7406\u7531\u540E\u91CD\u65B0\u7533\u8BF7",
462
+ "kbAccess.denyNoteLabel": "\u62D2\u7EDD\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
463
+ "kbAccess.duration30d": "30 \u5929",
464
+ "kbAccess.duration7d": "7 \u5929",
465
+ "kbAccess.durationForever": "\u6C38\u4E45",
466
+ "kbAccess.durationLabel": "\u8BBF\u95EE\u65F6\u957F",
467
+ "kbAccess.expired": "\u5DF2\u5230\u671F",
468
+ "kbAccess.expiresAt": "{p0}\u5230\u671F",
469
+ "kbAccess.grantAsPrefix": "\u6279\u51C6\u4E3A{p0}",
470
+ "kbAccess.grantRoleLabel": "\u6279\u51C6\u89D2\u8272",
471
+ "kbAccess.hoursLeft": "{p0} \u5C0F\u65F6\u540E",
472
+ "kbAccess.minutesLeft": "{p0} \u5206\u949F\u540E",
473
+ "kbAccess.ownerLabel": "\u5185\u5BB9\u8D1F\u8D23\u4EBA",
474
+ "kbAccess.ownerPrefix": "\u8D1F\u8D23\u4EBA\uFF1A{p0}",
475
+ "kbAccess.reapply": "\u91CD\u65B0\u7533\u8BF7",
476
+ "kbAccess.reasonLabel": "\u7533\u8BF7\u7406\u7531",
477
+ "kbAccess.reasonPlaceholder": "\u8BF4\u660E\u4E1A\u52A1\u539F\u56E0\uFF08\u5BA1\u6279\u4EBA\u53EF\u89C1\uFF09",
478
+ "kbAccess.rejectTip": "\u62D2\u7EDD\u8BE5\u8BBF\u95EE\u7533\u8BF7",
479
+ "kbAccess.requestRenewal": "\u7533\u8BF7\u7EED\u671F",
480
+ "kbAccess.requestToPrefix": "\u8BF7\u6C42\u5C06\u53D1\u9001\u7ED9\uFF1A{p0}",
481
+ "kbAccess.restrictedContent": "\u53D7\u9650\u5185\u5BB9",
482
+ "kbAccess.restrictedHint": "\u6B64\u5185\u5BB9\u4EC5\u5BF9\u6388\u6743\u8005\u5F00\u653E",
483
+ "kbAccess.revokedHint": "\u8BBF\u95EE\u5DF2\u88AB\u6536\u56DE",
484
+ "kbAccess.roleLabel": "\u7533\u8BF7\u89D2\u8272",
485
+ "kbAccess.submitRequest": "\u63D0\u4EA4\u7533\u8BF7",
486
+ "kbAccess.switchIdentity": "\u5207\u6362\u8EAB\u4EFD",
487
+ "kbAccess.switchIdentityTip": "\u5207\u6362\u8EAB\u4EFD\u540E\u91CD\u65B0\u68C0\u67E5\u6743\u9650",
488
+ "kbAccess.unknownRequester": "\u672A\u77E5\u8BF7\u6C42\u4EBA",
489
+ "kbAccess.waitingApproval": "\u7B49\u5F85 {p0} \u5BA1\u6279",
490
+ /* ── kbAcl ── */
491
+ "kbAcl.breakHint": "\u505C\u6B62\u4ECE\u7236\u7EA7\u7EE7\u627F\uFF0C\u6539\u4E3A\u72EC\u7ACB\u7BA1\u7406\u672C\u9879\u6743\u9650",
492
+ "kbAcl.breakInheritance": "\u505C\u6B62\u7EE7\u627F",
493
+ "kbAcl.brokenNotice": "\u5DF2\u505C\u6B62\u7EE7\u627F\u2014\u2014\u672C\u9879\u6743\u9650\u72EC\u7ACB\u4E8E\u7236\u7EA7",
494
+ "kbAcl.detachedChildren": "{p0}\uFF1A{p1} \u4E2A\u5B50\u9879\u5DF2\u8131\u79BB",
495
+ "kbAcl.directAccess": "\u76F4\u63A5\u8BBF\u95EE",
496
+ "kbAcl.exception": "\u4F8B\u5916",
497
+ "kbAcl.expiredOn": "\u5DF2\u8FC7\u671F\uFF08{p0}\uFF09",
498
+ "kbAcl.expiresIn": "{p0} \u5230\u671F",
499
+ "kbAcl.grantAccess": "\u6388\u4E88\u8BBF\u95EE",
500
+ "kbAcl.inheritedFrom": "\u7EE7\u627F\u81EA {p0}",
501
+ "kbAcl.inheritedFromLabel": "\u7EE7\u627F\u81EA",
502
+ "kbAcl.linkAccess": "\u94FE\u63A5\u8BBF\u95EE",
503
+ "kbAcl.noDirect": "\u6682\u65E0\u76F4\u63A5\u6388\u6743",
504
+ "kbAcl.noLinks": "\u65E0\u94FE\u63A5",
505
+ "kbAcl.removeEntry": "\u79FB\u9664 {p0}",
506
+ "kbAcl.restoreHint": "\u6062\u590D\u7EE7\u627F\u5C06\u4E22\u5F03\u672C\u9879\u81EA\u5B9A\u4E49\u7684\u6743\u9650",
507
+ "kbAcl.restoreInheritance": "\u6062\u590D\u7EE7\u627F",
508
+ "kbAcl.rootNotice": "\u6839\u7EA7\u8D44\u6E90\u2014\u2014\u65E0\u7236\u7EA7\u7EE7\u627F",
509
+ "kbAcl.systemBadge": "\u7CFB\u7EDF\u7BA1\u7406",
510
+ "kbAcl.systemNote": "\u7CFB\u7EDF\u81EA\u52A8\uFF0C\u4E0D\u53EF\u624B\u5DE5\u79FB\u9664",
511
+ "kbAcl.unnamedResource": "\u672A\u547D\u540D\u8D44\u6E90",
512
+ "kbAcl.visibleToCount": "\u5BF9 {p0} \u4EBA\u53EF\u89C1",
513
+ /* ── kbAnswer ── */
514
+ "kbAnswer.chartBar": "\u67F1\u72B6",
515
+ "kbAnswer.chartLine": "\u6298\u7EBF",
516
+ "kbAnswer.chartPie": "\u997C\u56FE",
517
+ "kbAnswer.exportNoun": "\u5BFC\u51FA {p0}",
518
+ "kbAnswer.filtered": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4",
519
+ "kbAnswer.filteredDetail": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4\uFF1A{p0}",
520
+ "kbAnswer.followups": "\u8FFD\u95EE\u5EFA\u8BAE",
521
+ "kbAnswer.hitAssets": "\u547D\u4E2D\u8D44\u4EA7\uFF1A{p0}",
522
+ "kbAnswer.kindCurated": "\u4EBA\u5DE5\u7B56\u5C55",
523
+ "kbAnswer.kindFunction": "\u51FD\u6570",
524
+ "kbAnswer.kindParameterized": "\u53C2\u6570\u5316\u67E5\u8BE2",
525
+ "kbAnswer.maskedPrefix": "\u5DF2\u8131\u654F\u5217\uFF1A",
526
+ "kbAnswer.rerunTip": "\u53C2\u6570\u53EF\u6539\u91CD\u8DD1",
527
+ "kbAnswer.truncated": "\u5DF2\u622A\u65AD\uFF1A\u663E\u793A {p0}/{p1} \u884C{p2}",
528
+ "kbAnswer.verifiedBadge": "\u8BA4\u8BC1\u7B54\u6848",
529
+ /* ── kbAudit ── */
530
+ "kbAudit.actionDetail": "\u5904\u7F6E\uFF1A{p0} \xB7 {p1}",
531
+ "kbAudit.actionLabel": "\u5904\u7F6E",
532
+ "kbAudit.alertedNote": "\u5DF2\u5B9E\u65F6\u544A\u8B66\u5B89\u5168\u56E2\u961F",
533
+ "kbAudit.channelFilterAria": "\u5BA1\u8BA1\u901A\u9053\u8FC7\u6EE4",
534
+ "kbAudit.channelPermission": "\u6743\u9650\u53D8\u66F4",
535
+ "kbAudit.channelRead": "\u8BFB\u53D6",
536
+ "kbAudit.channelRequest": "\u7533\u8BF7",
537
+ "kbAudit.channelSystem": "\u7CFB\u7EDF",
538
+ "kbAudit.empty": "\u6682\u65E0\u5BA1\u8BA1\u4E8B\u4EF6",
539
+ "kbAudit.exportTip": "\u5BFC\u51FA\u5F53\u524D\u8FC7\u6EE4\u89C6\u56FE\u4E3A CSV",
540
+ "kbAudit.hygieneLabel": "\u6743\u9650\u5F02\u5473",
541
+ "kbAudit.noHygiene": "\u672A\u53D1\u73B0\u6743\u9650\u5F02\u5473",
542
+ /* ── kbCanvas ── */
543
+ "kbCanvas.splitterAria": "\u8C03\u6574\u753B\u5E03\u53CC\u680F\u6BD4\u4F8B",
544
+ "kbCanvas.splitterTip": "\u62D6\u62FD\u8C03\u6574\u6BD4\u4F8B\uFF08\u2190/\u2192 \u5FAE\u8C03\uFF0C\u53CC\u51FB\u590D\u4F4D\uFF09",
545
+ /* ── kbCheckpoint ── */
546
+ "kbCheckpoint.chatAuditNote": "\u8BA8\u8BBA\u5386\u53F2\u6709\u5BA1\u8BA1\u4EF7\u503C",
547
+ "kbCheckpoint.label": "\u68C0\u67E5\u70B9",
548
+ "kbCheckpoint.restore": "\u6062\u590D\u68C0\u67E5\u70B9",
549
+ "kbCheckpoint.scopeBoth": "\u5185\u5BB9\u4E0E\u5BF9\u8BDD",
550
+ "kbCheckpoint.scopeChat": "\u4EC5\u5BF9\u8BDD",
551
+ "kbCheckpoint.scopeContent": "\u4EC5\u5185\u5BB9\uFF08\u4FDD\u7559\u5BF9\u8BDD\uFF09",
552
+ "kbCheckpoint.scopeMissing": "\u8BE5\u68C0\u67E5\u70B9\u672A\u5305\u542B\u6B64\u6062\u590D\u8303\u56F4",
553
+ /* ── kbChunks ── */
554
+ "kbChunks.addKeyword": "+ \u5173\u952E\u8BCD",
555
+ "kbChunks.chunkAddKeywordAria": "chunk {p0} \u65B0\u589E\u5173\u952E\u8BCD",
556
+ "kbChunks.chunkContentAria": "chunk {p0} \u5185\u5BB9",
557
+ "kbChunks.chunkEnableAria": "chunk {p0} \u542F\u7528",
558
+ "kbChunks.deleteChunkAria": "\u5220\u9664 chunk {p0}",
559
+ "kbChunks.disableNote": "\u5173\u95ED\u540E\u4E0D\u5220\u9664\uFF0C\u4EC5\u6392\u9664\u51FA\u68C0\u7D22",
560
+ "kbChunks.edited": "\u5DF2\u7F16\u8F91",
561
+ "kbChunks.empty": "\u6682\u65E0 chunk",
562
+ "kbChunks.modeFull": "\u5168\u6587",
563
+ "kbChunks.modeLabel": "\u641C\u7D22\u6A21\u5F0F",
564
+ "kbChunks.modeVector": "\u8BED\u4E49",
565
+ "kbChunks.removeKeyword": "\u79FB\u9664\u5173\u952E\u8BCD {p0}",
566
+ "kbChunks.searchAria": "\u641C\u7D22 chunk",
567
+ "kbChunks.searchFullPlaceholder": "\u5168\u6587\u641C\u7D22 chunk\u2026",
568
+ "kbChunks.searchVectorPlaceholder": "\u8BED\u4E49\u641C\u7D22 chunk\u2026",
569
+ /* ── kbCitation ── */
570
+ "kbCitation.sourceN": "\u6765\u6E90 {p0}",
571
+ "kbCitation.unavailable": "\u6765\u6E90\u5DF2\u4E0D\u53EF\u7528",
572
+ /* ── kbClarify ── */
573
+ "kbClarify.parsedPrefix": "\u5DF2\u89E3\u6790\uFF1A",
574
+ /* ── kbConflict ── */
575
+ "kbConflict.owner": "\u8D23\u4EFB\u4EBA {p0}",
576
+ /* ── kbConnector ── */
577
+ "kbConnector.changeRate": "\u53D8\u66F4\u7387",
578
+ "kbConnector.crawlRate": "\u6293\u53D6\u7387",
579
+ "kbConnector.credentials": "\u51ED\u8BC1",
580
+ "kbConnector.credentialsExpired": "\u51ED\u8BC1\u8FC7\u671F",
581
+ "kbConnector.editSchedule": "\u7F16\u8F91\u8BA1\u5212",
582
+ "kbConnector.empty": "\u6682\u65E0\u8FDE\u63A5\u5668",
583
+ "kbConnector.failing": "\u5F02\u5E38",
584
+ "kbConnector.lastSync": "\u6700\u8FD1\u540C\u6B65 {p0}",
585
+ "kbConnector.neverSynced": "\u4ECE\u672A\u540C\u6B65",
586
+ "kbConnector.notConfigured": "\u672A\u914D\u7F6E",
587
+ "kbConnector.off": "\u5DF2\u505C\u7528",
588
+ "kbConnector.perDay": "{p0}/\u5929",
589
+ "kbConnector.reauth": "\u91CD\u65B0\u6388\u6743",
590
+ "kbConnector.stale": "\u505C\u6EDE",
591
+ "kbConnector.syncNow": "\u7ACB\u5373\u540C\u6B65",
592
+ "kbConnector.synced": "\u5DF2\u540C\u6B65",
593
+ /* ── kbCore ── */
594
+ "kbCore.accessDenied": "\u672A\u901A\u8FC7",
595
+ "kbCore.accessExpired": "\u5DF2\u8FC7\u671F",
596
+ "kbCore.accessExpiring": "\u5373\u5C06\u5230\u671F",
597
+ "kbCore.accessGranted": "\u5DF2\u5F00\u901A",
598
+ "kbCore.accessNotRequested": "\u672A\u7533\u8BF7",
599
+ "kbCore.accessPending": "\u5F85\u5BA1\u6279",
600
+ "kbCore.accessRequested": "\u5DF2\u63D0\u4EA4",
601
+ "kbCore.accessRevoked": "\u5DF2\u6536\u56DE",
602
+ "kbCore.auditApprove": "\u6279\u51C6",
603
+ "kbCore.auditBreakGlass": "\u5E94\u6025\u8BBF\u95EE",
604
+ "kbCore.auditDelegation": "\u59D4\u6D3E",
605
+ "kbCore.auditDeny": "\u62D2\u7EDD",
606
+ "kbCore.auditGrant": "\u6388\u4E88",
607
+ "kbCore.auditPermissionChange": "\u6743\u9650\u53D8\u66F4",
608
+ "kbCore.auditPreview": "\u9884\u89C8",
609
+ "kbCore.auditRead": "\u8BFB\u53D6",
610
+ "kbCore.auditRequest": "\u7533\u8BF7",
611
+ "kbCore.auditRevoke": "\u6536\u56DE",
612
+ "kbCore.auditSync": "\u6743\u9650\u540C\u6B65",
613
+ "kbCore.daysAgo": "{p0} \u5929\u524D",
614
+ "kbCore.hoursAgo": "{p0} \u5C0F\u65F6\u524D",
615
+ "kbCore.hygieneBroadGroup": "\u8FC7\u5BBD\u7EC4\u6388\u6743",
616
+ "kbCore.hygieneBrokenInheritance": "\u65AD\u7EE7\u627F",
617
+ "kbCore.hygieneOrgWideLink": "\u7EC4\u7EC7\u7EA7\u94FE\u63A5",
618
+ "kbCore.hygieneOrphanedOwner": "\u8D1F\u8D23\u4EBA\u7F3A\u4F4D",
619
+ "kbCore.hygieneOverexposed": "\u8FC7\u5EA6\u66B4\u9732",
620
+ "kbCore.hygieneSensitiveMismatch": "\u654F\u611F\u5EA6\u9519\u914D",
621
+ "kbCore.justNow": "\u521A\u521A",
622
+ "kbCore.levelComment": "\u53EF\u8BC4\u8BBA",
623
+ "kbCore.levelEdit": "\u53EF\u7F16\u8F91",
624
+ "kbCore.levelNone": "\u65E0\u6743\u9650",
625
+ "kbCore.levelOwner": "\u8D1F\u8D23\u4EBA",
626
+ "kbCore.levelView": "\u53EF\u67E5\u770B",
627
+ "kbCore.minutesAgo": "{p0} \u5206\u949F\u524D",
628
+ "kbCore.runCancelled": "\u5DF2\u53D6\u6D88",
629
+ "kbCore.runDone": "\u5DF2\u5B8C\u6210",
630
+ "kbCore.runFailed": "\u5931\u8D25",
631
+ "kbCore.runQueued": "\u6392\u961F\u4E2D",
632
+ "kbCore.runRunning": "\u8FDB\u884C\u4E2D",
633
+ "kbCore.runUnstarted": "\u672A\u5F00\u59CB",
634
+ "kbCore.stageAgent": "\u4EE3\u7406",
635
+ "kbCore.stageChunk": "\u5207\u7247",
636
+ "kbCore.stageEmbed": "\u5411\u91CF\u5316",
637
+ "kbCore.stageGeneration": "\u751F\u6210",
638
+ "kbCore.stageGuard": "\u62A4\u680F",
639
+ "kbCore.stageQuery": "\u67E5\u8BE2",
640
+ "kbCore.stageRerank": "\u91CD\u6392",
641
+ "kbCore.stageRetrieval": "\u68C0\u7D22",
642
+ "kbCore.stageTool": "\u5DE5\u5177",
643
+ "kbCore.typeApi": "\u63A5\u53E3",
644
+ "kbCore.typeCode": "\u4EE3\u7801",
645
+ "kbCore.typeDatabase": "\u6570\u636E\u5E93",
646
+ "kbCore.typeDocument": "\u6587\u6863",
647
+ "kbCore.typeEmail": "\u90AE\u4EF6",
648
+ "kbCore.typeImage": "\u56FE\u7247",
649
+ "kbCore.typeKb": "\u77E5\u8BC6\u5E93",
650
+ "kbCore.typeTable": "\u8868\u683C",
651
+ "kbCore.typeTicket": "\u5DE5\u5355",
652
+ "kbCore.typeWebpage": "\u7F51\u9875",
653
+ "kbCore.unnamedSource": "\u672A\u547D\u540D\u6765\u6E90",
654
+ "kbCore.unnamedSubject": "\u672A\u547D\u540D\u4E3B\u4F53",
655
+ "kbCore.visHidden": "\u4E0D\u53EF\u89C1",
656
+ "kbCore.visMetadataOnly": "\u4EC5\u5143\u6570\u636E",
657
+ "kbCore.visSummaryOnly": "\u4EC5\u6458\u8981",
658
+ "kbCore.visVisible": "\u53EF\u89C1",
659
+ /* ── kbEval ── */
660
+ "kbEval.avgA": "A \u5747\u5206 {p0}",
661
+ "kbEval.avgB": "B \u5747\u5206 {p0}",
662
+ "kbEval.compare": "\u5BF9\u6BD4",
663
+ "kbEval.runSelectAria": "\u9009\u62E9\u5BF9\u6BD4\u8FD0\u884C",
664
+ "kbEval.expected": "\u671F\u671B",
665
+ "kbEval.gradeImprovement": "\u63D0\u5347",
666
+ "kbEval.gradeRegression": "\u56DE\u5F52",
667
+ "kbEval.gradeTie": "\u6301\u5E73",
668
+ "kbEval.gradeTradeoff": "\u6743\u8861",
669
+ "kbEval.noData": "\u6CA1\u6709\u5BF9\u6BD4\u6570\u636E",
670
+ "kbEval.onlyRegression": "\u4EC5\u770B\u56DE\u5F52",
671
+ "kbEval.outputA": "\u8F93\u51FA A",
672
+ "kbEval.outputB": "\u8F93\u51FA B",
673
+ "kbEval.outputN": "\u8F93\u51FA {p0}",
674
+ /* ── kbExplain ── */
675
+ "kbExplain.empty": "\u6682\u65E0\u53E3\u5F84\u4FE1\u606F",
676
+ "kbExplain.groupAgg": "\u805A\u5408",
677
+ "kbExplain.groupColumn": "\u5217",
678
+ "kbExplain.groupFilter": "\u7B5B\u9009",
679
+ "kbExplain.groupTable": "\u8868",
680
+ "kbExplain.trigger": "\u8FD9\u4E2A\u6570\u5B57\u662F\u600E\u4E48\u7B97\u51FA\u6765\u7684",
681
+ "kbExplain.viewDefinition": "\u67E5\u770B\u53E3\u5F84",
682
+ /* ── kbFilter ── */
683
+ "kbFilter.addGroup": "+ \u7EC4",
684
+ "kbFilter.addRule": "+ \u89C4\u5219",
685
+ "kbFilter.and": "\u4E14",
686
+ "kbFilter.combineMode": "\u7EC4\u5408\u65B9\u5F0F {p0}",
687
+ "kbFilter.copyDsl": "\u590D\u5236 DSL",
688
+ "kbFilter.deleteGroup": "\u5220\u9664\u7EC4",
689
+ "kbFilter.deleteRule": "\u5220\u9664\u89C4\u5219",
690
+ "kbFilter.fieldLabel": "\u5B57\u6BB5",
691
+ "kbFilter.fieldPlaceholder": "\u8FC7\u6EE4\u5B57\u6BB5",
692
+ "kbFilter.noValueNeeded": "\uFF08\u65E0\u9700\u503C\uFF09",
693
+ "kbFilter.none": "\uFF08\u65E0\u8FC7\u6EE4\uFF09",
694
+ "kbFilter.opContains": "\u5305\u542B",
695
+ "kbFilter.opEq": "\u7B49\u4E8E",
696
+ "kbFilter.opExists": "\u5B58\u5728",
697
+ "kbFilter.opGt": "\u5927\u4E8E",
698
+ "kbFilter.opGte": "\u5927\u4E8E\u7B49\u4E8E",
699
+ "kbFilter.opIn": "\u5C5E\u4E8E",
700
+ "kbFilter.opLt": "\u5C0F\u4E8E",
701
+ "kbFilter.opLte": "\u5C0F\u4E8E\u7B49\u4E8E",
702
+ "kbFilter.opNe": "\u4E0D\u7B49\u4E8E",
703
+ "kbFilter.operatorLabel": "\u64CD\u4F5C\u7B26",
704
+ "kbFilter.or": "\u6216",
705
+ "kbFilter.toggleAndOr": "\u5207\u6362 AND / OR",
706
+ "kbFilter.valueAria": "\u8FC7\u6EE4\u503C",
707
+ "kbFilter.valueLabel": "\u503C",
708
+ "kbFilter.valuePlaceholder": "\u503C 1, \u503C 2\uFF08\u9017\u53F7\u5206\u9694\uFF09",
709
+ /* ── kbGap ── */
710
+ "kbGap.addSynonym": "\u52A0\u540C\u4E49\u8BCD",
711
+ "kbGap.colCount": "\u6B21\u6570",
712
+ "kbGap.colLastSeen": "\u6700\u8FD1\u51FA\u73B0",
713
+ "kbGap.colQuery": "\u67E5\u8BE2",
714
+ "kbGap.colShare": "\u5360\u6BD4",
715
+ "kbGap.createDoc": "\u5EFA\u6587\u6863",
716
+ "kbGap.empty": "\u6CA1\u6709\u672A\u547D\u4E2D\u67E5\u8BE2\u2014\u2014\u8986\u76D6\u826F\u597D",
717
+ "kbGap.title": "\u672A\u547D\u4E2D\u67E5\u8BE2\u8D8B\u52BF",
718
+ "kbGap.zeroClickHint": "\u7528\u6237\u53EF\u80FD\u5DF2\u4ECE\u5F15\u7528\u7247\u6BB5\u5F97\u5230\u7B54\u6848\uFF1B\u96F6\u70B9\u51FB\u9700\u4EBA\u5DE5\u5224\u8BFB\uFF0C\u4E0D\u76F4\u63A5\u89C6\u4E3A\u5931\u8D25",
719
+ "kbGap.zeroClickRate": "\u96F6\u70B9\u51FB\u7387",
720
+ "kbGap.zeroClickTitle": "\u96F6\u70B9\u51FB \u2260 \u5931\u8D25",
721
+ /* ── kbHittest ── */
722
+ "kbHittest.addAria": "\u65B0\u589E\u6D4B\u8BD5\u95EE\u9898",
723
+ "kbHittest.addPlaceholder": "\u65B0\u589E\u95EE\u9898\uFF0CEnter \u6DFB\u52A0",
724
+ "kbHittest.avgScore": "\u5747\u5206",
725
+ "kbHittest.deleteQuestion": "\u5220\u9664\u95EE\u9898",
726
+ "kbHittest.empty": "\u6682\u65E0\u6D4B\u8BD5\u95EE\u9898\u2014\u2014\u6DFB\u52A0\u7B2C\u4E00\u6761\uFF0C\u5F00\u59CB\u53EC\u56DE\u56DE\u5F52",
727
+ "kbHittest.expectHit": "\u671F\u671B\u547D\u4E2D\u5728\u524D\u6392\u547D\u4E2D\u4E2D",
728
+ "kbHittest.expectMiss": "\u671F\u671B\u672A\u547D\u4E2D",
729
+ "kbHittest.hitRate": "\u547D\u4E2D\u7387",
730
+ "kbHittest.noExpectation": "\u672A\u8BBE\u671F\u671B",
731
+ "kbHittest.notRun": "\u672A\u8FD0\u884C",
732
+ "kbHittest.pass": "\u901A\u8FC7",
733
+ "kbHittest.pin": "\u7F6E\u9876\u56FA\u5B9A",
734
+ "kbHittest.runAll": "\u8FD0\u884C\u5168\u90E8",
735
+ "kbHittest.sessionOnly": "\u53C2\u6570\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
736
+ "kbHittest.sessionOnlyHint": "\u6D4B\u8BD5\u8FD0\u884C\u7684\u68C0\u7D22\u53C2\u6570\uFF08topK/\u9608\u503C/\u91CD\u6392\uFF09\u4E0D\u843D\u5E93\uFF0C\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
737
+ "kbHittest.unpin": "\u53D6\u6D88\u7F6E\u9876",
738
+ /* ── kbMetadata ── */
739
+ "kbMetadata.addField": "\u65B0\u589E\u5B57\u6BB5",
740
+ "kbMetadata.builtIn": "\u5185\u7F6E",
741
+ "kbMetadata.colField": "\u5B57\u6BB5",
742
+ "kbMetadata.colType": "\u7C7B\u578B",
743
+ "kbMetadata.colValue": "\u503C",
744
+ "kbMetadata.empty": "\u6682\u65E0\u5143\u6570\u636E\u5B57\u6BB5",
745
+ "kbMetadata.nameLabel": "\u65B0\u5B57\u6BB5\u540D",
746
+ "kbMetadata.namePlaceholder": "\u5B57\u6BB5\u540D\uFF0C\u5982 department",
747
+ "kbMetadata.removeField": "\u79FB\u9664\u5B57\u6BB5 {p0}",
748
+ "kbMetadata.typeLabel": "\u65B0\u5B57\u6BB5\u7C7B\u578B",
749
+ "kbMetadata.valueOf": "{p0} \u7684\u503C",
750
+ /* ── kbPassage ── */
751
+ "kbPassage.blockRange": "\u5757 {p0}\u2013{p1}",
752
+ "kbPassage.close": "\u5173\u95ED\u539F\u6587",
753
+ "kbPassage.expandContext": "\u5C55\u5F00\u4E0A\u4E0B\u6587",
754
+ "kbPassage.locate": "\u539F\u6587\u5B9A\u4F4D",
755
+ "kbPassage.none": "\uFF08\u65E0\u539F\u6587\uFF09",
756
+ "kbPassage.pageRange": "\u7B2C {p0}\u2013{p1} \u9875",
757
+ "kbPassage.restricted": "\u5185\u5BB9\u53D7\u9650",
758
+ "kbPassage.unitByte": "\u5B57\u8282",
759
+ "kbPassage.unitChar": "\u5B57\u7B26",
760
+ /* ── kbPipeline ── */
761
+ "kbPipeline.empty": "\u6682\u65E0\u89E3\u6790\u4EFB\u52A1",
762
+ "kbPipeline.progress": "\u89E3\u6790\u8FDB\u5EA6",
763
+ "kbPipeline.rerun": "\u91CD\u8DD1",
764
+ "kbPipeline.unknownStage": "\u672A\u77E5\u9636\u6BB5",
765
+ /* ── kbQa ── */
766
+ "kbQa.colAnswer": "\u7B54\u6848",
767
+ "kbQa.colQuestion": "\u95EE\u9898",
768
+ "kbQa.csvHint": "CSV \u6A21\u677F\uFF1Aquestion,answer\uFF08\u6BCF\u884C\u4E00\u5BF9\uFF0CUTF-8\uFF09",
769
+ "kbQa.deleteRow": "\u5220\u9664\u7B2C {p0} \u884C",
770
+ "kbQa.empty": "\u6682\u65E0\u8BA4\u8BC1\u95EE\u7B54\u5BF9",
771
+ "kbQa.importCsv": "\u5BFC\u5165 CSV",
772
+ /* ── kbRerank ── */
773
+ "kbRerank.after": "\u91CD\u6392\u540E",
774
+ "kbRerank.before": "\u91CD\u6392\u524D",
775
+ "kbRerank.compareTitle": "\u91CD\u6392\u5BF9\u6BD4",
776
+ "kbRerank.down": "\u4E0B\u964D {p0} \u4F4D",
777
+ "kbRerank.dropped": "\u843D\u9009",
778
+ "kbRerank.empty": "\u4E24\u4FA7\u5747\u4E3A\u7A7A\u2014\u2014\u8FD0\u884C\u68C0\u7D22\u540E\u518D\u5BF9\u6BD4",
779
+ "kbRerank.enableCompare": "\u542F\u7528\u91CD\u6392\u5BF9\u6BD4",
780
+ "kbRerank.newIn": "\u65B0\u8FDB",
781
+ "kbRerank.unmarked": "\u672A\u6807",
782
+ "kbRerank.up": "\u4E0A\u5347 {p0} \u4F4D",
783
+ /* ── kbRetrieval ── */
784
+ "kbRetrieval.breakdown": "\u62C6\u89E3",
785
+ "kbRetrieval.copyParams": "\u590D\u5236\u53C2\u6570 JSON",
786
+ "kbRetrieval.decreaseTopK": "\u51CF\u5C11 topK",
787
+ "kbRetrieval.empty": "\u8F93\u5165\u95EE\u9898\u5E76\u8FD0\u884C\uFF0C\u547D\u4E2D\u7ED3\u679C\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
788
+ "kbRetrieval.failOpenNotice": "fail-open\uFF1A\u5F53\u524D\u67E5\u8BE2\u672A\u643A\u5E26\u8EAB\u4EFD\u8FC7\u6EE4\uFF0C\u5C06\u8FD4\u56DE\u5168\u90E8\u5019\u9009\uFF08\u4EC5\u9650\u8C03\u8BD5\uFF09",
789
+ "kbRetrieval.hybridWeight": "\u6DF7\u5408\u6743\u91CD\uFF08\u5DE6\u8BED\u4E49\u53F3\u5173\u952E\u8BCD\uFF09",
790
+ "kbRetrieval.identityLabel": "\u68C0\u7D22\u8EAB\u4EFD",
791
+ "kbRetrieval.identityShort": "\u8EAB\u4EFD",
792
+ "kbRetrieval.increaseTopK": "\u589E\u52A0 topK",
793
+ "kbRetrieval.keywordHint": "\u5173\u952E\u8BCD\uFF1A\u5927\u5E93\u5FEB\u901F\u7CBE\u786E",
794
+ "kbRetrieval.layerLabel": "\u8FC7\u6EE4\u5C42",
795
+ "kbRetrieval.layerNone": "none\uFF1Afail-open\uFF0C\u65E0\u8EAB\u4EFD\u8FC7\u6EE4\u8FD4\u56DE\u5168\u90E8\u2014\u2014\u5371\u9669\uFF0C\u4EC5\u6F14\u793A",
796
+ "kbRetrieval.layerPost": "post-filter\uFF1A\u5206\u6570\u5DF2\u53EF\u89C2\u5BDF\u2014\u2014\u7F3A\u9677\u5C42\uFF0C\u4EC5\u6F14\u793A",
797
+ "kbRetrieval.layerPre": "pre-filter\uFF1AACL \u5728\u68C0\u7D22\u6267\u884C\u4F53\u5185\u751F\u6548\u2014\u2014\u5B89\u5168\u57FA\u7EBF",
798
+ "kbRetrieval.leakNote": "\u5206\u6BCD\u672A\u8FC7\u6EE4\u524D\u8BA1\u6570\u5C5E\u6CC4\u9732\uFF0C\u4E0D\u663E\u793A",
799
+ "kbRetrieval.modeHybrid": "\u6DF7\u5408",
800
+ "kbRetrieval.modeKeyword": "\u5173\u952E\u8BCD",
801
+ "kbRetrieval.modeLabel": "\u68C0\u7D22\u6A21\u5F0F",
802
+ "kbRetrieval.modeVector": "\u5411\u91CF",
803
+ "kbRetrieval.postFilterNotice": "post-filter\uFF1A\u5206\u6570\u5DF2\u5728\u8FC7\u6EE4\u524D\u4EA7\u751F\uFF08\u7F3A\u9677\u5C42\u6F14\u793A\uFF09",
804
+ "kbRetrieval.queryLabel": "\u68C0\u7D22\u95EE\u9898",
805
+ "kbRetrieval.queryPlaceholder": "\u68C0\u7D22\u95EE\u9898\uFF0CEnter \u8FD0\u884C",
806
+ "kbRetrieval.rerankLabel": "\u91CD\u6392",
807
+ "kbRetrieval.rerankThresholdOff": "\u9608\u503C \u5173 \xB7 \u5B58\u6D3B {p0}",
808
+ "kbRetrieval.rerankThresholdOn": "\u9608\u503C {p0} \xB7 \u5B58\u6D3B {p1}",
809
+ "kbRetrieval.running": "\u8FD0\u884C\u4E2D\u2026",
810
+ "kbRetrieval.thresholdLabel": "\u5206\u6570\u9608\u503C",
811
+ "kbRetrieval.thresholdValue": "\u9608\u503C N/A",
812
+ "kbRetrieval.vectorHint": "\u8BED\u4E49\uFF1A\u8DE8\u8BED\u8A00/\u65E0\u7CBE\u786E\u8BCD",
813
+ "kbRetrieval.vectorPercent": "\u8BED\u4E49 {p0}",
814
+ "kbRetrieval.weightValue": "\u5411\u91CF {p0}% / \u5173\u952E\u8BCD {p1}%",
815
+ /* ── kbReview ── */
816
+ "kbReview.assignee": "\u5206\u914D\u4EBA",
817
+ "kbReview.doneNext": "\u5B8C\u6210\u5E76\u4E0B\u4E00\u6761",
818
+ "kbReview.empty": "\u6CA1\u6709\u5F85\u5BA1\u67E5\u6761\u76EE",
819
+ "kbReview.emptyAssignee": "\u8BE5\u5206\u914D\u4EBA\u4E0B\u6CA1\u6709\u6761\u76EE",
820
+ "kbReview.emptyQueue": "\u961F\u5217\u4E3A\u7A7A",
821
+ "kbReview.kbCloseHint": "\u5173\u95ED\u63D0\u793A",
822
+ "kbReview.kbSelectOption": "\u9009\u62E9\u9009\u9879",
823
+ "kbReview.kbSwitchItem": "\u5207\u6362\u6761\u76EE",
824
+ "kbReview.kbToggleHint": "\u663E\u793A/\u9690\u85CF\u672C\u63D0\u793A",
825
+ "kbReview.shortcuts": "? \u5FEB\u6377\u952E",
826
+ "kbReview.typeAnswer": "\u56DE\u7B54",
827
+ "kbReview.typeMessage": "\u6D88\u606F",
828
+ "kbReview.typeTrace": "\u8F68\u8FF9",
829
+ "kbReview.unassigned": "\u672A\u5206\u914D",
830
+ /* ── kbSandbox ── */
831
+ "kbSandbox.noResolver": "\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668",
832
+ "kbSandbox.notReady": "kb-sandbox: \u5E94\u7528\u672A\u5C31\u7EEA",
833
+ "kbSandbox.resolveFailed": "ui:// \u89E3\u6790\u5931\u8D25\uFF1A{p0}",
834
+ "kbSandbox.timeout": "kb-sandbox: \u8C03\u7528\u8D85\u65F6\uFF08{p0}ms\uFF09",
835
+ "kbSandbox.title": "MCP App \u6C99\u7BB1",
836
+ /* ── kbSegment ── */
837
+ "kbSegment.avgLength": "\u5747\u957F {p0}",
838
+ "kbSegment.childNote": "\u5B50\u5206\u6BB5\u6309\u957F\u5EA6\u81EA\u52A8\u751F\u6210",
839
+ "kbSegment.cleanBlankLines": "\u5408\u5E76\u8FDE\u7EED\u7A7A\u884C",
840
+ "kbSegment.cleanEmails": "\u53BB\u9664\u90AE\u7BB1",
841
+ "kbSegment.cleanLinks": "\u53BB\u9664\u94FE\u63A5",
842
+ "kbSegment.empty": "\u6837\u672C\u4E3A\u7A7A\uFF0C\u6682\u65E0\u53EF\u9884\u89C8\u5206\u6BB5",
843
+ "kbSegment.maxLengthLabel": "\u6700\u5927\u957F\u5EA6",
844
+ "kbSegment.maxLengthPlaceholder": "\u5206\u6BB5\u6700\u5927\u957F\u5EA6",
845
+ "kbSegment.modeAuto": "\u81EA\u52A8",
846
+ "kbSegment.modeCustom": "\u81EA\u5B9A\u4E49",
847
+ "kbSegment.modeLabel": "\u5206\u6BB5\u6A21\u5F0F",
848
+ "kbSegment.modeNote": "\u5206\u6BB5\u6A21\u5F0F\u521B\u5EFA\u540E\u4E0D\u53EF\u66F4\u6539\uFF0C\u53C2\u6570\u53EF\u968F\u65F6\u8C03\u6574",
849
+ "kbSegment.modeParentChild": "\u7236\u5B50",
850
+ "kbSegment.overlapInvalid": "\u91CD\u53E0\u9700\u5C0F\u4E8E\u6700\u5927\u957F\u5EA6",
851
+ "kbSegment.overlapLabel": "\u91CD\u53E0",
852
+ "kbSegment.overlapPlaceholder": "\u5206\u6BB5\u91CD\u53E0",
853
+ "kbSegment.previewNote": "\u5171 {p0} \u6BB5\uFF0C\u4EC5\u9884\u89C8\u524D {p1} \u6BB5",
854
+ "kbSegment.segmentsCount": "{p0} \u6BB5",
855
+ "kbSegment.separatorLabel": "\u5206\u9694\u7B26",
856
+ "kbSegment.separatorPlaceholder": "\u5206\u6BB5\u5206\u9694\u7B26",
857
+ "kbSegment.toggleTip": "\u70B9\u51FB\u5C55\u5F00/\u6536\u8D77",
858
+ /* ── kbSources ── */
859
+ "kbSources.cited": "\u88AB\u5F15 \xD7{p0}",
860
+ "kbSources.empty": "\u4E0B\u4E00\u6761\u7B54\u6848\u5F15\u7528\u7684\u6BB5\u843D\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
861
+ /* ── kbSql ── */
862
+ "kbSql.adminOnly": "\u4EC5\u7BA1\u7406\u5458\u53EF\u89C1",
863
+ "kbSql.applyFix": "\u5E94\u7528\u4FEE\u590D\u5E76\u91CD\u8DD1",
864
+ "kbSql.confirmRerun": "\u786E\u8BA4\u5E76\u91CD\u8DD1",
865
+ "kbSql.editRerun": "\u7F16\u8F91\u91CD\u8DD1",
866
+ "kbSql.fixReady": "\u68C0\u6D4B\u5230\u4E0A\u7248\u62A5\u9519\uFF0C\u4FEE\u590D\u5EFA\u8BAE\u5DF2\u5C31\u7EEA",
867
+ "kbSql.generated": "\u751F\u6210\u7684 SQL",
868
+ /* ── kbTrace ── */
869
+ "kbTrace.empty": "\u6682\u65E0\u8C03\u7528\u94FE\u6570\u636E",
870
+ "kbTrace.hits": "\u547D\u4E2D {p0}",
871
+ /* ── kbVisibility ── */
872
+ "kbVisibility.adminOnlyNote": "\u4EE5\u4E0A\u5BF9\u7167\u4EC5\u9650 admin \u5BA1\u8BA1",
873
+ "kbVisibility.adminWarn": "admin \u5BA1\u8BA1\u89C6\u56FE\u2014\u2014\u547D\u4E2D\u5DEE\u5F02\u5BF9\u7167\u5BF9\u666E\u901A\u7528\u6237\u6784\u6210\u6CC4\u9732\uFF0C\u52FF\u5D4C\u5165\u7EC8\u7AEF\u7528\u6237\u754C\u9762",
874
+ "kbVisibility.failOpenNote": "fail-open\uFF1AKendra \u65E0\u8EAB\u4EFD\u4E0A\u4E0B\u6587\u8FD4\u56DE\u5168\u90E8\u6587\u6863\u2014\u2014\u68C0\u7D22\u5FC5\u987B\u643A\u5E26\u670D\u52A1\u7AEF\u8EAB\u4EFD",
875
+ "kbVisibility.focusColumn": "\u805A\u7126\u8EAB\u4EFD {p0} \u7684\u5217",
876
+ "kbVisibility.layerValue": "\u8FC7\u6EE4\u5C42\uFF1A{p0}",
877
+ "kbVisibility.leakageNote": "\u8BA1\u6570\u5DEE\u5F02\u5373 volume leakage\uFF1A\u5BF9\u666E\u901A\u7528\u6237\u53EA\u53EF\u7ED9\u300C\u5DF2\u6309\u6743\u9650\u8FC7\u6EE4\u300D\u6052\u5B9A\u6587\u6848\uFF0C\u7F13\u89E3\u53EA\u6709 padding \u53D6\u6574",
878
+ "kbVisibility.postFilterNote": "post-filter\uFF1AtopK \u88AB\u65E0\u6743\u7ED3\u679C\u5360\u7528\u4E14\u76F8\u4F3C\u5EA6\u5206\u6570\u53EF\u88AB\u89C2\u5BDF",
879
+ "kbVisibility.queryLabel": "\u67E5\u8BE2\uFF1A{p0}",
880
+ "kbVisibility.safeCount": "\u5B89\u5168\u8BA1\u6570 {p0}",
881
+ "kbVisibility.sourceUnavailable": "\u539F\u6587\u4E0D\u53EF\u7528",
882
+ "kbVisibility.unnamedHit": "\u672A\u547D\u540D\u547D\u4E2D",
883
+ /* ── kbWhoCan ── */
884
+ "kbWhoCan.check": "\u68C0\u67E5",
885
+ "kbWhoCan.checkIdentity": "\u68C0\u67E5\u8EAB\u4EFD",
886
+ "kbWhoCan.daysUntil": "{p0} \u5929\u540E",
887
+ "kbWhoCan.deniedBy": "\u88AB\u7B56\u7565\u62D2\u7EDD\uFF1A{p0}",
888
+ "kbWhoCan.denyVeto": "\u88AB Deny \u4E00\u7968\u5426\u51B3",
889
+ "kbWhoCan.direct": "\u76F4\u63A5",
890
+ "kbWhoCan.expiresSoon": "\u6700\u8FD1\u5230\u671F {p0}",
891
+ "kbWhoCan.hoursUntil": "{p0} \u5C0F\u65F6\u540E",
892
+ "kbWhoCan.inherit": "\u7EE7\u627F",
893
+ "kbWhoCan.link": "\u94FE\u63A5",
894
+ "kbWhoCan.noDeny": "\u65E0 Deny \u751F\u6548",
895
+ "kbWhoCan.noIdentity": "\u672A\u63D0\u4F9B\u53EF\u68C0\u67E5\u7684\u8EAB\u4EFD",
896
+ "kbWhoCan.none": "\u672A\u547D\u4E2D\u4EFB\u4F55\u6388\u6743\u2014\u2014\u9ED8\u8BA4\u62D2\u7EDD",
897
+ "kbWhoCan.recheckTip": "\u91CD\u65B0\u68C0\u67E5\u5F53\u524D\u8EAB\u4EFD\u7684\u6709\u6548\u6743\u9650",
898
+ "kbWhoCan.stackRule": "\u53E0\u52A0\u89C4\u5219\uFF1A\u591A\u6765\u6E90\u5E76\u96C6 \u2192 {p0}\uFF1B{p1}",
899
+ /* ── mentions ── */
900
+ "mentions.create": "\u521B\u5EFA\u201C{p0}\u201D",
901
+ "mentions.customBadge": "\u81EA\u5B9A\u4E49",
902
+ "mentions.loading": "\u52A0\u8F7D\u4E2D\u2026",
903
+ /* ── notification ── */
904
+ "notification.groupBusy": "\u64CD\u4F5C\u7ED3\u675F\u540E\u53EF\u4EE5\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5\u3002",
905
+ "notification.groupUnread": "{count} \u6761\u540C\u7EC4\u901A\u77E5\uFF0C{unread} \u6761\u672A\u8BFB",
906
+ "notification.groupCount": "{count} \u6761\u540C\u7EC4\u901A\u77E5",
907
+ "notification.groupExpanded": "\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5",
908
+ "notification.ariaLabel": "\u901A\u77E5",
909
+ "notification.viewDetails": "\u67E5\u770B\u8BE6\u60C5",
910
+ /* ── pagination ── */
911
+ "pagination.next": "\u4E0B\u4E00\u9875",
912
+ "pagination.pageSize": "{p0} \u6761/\u9875",
913
+ "pagination.prev": "\u4E0A\u4E00\u9875",
914
+ /* ── select ── */
915
+ "select.fieldLabel": "\u9009\u62E9\u9009\u9879",
916
+ "select.noMatch": "\u65E0\u5339\u914D\u9879",
917
+ "select.remove": "\u79FB\u9664 {p0}",
918
+ "select.searchPlaceholder": "\u641C\u7D22\u2026",
919
+ /* ── cascader / tree-select ── */
920
+ "cascader.placeholder": "\u8BF7\u9009\u62E9",
921
+ "cascader.noMatch": "\u65E0\u5339\u914D",
922
+ "cascader.search": "\u641C\u7D22",
923
+ "treeSelect.placeholder": "\u8BF7\u9009\u62E9",
924
+ "treeSelect.noMatch": "\u65E0\u5339\u914D",
925
+ "treeSelect.search": "\u641C\u7D22",
926
+ /* ── tagInput ── */
927
+ "tagInput.ariaLabel": "\u6807\u7B7E\u8F93\u5165\uFF0C\u5171 {p0} \u4E2A",
928
+ "tagInput.remove": "\u79FB\u9664 {p0}",
929
+ "tagInput.field": "\u6DFB\u52A0\u6807\u7B7E",
930
+ "tagInput.added": "\u5DF2\u6DFB\u52A0 {p0} \u4E2A\u6807\u7B7E\u3002",
931
+ "tagInput.removed": "\u5DF2\u79FB\u9664 {p0}\u3002",
932
+ "tagInput.duplicate": "\u5DF2\u6709\u300C{p0}\u300D\uFF0C\u53EF\u4EE5\u7F16\u8F91\u540E\u91CD\u8BD5\u3002",
933
+ "tagInput.limit": "\u6700\u591A {p0} \u4E2A\u6807\u7B7E\uFF0C\u8BF7\u5148\u79FB\u9664\u4E00\u4E2A\u3002",
934
+ /* ── upload ── */
935
+ "upload.remove": "\u79FB\u9664 {p0}",
936
+ "upload.tooBig": "\u6587\u4EF6\u8D85\u8FC7 {p0}",
937
+ "upload.tooMany": "\u6700\u591A {p0} \u4E2A\u6587\u4EF6",
938
+ "upload.typeNotAllowed": "\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301"
939
+ };
940
+ var current = { ...ICEN_LOCALE_ZH_CN };
941
+ function t(key, vars) {
942
+ const raw = current[key] ?? ICEN_LOCALE_ZH_CN[key];
943
+ if (vars == null || Array.isArray(raw)) return raw;
944
+ return raw.replace(/\{(\w+)\}/g, (m, name) => name in vars ? String(vars[name]) : m);
945
+ }
946
+
8
947
  // src/behaviors/charts.ts
9
948
  var SVG_NS = "http://www.w3.org/2000/svg";
10
949
  var REGISTERED_TONES = /* @__PURE__ */ new Map();
@@ -17,16 +956,16 @@ function toneVar(tone = "accent") {
17
956
  if (registered) return registered;
18
957
  switch (tone) {
19
958
  case "success":
20
- return "var(--token-success)";
959
+ return "var(--icen-token-success)";
21
960
  case "warning":
22
- return "var(--token-warning)";
961
+ return "var(--icen-token-warning)";
23
962
  case "error":
24
- return "var(--token-error)";
963
+ return "var(--icen-token-error)";
25
964
  case "muted":
26
- return "var(--token-text-faint)";
965
+ return "var(--icen-token-text-faint)";
27
966
  case "accent":
28
967
  default:
29
- return "var(--token-accent)";
968
+ return "var(--icen-token-accent)";
30
969
  }
31
970
  }
32
971
  function fmt(opts, value) {
@@ -37,13 +976,66 @@ function maxOf(values) {
37
976
  for (const v of values) if (v > max) max = v;
38
977
  return max;
39
978
  }
40
- function sampleLabels(labels, max = 7) {
41
- if (labels.length <= max) return labels;
42
- const out = [];
43
- for (let i = 0; i < max; i++) {
44
- out.push(labels[Math.round(i * (labels.length - 1) / (max - 1))] ?? "");
979
+ function pointLabelsRow(labels, width, pad) {
980
+ const row = document.createElement("div");
981
+ row.className = "icen-chart-labels icen-chart-labels--points";
982
+ const count = Math.min(labels.length, Math.max(2, Math.min(7, Math.floor(width / 64))));
983
+ const step = count > 1 ? (width - 2 * pad) / (count - 1) : width;
984
+ for (let tick = 0; tick < count; tick++) {
985
+ const index = count <= 1 ? 0 : Math.round(tick * (labels.length - 1) / (count - 1));
986
+ const x = labels.length <= 1 ? width / 2 : pad + index / (labels.length - 1) * (width - 2 * pad);
987
+ const span = document.createElement("span");
988
+ span.textContent = labels[index] ?? "";
989
+ span.title = span.textContent;
990
+ span.dir = "auto";
991
+ span.dataset.icenChartIndex = String(index);
992
+ span.style.left = `${x / width * 100}%`;
993
+ span.style.width = `${Math.max(0, Math.min(step * 0.9, 2 * x, 2 * (width - x)))}px`;
994
+ row.appendChild(span);
995
+ }
996
+ return row;
997
+ }
998
+ function clampNum(v, lo, hi) {
999
+ return Math.min(hi, Math.max(lo, v));
1000
+ }
1001
+ function lttb(points, threshold, getX, getY) {
1002
+ const len = points.length;
1003
+ const n = Math.floor(threshold);
1004
+ if (!Number.isFinite(n) || n < 3 || n >= len || len <= 3) return points;
1005
+ const sampled = new Array(n);
1006
+ sampled[0] = points[0];
1007
+ sampled[n - 1] = points[len - 1];
1008
+ const every = (len - 2) / (n - 2);
1009
+ let a = 0;
1010
+ for (let i = 0; i < n - 2; i++) {
1011
+ const avgStart = Math.floor((i + 1) * every) + 1;
1012
+ const avgEnd = Math.min(Math.floor((i + 2) * every) + 1, len);
1013
+ let avgX = 0;
1014
+ let avgY = 0;
1015
+ for (let j = avgStart; j < avgEnd; j++) {
1016
+ avgX += getX(points[j]);
1017
+ avgY += getY(points[j]);
1018
+ }
1019
+ const avgLen = Math.max(1, avgEnd - avgStart);
1020
+ avgX /= avgLen;
1021
+ avgY /= avgLen;
1022
+ const rangeStart = Math.floor(i * every) + 1;
1023
+ const rangeEnd = Math.min(Math.floor((i + 1) * every) + 1, len);
1024
+ const ax = getX(points[a]);
1025
+ const ay = getY(points[a]);
1026
+ let maxArea = -1;
1027
+ let nextA = rangeStart;
1028
+ for (let j = rangeStart; j < rangeEnd; j++) {
1029
+ const area = Math.abs((ax - avgX) * (getY(points[j]) - ay) - (ax - getX(points[j])) * (avgY - ay)) * 0.5;
1030
+ if (area > maxArea) {
1031
+ maxArea = area;
1032
+ nextA = j;
1033
+ }
1034
+ }
1035
+ sampled[i + 1] = points[nextA];
1036
+ a = nextA;
45
1037
  }
46
- return out;
1038
+ return sampled;
47
1039
  }
48
1040
  function svgEl(tag, attrs) {
49
1041
  const el = document.createElementNS(SVG_NS, tag);
@@ -52,28 +1044,28 @@ function svgEl(tag, attrs) {
52
1044
  }
53
1045
  function renderEmpty(el, label) {
54
1046
  const box = document.createElement("div");
55
- box.className = "chart-empty";
56
- box.textContent = label ?? "\u6682\u65E0\u6570\u636E";
1047
+ box.className = "icen-chart-empty";
1048
+ box.textContent = label ?? t("charts.noData");
57
1049
  el.appendChild(box);
58
1050
  }
59
1051
  function legendItem(label, valueText, tone) {
60
1052
  const row = document.createElement("div");
61
- row.className = "chart-legend-item";
1053
+ row.className = "icen-chart-legend-item";
62
1054
  const dot = document.createElement("span");
63
- dot.className = "chart-legend-dot";
1055
+ dot.className = "icen-chart-legend-dot";
64
1056
  if (tone) dot.style.setProperty("--chart-tone", toneVar(tone));
65
1057
  const name = document.createElement("span");
66
- name.className = "chart-legend-label";
1058
+ name.className = "icen-chart-legend-label";
67
1059
  name.textContent = label;
68
1060
  const val = document.createElement("span");
69
- val.className = "chart-legend-value";
1061
+ val.className = "icen-chart-legend-value";
70
1062
  val.textContent = valueText;
71
1063
  row.append(dot, name, val);
72
1064
  return row;
73
1065
  }
74
1066
  function labelsRow(labels) {
75
1067
  const row = document.createElement("div");
76
- row.className = "chart-labels";
1068
+ row.className = "icen-chart-labels";
77
1069
  for (const label of labels) {
78
1070
  const span = document.createElement("span");
79
1071
  span.textContent = label;
@@ -88,110 +1080,123 @@ function normalizeSeriesInput(opts) {
88
1080
  function toneOf(tone, seriesIndex) {
89
1081
  if (typeof tone === "string") return toneVar(tone);
90
1082
  if (typeof tone === "number") return paletteVar(tone);
91
- return seriesIndex > 0 ? paletteVar((seriesIndex - 1) % 6 + 1) : void 0;
1083
+ return seriesIndex > 0 ? paletteVar(seriesIndex % 6 + 1) : void 0;
92
1084
  }
93
1085
  var PALETTE_VARS = [
94
- "var(--token-accent)",
95
- "var(--token-accent-cold)",
96
- "var(--token-success)",
97
- "var(--token-warning)",
98
- "var(--token-info)",
99
- "color-mix(in srgb, var(--token-text) 50%, transparent)"
1086
+ "var(--icen-token-accent)",
1087
+ "var(--icen-token-accent-cold)",
1088
+ "var(--icen-token-success)",
1089
+ "var(--icen-token-warning)",
1090
+ "var(--icen-token-info)",
1091
+ "color-mix(in srgb, var(--icen-token-text) 50%, transparent)"
100
1092
  ];
101
1093
  function paletteVar(index) {
102
1094
  const i = ((Math.floor(index) - 1) % 6 + 6) % 6;
103
1095
  return PALETTE_VARS[i];
104
1096
  }
105
1097
  function setMarkData(node, data) {
106
- node.setAttribute("data-chart-mark", "1");
107
- if (data.index != null) node.setAttribute("data-chart-index", String(data.index));
108
- if (data.seriesIndex != null) node.setAttribute("data-chart-series", String(data.seriesIndex));
109
- if (data.seriesName != null) node.setAttribute("data-chart-series-name", String(data.seriesName));
110
- if (data.label != null) node.setAttribute("data-chart-label", String(data.label));
111
- if (data.value != null) node.setAttribute("data-chart-value", String(data.value));
1098
+ node.setAttribute("data-icen-chart-mark", "1");
1099
+ if (data.index != null) node.setAttribute("data-icen-chart-index", String(data.index));
1100
+ if (data.seriesIndex != null) node.setAttribute("data-icen-chart-series", String(data.seriesIndex));
1101
+ if (data.seriesName != null) node.setAttribute("data-icen-chart-series-name", String(data.seriesName));
1102
+ if (data.label != null) node.setAttribute("data-icen-chart-label", String(data.label));
1103
+ if (data.value != null) node.setAttribute("data-icen-chart-value", String(data.value));
112
1104
  }
113
1105
  function copyMarkData(target, source) {
114
1106
  for (const attr of Array.from(source.attributes)) {
115
- if (attr.name.startsWith("data-chart-")) target.setAttribute(attr.name, attr.value);
116
- }
117
- }
118
- var CHART_EYE_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0"/><circle cx="12" cy="12" r="3"/></svg>';
119
- var CHART_EYE_OFF_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.73 5.08A10.4 10.4 0 0 1 12 5c7 0 10 7 10 7a13.2 13.2 0 0 1-1.67 2.68"/><path d="M6.61 6.61A13.5 13.5 0 0 0 2 12s3 7 10 7a9.7 9.7 0 0 0 5.39-1.61"/><path d="M2 2l20 20"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>';
120
- function parseChartSvg(svg) {
121
- try {
122
- const doc = new DOMParser().parseFromString(svg, "image/svg+xml");
123
- const el = doc.documentElement;
124
- return el && el.tagName.toLowerCase() === "svg" && !doc.querySelector("parsererror") ? document.importNode(el, true) : null;
125
- } catch {
126
- return null;
1107
+ if (attr.name.startsWith("data-icen-chart-")) target.setAttribute(attr.name, attr.value);
127
1108
  }
128
1109
  }
129
- function withChrome(el, opts, hasLegend, paint, state) {
130
- if (el.dataset.chartBody != null) {
1110
+ function withChrome(el, opts, hasLegend, paint, state, extras) {
1111
+ if (el.dataset.icenChartBody != null) {
131
1112
  el.textContent = "";
132
1113
  paint(el);
133
1114
  return;
134
1115
  }
135
1116
  el.textContent = "";
136
1117
  const body = document.createElement("div");
137
- body.className = "chart-body";
138
- body.dataset.chartBody = "";
139
- if (!opts.title && !hasLegend) {
1118
+ body.className = "icen-chart-body";
1119
+ body.dataset.icenChartBody = "";
1120
+ const note = extras?.note ?? null;
1121
+ const onZoomReset = extras?.onZoomReset ?? null;
1122
+ if (!opts.title && !hasLegend && note == null && !onZoomReset) {
140
1123
  el.appendChild(body);
141
1124
  paint(body);
142
1125
  return;
143
1126
  }
144
1127
  let hidden = state && state.hidden != null ? state.hidden : opts.legend === false;
145
1128
  if (state) state.hidden = hidden;
146
- el.setAttribute("data-legend-hidden", String(hidden));
1129
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
147
1130
  const head = document.createElement("div");
148
- head.className = "chart-head";
1131
+ head.className = "icen-chart-head";
149
1132
  const title = document.createElement("div");
150
- title.className = "chart-title";
1133
+ title.className = "icen-chart-title";
151
1134
  title.textContent = opts.title ?? "";
152
1135
  if (!opts.title) title.setAttribute("aria-hidden", "true");
1136
+ if (note != null) {
1137
+ const noteEl = document.createElement("span");
1138
+ noteEl.className = "icen-chart-note";
1139
+ noteEl.textContent = note;
1140
+ head.appendChild(noteEl);
1141
+ }
1142
+ if (onZoomReset) {
1143
+ const chip = document.createElement("button");
1144
+ chip.type = "button";
1145
+ chip.className = "icen-chart-zoom-reset";
1146
+ chip.textContent = t("charts.resetZoom");
1147
+ chip.addEventListener("click", onZoomReset);
1148
+ head.appendChild(chip);
1149
+ }
153
1150
  const eye = document.createElement("button");
154
1151
  eye.type = "button";
155
- eye.className = "chart-legend-eye";
156
- eye.dataset.chartLegendEye = "";
1152
+ eye.className = "icen-chart-legend-eye";
1153
+ eye.dataset.icenChartLegendEye = "";
157
1154
  const syncEye = () => {
158
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1155
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
159
1156
  eye.setAttribute("aria-pressed", String(!nowHidden));
160
- eye.setAttribute("aria-label", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
161
- eye.setAttribute("title", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
162
- const icon = parseChartSvg(nowHidden ? CHART_EYE_OFF_SVG : CHART_EYE_SVG);
1157
+ eye.setAttribute("aria-label", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1158
+ eye.setAttribute("title", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1159
+ const icon = createIcon(nowHidden ? "eye-off" : "eye");
163
1160
  if (icon) eye.replaceChildren(icon);
164
1161
  };
165
1162
  eye.addEventListener("click", () => {
166
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1163
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
167
1164
  hidden = !nowHidden;
168
1165
  if (state) state.hidden = hidden;
169
- el.setAttribute("data-legend-hidden", String(hidden));
1166
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
170
1167
  syncEye();
171
1168
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
172
1169
  });
173
1170
  syncEye();
174
- head.append(title, eye);
1171
+ if (hasLegend) head.append(title, eye);
1172
+ else head.append(title);
175
1173
  el.append(head, body);
176
1174
  paint(body);
177
1175
  }
1176
+ var hiddenLegendKeys = /* @__PURE__ */ new WeakMap();
178
1177
  function toggleLegend(items, scope) {
179
1178
  const legend = document.createElement("div");
180
- legend.className = "chart-legend chart-legend--toggle";
1179
+ legend.className = "icen-chart-legend icen-chart-legend--toggle";
1180
+ const owner = scope instanceof Element ? scope.closest("[data-icen-chart-body]")?.parentElement ?? scope : null;
1181
+ const hidden = owner ? hiddenLegendKeys.get(owner) ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
1182
+ if (owner) hiddenLegendKeys.set(owner, hidden);
181
1183
  for (const item of items) {
182
1184
  const row = legendItem(item.label, "", item.tone);
183
- row.classList.add("chart-legend-toggle-item");
1185
+ row.classList.add("icen-chart-legend-toggle-item");
184
1186
  row.setAttribute("role", "button");
185
1187
  row.tabIndex = 0;
186
- row.setAttribute("aria-pressed", "true");
187
- row.dataset.chartKey = item.key;
188
- const dot = row.querySelector(".chart-legend-dot");
189
- const toneColor = toneOf(item.tone, item.si + 1);
1188
+ row.classList.toggle("is-off", hidden.has(item.key));
1189
+ row.setAttribute("aria-pressed", String(!hidden.has(item.key)));
1190
+ row.dataset.icenChartKey = item.key;
1191
+ const dot = row.querySelector(".icen-chart-legend-dot");
1192
+ const toneColor = toneOf(item.tone, item.si);
190
1193
  if (dot && toneColor) dot.style.setProperty("--chart-tone", toneColor);
191
1194
  const toggle = () => {
192
1195
  const off = row.classList.toggle("is-off");
1196
+ if (off) hidden.add(item.key);
1197
+ else hidden.delete(item.key);
193
1198
  row.setAttribute("aria-pressed", String(!off));
194
- scope.querySelectorAll(`[data-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
1199
+ scope.querySelectorAll(`[data-icen-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
195
1200
  m.classList.toggle("is-off", off);
196
1201
  });
197
1202
  emitIcen(legend, "icen:chart-legend-toggle", { key: item.key, seriesIndex: item.si, hidden: off });
@@ -206,8 +1211,9 @@ function toggleLegend(items, scope) {
206
1211
  legend.appendChild(row);
207
1212
  }
208
1213
  for (const item of items) {
209
- scope.querySelectorAll(`[data-chart-series="${item.si}"]`).forEach((m) => {
210
- if (!m.hasAttribute("data-chart-key")) m.setAttribute("data-chart-key", item.key);
1214
+ scope.querySelectorAll(`[data-icen-chart-series="${item.si}"]`).forEach((m) => {
1215
+ if (!m.hasAttribute("data-icen-chart-key")) m.setAttribute("data-icen-chart-key", item.key);
1216
+ m.classList.toggle("is-off", hidden.has(item.key));
211
1217
  });
212
1218
  }
213
1219
  return legend;
@@ -234,19 +1240,19 @@ function renderVBar(el, opts) {
234
1240
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
235
1241
  }
236
1242
  const wrap = document.createElement("div");
237
- wrap.className = "chart-vbar";
1243
+ wrap.className = "icen-chart-vbar";
238
1244
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
239
1245
  for (let i = 0; i < n; i++) {
240
1246
  const track = document.createElement("div");
241
- track.className = "chart-vbar-track";
1247
+ track.className = "icen-chart-vbar-track";
242
1248
  if (seriesList.length > 1) {
243
- track.classList.add("chart-vbar-track--multi");
244
- if (opts.stacked) track.classList.add("chart-vbar-track--stacked");
1249
+ track.classList.add("icen-chart-vbar-track--multi");
1250
+ if (opts.stacked) track.classList.add("icen-chart-vbar-track--stacked");
245
1251
  }
246
1252
  seriesList.forEach((s, si) => {
247
1253
  const value = s.values[i] ?? 0;
248
1254
  const bar = document.createElement("div");
249
- bar.className = "chart-vbar-bar";
1255
+ bar.className = "icen-chart-vbar-bar";
250
1256
  const height = value > 0 ? Math.max(6, value / max * 100) : 0;
251
1257
  bar.style.height = `${height}%`;
252
1258
  const toneColor = toneOf(s.tone, si);
@@ -264,7 +1270,7 @@ function renderVBar(el, opts) {
264
1270
  wrap.appendChild(track);
265
1271
  }
266
1272
  body.append(wrap, labelsRow(labelsUsed));
267
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1273
+ 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));
268
1274
  });
269
1275
  attachChartInteraction(el, "vbar");
270
1276
  return el;
@@ -281,22 +1287,22 @@ function renderHBar(el, opts) {
281
1287
  const values = opts.values.slice(0, n);
282
1288
  const max = maxOf(values);
283
1289
  const wrap = document.createElement("div");
284
- wrap.className = "chart-hbar";
1290
+ wrap.className = "icen-chart-hbar";
285
1291
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
286
1292
  values.forEach((value, i) => {
287
1293
  const row = document.createElement("div");
288
- row.className = "chart-hbar-row";
1294
+ row.className = "icen-chart-hbar-row";
289
1295
  const label = document.createElement("span");
290
- label.className = "chart-hbar-label";
1296
+ label.className = "icen-chart-hbar-label";
291
1297
  label.textContent = labels[i] ?? "";
292
1298
  const track = document.createElement("div");
293
- track.className = "chart-hbar-track";
1299
+ track.className = "icen-chart-hbar-track";
294
1300
  const bar = document.createElement("div");
295
- bar.className = "chart-hbar-bar";
1301
+ bar.className = "icen-chart-hbar-bar";
296
1302
  bar.style.width = value > 0 ? `${Math.max(2, value / max * 100)}%` : "0%";
297
1303
  setMarkData(bar, { index: i, label: labels[i] ?? "", value });
298
1304
  const val = document.createElement("span");
299
- val.className = "chart-hbar-value";
1305
+ val.className = "icen-chart-hbar-value";
300
1306
  val.textContent = fmt(opts, value);
301
1307
  track.appendChild(bar);
302
1308
  row.append(label, track, val);
@@ -316,10 +1322,10 @@ function renderStack(el, opts) {
316
1322
  return;
317
1323
  }
318
1324
  const bar = document.createElement("div");
319
- bar.className = "chart-stack";
1325
+ bar.className = "icen-chart-stack";
320
1326
  for (const [segIndex, seg] of opts.segments.entries()) {
321
1327
  const s = document.createElement("div");
322
- s.className = "chart-stack-seg";
1328
+ s.className = "icen-chart-stack-seg";
323
1329
  s.style.width = `${seg.value / total * 100}%`;
324
1330
  if (seg.tone) s.style.setProperty("--chart-tone", toneVar(seg.tone));
325
1331
  s.setAttribute("title", `${seg.label}: ${fmt(opts, seg.value)}`);
@@ -327,7 +1333,7 @@ function renderStack(el, opts) {
327
1333
  bar.appendChild(s);
328
1334
  }
329
1335
  const legend = document.createElement("div");
330
- legend.className = "chart-legend";
1336
+ legend.className = "icen-chart-legend";
331
1337
  for (const seg of opts.segments) {
332
1338
  legend.appendChild(legendItem(seg.label, fmt(opts, seg.value), seg.tone));
333
1339
  }
@@ -347,20 +1353,22 @@ function renderDonut(el, opts) {
347
1353
  const radius = 42;
348
1354
  const circumference = 2 * Math.PI * radius;
349
1355
  const wrap = document.createElement("div");
350
- wrap.className = "chart-donut";
351
- const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
1356
+ wrap.className = "icen-chart-donut";
1357
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.donut")) });
352
1358
  svg.style.transform = "rotate(-90deg)";
353
1359
  svg.appendChild(svgEl("circle", {
354
1360
  cx: "60",
355
1361
  cy: "60",
356
1362
  r: String(radius),
357
1363
  fill: "none",
358
- stroke: "var(--token-line-soft)",
1364
+ stroke: "var(--icen-token-line-soft)",
359
1365
  "stroke-width": "14"
360
1366
  }));
361
1367
  let offset = 0;
1368
+ const gap = opts.segments.length > 1 ? 2.5 : 0;
362
1369
  opts.segments.forEach((seg, segIndex) => {
363
- const dash = seg.value / total * circumference;
1370
+ const arcLength = Math.max(0, seg.value / total * circumference);
1371
+ const dash = arcLength - Math.min(gap, arcLength * 0.1);
364
1372
  const arc = svgEl("circle", {
365
1373
  cx: "60",
366
1374
  cy: "60",
@@ -374,10 +1382,10 @@ function renderDonut(el, opts) {
374
1382
  });
375
1383
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
376
1384
  svg.appendChild(arc);
377
- offset += dash;
1385
+ offset += arcLength;
378
1386
  });
379
1387
  const legend = document.createElement("div");
380
- legend.className = "chart-legend";
1388
+ legend.className = "icen-chart-legend";
381
1389
  for (const seg of opts.segments) {
382
1390
  legend.appendChild(legendItem(seg.label, `${Math.round(seg.value / total * 100)}%`, seg.tone));
383
1391
  }
@@ -399,23 +1407,24 @@ function renderLine(el, opts) {
399
1407
  return;
400
1408
  }
401
1409
  const labelsUsed = labels.slice(0, n);
402
- const width = 360;
1410
+ const width = fluidWidth(body);
403
1411
  const height = 150;
404
1412
  const pad = 14;
405
1413
  let max = 1;
406
1414
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
407
1415
  const wrap = document.createElement("div");
408
- wrap.className = "chart-line";
409
- const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
1416
+ wrap.className = "icen-chart-line";
1417
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
410
1418
  const defs = svgEl("defs", {});
411
1419
  for (let i = 0; i < 4; i++) {
412
- const y = pad + i * (height - pad * 2) / 3;
1420
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
413
1421
  svg.appendChild(svgEl("line", {
1422
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
414
1423
  x1: String(pad),
415
1424
  x2: String(width - pad),
416
1425
  y1: String(y),
417
1426
  y2: String(y),
418
- stroke: "var(--token-line-soft)",
1427
+ stroke: "var(--icen-token-line-soft)",
419
1428
  "stroke-width": "1"
420
1429
  }));
421
1430
  }
@@ -456,7 +1465,7 @@ function renderLine(el, opts) {
456
1465
  "stroke-linejoin": "round"
457
1466
  });
458
1467
  const lineTitle = svgEl("title", {});
459
- lineTitle.textContent = s.name || "\u6570\u503C";
1468
+ lineTitle.textContent = s.name || t("charts.value");
460
1469
  linePath.appendChild(lineTitle);
461
1470
  setMarkData(linePath, { seriesIndex: si, seriesName: s.name, label: s.name, value: values[values.length - 1] ?? 0 });
462
1471
  svg.appendChild(linePath);
@@ -465,7 +1474,7 @@ function renderLine(el, opts) {
465
1474
  cx: p.x.toFixed(1),
466
1475
  cy: p.y.toFixed(1),
467
1476
  r: "3",
468
- fill: "var(--token-card)",
1477
+ fill: "var(--icen-token-card)",
469
1478
  stroke: tone,
470
1479
  "stroke-width": "2"
471
1480
  });
@@ -485,17 +1494,18 @@ function renderLine(el, opts) {
485
1494
  cy: p.y.toFixed(1),
486
1495
  r: "8",
487
1496
  fill: "transparent",
488
- "data-chart-hit": "1"
1497
+ "data-icen-chart-hit": "1"
489
1498
  });
490
1499
  copyMarkData(hit, dot);
491
1500
  svg.appendChild(hit);
492
1501
  }
493
1502
  });
494
1503
  if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
495
- wrap.append(svg, labelsRow(sampleLabels(labelsUsed)));
1504
+ wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
496
1505
  body.appendChild(wrap);
497
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1506
+ 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));
498
1507
  });
1508
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
499
1509
  attachChartInteraction(el, "line");
500
1510
  return el;
501
1511
  }
@@ -509,14 +1519,16 @@ function renderArea(el, opts) {
509
1519
  }
510
1520
  const labels = opts.labels.slice(0, n);
511
1521
  const values = opts.values.slice(0, n);
512
- const width = 360;
1522
+ const width = fluidWidth(body);
513
1523
  const height = 150;
514
1524
  const pad = 14;
515
1525
  const max = maxOf(values);
516
1526
  const tone = toneVar(opts.tone);
517
1527
  const points = values.map((value, i) => ({
1528
+ i,
518
1529
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
519
- y: height - pad - value / max * (height - pad * 2),
1530
+ /* 负值钳到基线(与折线图同口径):容器 overflow:visible,反向射出会压住下方内容 */
1531
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
520
1532
  value,
521
1533
  label: labels[i] ?? ""
522
1534
  }));
@@ -526,8 +1538,8 @@ function renderArea(el, opts) {
526
1538
  const area = `${line} L${last.x.toFixed(1)},${height - pad} L${first.x.toFixed(1)},${height - pad} Z`;
527
1539
  const gradientId = `icen-chart-area-${++lineGradientSeq}`;
528
1540
  const wrap = document.createElement("div");
529
- wrap.className = "chart-area";
530
- const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
1541
+ wrap.className = "icen-chart-area";
1542
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.area")) });
531
1543
  const defs = svgEl("defs", {});
532
1544
  const gradient = svgEl("linearGradient", { id: gradientId, x1: "0", x2: "0", y1: "0", y2: "1" });
533
1545
  gradient.appendChild(svgEl("stop", { offset: "0%", "stop-color": tone, "stop-opacity": "0.5" }));
@@ -535,13 +1547,14 @@ function renderArea(el, opts) {
535
1547
  defs.appendChild(gradient);
536
1548
  svg.appendChild(defs);
537
1549
  for (let i = 0; i < 4; i++) {
538
- const y = pad + i * (height - pad * 2) / 3;
1550
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
539
1551
  svg.appendChild(svgEl("line", {
1552
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
540
1553
  x1: String(pad),
541
1554
  x2: String(width - pad),
542
1555
  y1: String(y),
543
1556
  y2: String(y),
544
- stroke: "var(--token-line-soft)",
1557
+ stroke: "var(--icen-token-line-soft)",
545
1558
  "stroke-width": "1"
546
1559
  }));
547
1560
  }
@@ -557,18 +1570,31 @@ function renderArea(el, opts) {
557
1570
  for (const p of points) {
558
1571
  const title = svgEl("title", {});
559
1572
  title.textContent = `${p.label}: ${fmt(opts, p.value)}`;
560
- const inv = svgEl("circle", {
1573
+ const dot = svgEl("circle", {
561
1574
  cx: p.x.toFixed(1),
562
1575
  cy: p.y.toFixed(1),
563
- r: "2",
564
- fill: "transparent"
1576
+ r: "2.6",
1577
+ fill: "var(--icen-token-card)",
1578
+ stroke: tone,
1579
+ "stroke-width": "1.6"
565
1580
  });
566
- inv.appendChild(title);
567
- svg.appendChild(inv);
1581
+ dot.appendChild(title);
1582
+ setMarkData(dot, { index: p.i, label: p.label, value: p.value });
1583
+ svg.appendChild(dot);
1584
+ const hit = svgEl("circle", {
1585
+ cx: p.x.toFixed(1),
1586
+ cy: p.y.toFixed(1),
1587
+ r: "9",
1588
+ fill: "transparent",
1589
+ "data-icen-chart-hit": "1"
1590
+ });
1591
+ copyMarkData(hit, dot);
1592
+ svg.appendChild(hit);
568
1593
  }
569
- wrap.append(svg, labelsRow(sampleLabels(labels)));
1594
+ wrap.append(svg, pointLabelsRow(labels, width, pad));
570
1595
  body.appendChild(wrap);
571
1596
  });
1597
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderArea(el, opts));
572
1598
  attachChartInteraction(el, "area");
573
1599
  return el;
574
1600
  }
@@ -600,8 +1626,8 @@ function renderRadar(el, opts) {
600
1626
  y: cy + r * Math.sin(angleOf(i))
601
1627
  });
602
1628
  const wrap = document.createElement("div");
603
- wrap.className = "chart-radar";
604
- const svg = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img" });
1629
+ wrap.className = "icen-chart-radar";
1630
+ const svg = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.radar")) });
605
1631
  for (let lv = 1; lv <= levels; lv++) {
606
1632
  const r = radius * lv / levels;
607
1633
  const pts = Array.from({ length: n }, (_, i) => {
@@ -611,7 +1637,7 @@ function renderRadar(el, opts) {
611
1637
  svg.appendChild(svgEl("polygon", {
612
1638
  points: pts,
613
1639
  fill: "none",
614
- stroke: "var(--token-line-soft)",
1640
+ stroke: "var(--icen-token-line-soft)",
615
1641
  "stroke-width": "1",
616
1642
  "stroke-dasharray": lv === levels ? "0" : "3 2"
617
1643
  }));
@@ -623,7 +1649,7 @@ function renderRadar(el, opts) {
623
1649
  y1: String(cy),
624
1650
  x2: edge.x.toFixed(1),
625
1651
  y2: edge.y.toFixed(1),
626
- stroke: "var(--token-line-soft)",
1652
+ stroke: "var(--icen-token-line-soft)",
627
1653
  "stroke-width": "1"
628
1654
  }));
629
1655
  const labelP = pointAt(i, radius + 14);
@@ -633,14 +1659,14 @@ function renderRadar(el, opts) {
633
1659
  "text-anchor": "middle",
634
1660
  "dominant-baseline": "middle",
635
1661
  "font-size": "9",
636
- fill: "var(--token-text-muted)"
1662
+ fill: "var(--icen-token-text-muted)"
637
1663
  });
638
1664
  txt.textContent = axes[i] ?? "";
639
1665
  svg.appendChild(txt);
640
1666
  }
641
1667
  const legendItems = [];
642
1668
  opts.series.forEach((s, si) => {
643
- const tone = toneVar(s.tone);
1669
+ const tone = toneOf(s.tone, si) ?? toneVar(s.tone);
644
1670
  const pts = Array.from({ length: n }, (_, i) => {
645
1671
  const v = Math.max(0, Math.min(maxVal, s.values[i] ?? 0));
646
1672
  const p = pointAt(i, v / maxVal * radius);
@@ -666,18 +1692,19 @@ function renderRadar(el, opts) {
666
1692
  cx: p.x.toFixed(1),
667
1693
  cy: p.y.toFixed(1),
668
1694
  r: "2.5",
669
- fill: "var(--token-card)",
1695
+ fill: "var(--icen-token-card)",
670
1696
  stroke: tone,
671
1697
  "stroke-width": "1.5"
672
1698
  });
673
1699
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
674
1700
  svg.appendChild(dot);
675
1701
  }
676
- legendItems.push({ key: s.name || `\u7CFB\u5217${si + 1}`, label: s.name || `\u7CFB\u5217${si + 1}`, tone: s.tone, si });
1702
+ 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 });
677
1703
  });
678
- const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
679
- wrap.append(svg, ...legend ? [legend] : []);
1704
+ wrap.appendChild(svg);
680
1705
  body.appendChild(wrap);
1706
+ const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
1707
+ if (legend) wrap.appendChild(legend);
681
1708
  });
682
1709
  attachChartInteraction(el, "radar");
683
1710
  return el;
@@ -694,6 +1721,11 @@ function niceCeil(v) {
694
1721
  else nice = 10;
695
1722
  return nice * base;
696
1723
  }
1724
+ function tickPrecision(min, max, steps) {
1725
+ const span = Math.abs(max - min);
1726
+ if (!Number.isFinite(span) || span <= 0) return 0;
1727
+ return Math.max(0, Math.ceil(-Math.log10(span / steps)));
1728
+ }
697
1729
  function isoDate(d) {
698
1730
  const m = String(d.getMonth() + 1).padStart(2, "0");
699
1731
  const day = String(d.getDate()).padStart(2, "0");
@@ -710,23 +1742,23 @@ function padFirstWeek(grid, firstDate, weekStart) {
710
1742
  const pad = (first.getDay() + 7 - weekStart) % 7;
711
1743
  for (let i = 0; i < pad; i++) {
712
1744
  const blank = document.createElement("span");
713
- blank.className = "chart-heatmap-cell is-blank";
1745
+ blank.className = "icen-chart-heatmap-cell is-blank";
714
1746
  grid.appendChild(blank);
715
1747
  }
716
1748
  return pad;
717
1749
  }
718
1750
  function heatmapLegend(labels) {
719
1751
  const legend = document.createElement("div");
720
- legend.className = "chart-heatmap-legend";
1752
+ legend.className = "icen-chart-heatmap-legend";
721
1753
  const less = document.createElement("span");
722
- less.textContent = labels?.less ?? "\u5C11";
1754
+ less.textContent = labels?.less ?? t("charts.few");
723
1755
  const more = document.createElement("span");
724
- more.textContent = labels?.more ?? "\u591A";
1756
+ more.textContent = labels?.more ?? t("charts.many");
725
1757
  legend.appendChild(less);
726
1758
  for (let lv = 0; lv <= 4; lv++) {
727
1759
  const cell = document.createElement("span");
728
- cell.className = "chart-heatmap-cell";
729
- cell.dataset.level = String(lv);
1760
+ cell.className = "icen-chart-heatmap-cell";
1761
+ cell.dataset.icenLevel = String(lv);
730
1762
  legend.appendChild(cell);
731
1763
  }
732
1764
  legend.appendChild(more);
@@ -753,16 +1785,17 @@ function renderHeatmap(el, opts) {
753
1785
  if (entries.length > weeks * 7) entries = entries.slice(entries.length - weeks * 7);
754
1786
  const max = maxOf(entries.map((e) => e.value));
755
1787
  const wrap = document.createElement("div");
756
- wrap.className = "chart-heatmap";
1788
+ wrap.className = "icen-chart-heatmap";
757
1789
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
758
1790
  const grid = document.createElement("div");
759
- grid.className = "chart-heatmap-grid";
1791
+ grid.className = "icen-chart-heatmap-grid";
760
1792
  grid.setAttribute("role", "img");
1793
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
761
1794
  padFirstWeek(grid, entries[0].date, opts.weekStart === 0 ? 0 : 1);
762
1795
  for (const [i, entry] of entries.entries()) {
763
1796
  const cell = document.createElement("span");
764
- cell.className = "chart-heatmap-cell";
765
- cell.dataset.level = String(levelOf(entry.value, max));
1797
+ cell.className = "icen-chart-heatmap-cell";
1798
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
766
1799
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
767
1800
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
768
1801
  grid.appendChild(cell);
@@ -788,7 +1821,8 @@ function renderSparkline(el, opts) {
788
1821
  const tone = toneVar(opts.tone);
789
1822
  const points = values.map((value, i) => ({
790
1823
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
791
- y: height - pad - value / max * (height - pad * 2),
1824
+ /* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
1825
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
792
1826
  value
793
1827
  }));
794
1828
  const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
@@ -797,8 +1831,8 @@ function renderSparkline(el, opts) {
797
1831
  const area = `${line} L${last.x.toFixed(1)},${height - pad} L${first.x.toFixed(1)},${height - pad} Z`;
798
1832
  const gradientId = `icen-chart-line-${++lineGradientSeq}`;
799
1833
  const wrap = document.createElement("div");
800
- wrap.className = "chart-sparkline";
801
- const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
1834
+ wrap.className = "icen-chart-sparkline";
1835
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.sparkline")) });
802
1836
  const defs = svgEl("defs", {});
803
1837
  const gradient = svgEl("linearGradient", { id: gradientId, x1: "0", x2: "0", y1: "0", y2: "1" });
804
1838
  gradient.appendChild(svgEl("stop", { offset: "0%", "stop-color": tone, "stop-opacity": "0.28" }));
@@ -818,7 +1852,7 @@ function renderSparkline(el, opts) {
818
1852
  cx: last.x.toFixed(1),
819
1853
  cy: last.y.toFixed(1),
820
1854
  r: "2.4",
821
- fill: "var(--token-card)",
1855
+ fill: "var(--icen-token-card)",
822
1856
  stroke: tone,
823
1857
  "stroke-width": "1.6"
824
1858
  });
@@ -840,16 +1874,16 @@ function renderGauge(el, opts) {
840
1874
  const radius = 42;
841
1875
  const circumference = 2 * Math.PI * radius;
842
1876
  const wrap = document.createElement("div");
843
- wrap.className = "chart-gauge";
1877
+ wrap.className = "icen-chart-gauge";
844
1878
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
845
- const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
1879
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.label, t("charts.type.gauge")) });
846
1880
  svg.style.transform = "rotate(-90deg)";
847
1881
  svg.appendChild(svgEl("circle", {
848
1882
  cx: "60",
849
1883
  cy: "60",
850
1884
  r: String(radius),
851
1885
  fill: "none",
852
- stroke: "var(--token-line-soft)",
1886
+ stroke: "var(--icen-token-line-soft)",
853
1887
  "stroke-width": "10"
854
1888
  }));
855
1889
  const dash = ratio * circumference;
@@ -864,14 +1898,14 @@ function renderGauge(el, opts) {
864
1898
  "stroke-linecap": "round"
865
1899
  }));
866
1900
  const center = document.createElement("div");
867
- center.className = "chart-gauge-center";
1901
+ center.className = "icen-chart-gauge-center";
868
1902
  const val = document.createElement("span");
869
- val.className = "chart-gauge-value";
1903
+ val.className = "icen-chart-gauge-value";
870
1904
  val.textContent = opts.formatValue ? opts.formatValue(opts.value) : `${Math.round(ratio * 100)}%`;
871
1905
  center.appendChild(val);
872
1906
  if (opts.label) {
873
1907
  const lab = document.createElement("span");
874
- lab.className = "chart-gauge-label";
1908
+ lab.className = "icen-chart-gauge-label";
875
1909
  lab.textContent = opts.label;
876
1910
  center.appendChild(lab);
877
1911
  }
@@ -893,25 +1927,27 @@ function renderCalendar(el, opts) {
893
1927
  return;
894
1928
  }
895
1929
  const wrap = document.createElement("div");
896
- wrap.className = "chart-calendar";
1930
+ wrap.className = "icen-chart-calendar";
897
1931
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
898
1932
  const weekStart = opts.weekStart === 0 ? 0 : 1;
899
- const weekdayDefaults = ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"];
1933
+ const weekdayDefaults = t("charts.calendarWeekdays");
900
1934
  const weekdayLabels = opts.labels?.weekdays ?? weekdayDefaults.map((_, i) => weekdayLabelAt(weekdayDefaults, (weekStart + i) % 7));
901
- const monthLabel = (m) => opts.labels?.months?.[m] ?? `${m + 1}\u6708`;
1935
+ const monthLabel = (m) => opts.labels?.months?.[m] ?? t("charts.monthLabel", { p0: m + 1 });
902
1936
  const grid = document.createElement("div");
903
- grid.className = "chart-heatmap-grid";
1937
+ grid.className = "icen-chart-heatmap-grid";
904
1938
  grid.setAttribute("role", "img");
1939
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
905
1940
  const months = document.createElement("div");
906
- months.className = "chart-calendar-months";
1941
+ months.className = "icen-chart-calendar-months";
907
1942
  const weekdayRow = document.createElement("div");
908
- weekdayRow.className = "chart-calendar-weekdays";
1943
+ weekdayRow.className = "icen-chart-calendar-weekdays";
909
1944
  weekdayLabels.forEach((w) => {
910
1945
  const s = document.createElement("span");
911
1946
  s.textContent = w;
912
1947
  weekdayRow.appendChild(s);
913
1948
  });
914
1949
  const max = maxOf(entries.map((e) => e.value));
1950
+ entries.sort((a, b) => a.date.localeCompare(b.date));
915
1951
  const pad = padFirstWeek(grid, entries[0].date, weekStart);
916
1952
  let lastMonth = -1;
917
1953
  entries.forEach((entry, i) => {
@@ -920,14 +1956,14 @@ function renderCalendar(el, opts) {
920
1956
  if (d.getMonth() !== lastMonth) {
921
1957
  lastMonth = d.getMonth();
922
1958
  const label = document.createElement("span");
923
- label.className = "chart-calendar-month";
1959
+ label.className = "icen-chart-calendar-month";
924
1960
  label.textContent = monthLabel(d.getMonth());
925
1961
  label.style.setProperty("--col", String(col));
926
1962
  months.appendChild(label);
927
1963
  }
928
1964
  const cell = document.createElement("span");
929
- cell.className = "chart-heatmap-cell";
930
- cell.dataset.level = String(levelOf(entry.value, max));
1965
+ cell.className = "icen-chart-heatmap-cell";
1966
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
931
1967
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
932
1968
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
933
1969
  grid.appendChild(cell);
@@ -949,7 +1985,7 @@ function renderScatter(el, opts) {
949
1985
  renderEmpty(body, opts.emptyLabel);
950
1986
  return;
951
1987
  }
952
- const width = 360;
1988
+ const width = fluidWidth(body);
953
1989
  const height = 220;
954
1990
  const pad = 30;
955
1991
  let xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, sMax = 0;
@@ -964,19 +2000,20 @@ function renderScatter(el, opts) {
964
2000
  if (yMax === yMin) yMax = yMin + 1;
965
2001
  const rOf = (size) => size && sMax > 0 ? 3 + size / sMax * 7 : 4;
966
2002
  const wrap = document.createElement("div");
967
- wrap.className = "chart-scatter";
2003
+ wrap.className = "icen-chart-scatter";
968
2004
  const tone = toneVar(opts.tone);
969
- const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
2005
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.scatter")) });
970
2006
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
971
2007
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
972
2008
  for (let i = 0; i <= 3; i++) {
973
- const y = pad + i * (height - pad * 2) / 3;
2009
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
974
2010
  svg.appendChild(svgEl("line", {
2011
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
975
2012
  x1: String(pad),
976
2013
  x2: String(width - pad),
977
2014
  y1: String(y),
978
2015
  y2: String(y),
979
- stroke: "var(--token-line-soft)",
2016
+ stroke: "var(--icen-token-line-soft)",
980
2017
  "stroke-width": "1"
981
2018
  }));
982
2019
  const tv = yMin + (yMax - yMin) * (3 - i) / 3;
@@ -985,19 +2022,20 @@ function renderScatter(el, opts) {
985
2022
  y: String(y + 3),
986
2023
  "text-anchor": "end",
987
2024
  "font-size": "8",
988
- fill: "var(--token-text-faint)"
2025
+ fill: "var(--icen-token-text-faint)"
989
2026
  });
990
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2027
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
991
2028
  svg.appendChild(txt);
992
2029
  }
993
2030
  for (let i = 0; i <= 4; i++) {
994
- const x = pad + i * (width - pad * 2) / 4;
2031
+ const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
995
2032
  svg.appendChild(svgEl("line", {
2033
+ class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
996
2034
  x1: String(x),
997
2035
  x2: String(x),
998
2036
  y1: String(pad),
999
2037
  y2: String(height - pad),
1000
- stroke: "var(--token-line-soft)",
2038
+ stroke: "var(--icen-token-line-soft)",
1001
2039
  "stroke-width": "1",
1002
2040
  "stroke-dasharray": "2 3"
1003
2041
  }));
@@ -1007,20 +2045,20 @@ function renderScatter(el, opts) {
1007
2045
  y: String(height - pad + 12),
1008
2046
  "text-anchor": "middle",
1009
2047
  "font-size": "8",
1010
- fill: "var(--token-text-faint)"
2048
+ fill: "var(--icen-token-text-faint)"
1011
2049
  });
1012
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2050
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
1013
2051
  svg.appendChild(txt);
1014
2052
  }
1015
2053
  if (opts.yLabel) {
1016
- const t = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--token-text-faint)" });
1017
- t.textContent = opts.yLabel;
1018
- svg.appendChild(t);
2054
+ const t2 = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--icen-token-text-faint)" });
2055
+ t2.textContent = opts.yLabel;
2056
+ svg.appendChild(t2);
1019
2057
  }
1020
2058
  if (opts.xLabel) {
1021
- const t = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--token-text-faint)" });
1022
- t.textContent = opts.xLabel;
1023
- svg.appendChild(t);
2059
+ const t2 = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--icen-token-text-faint)" });
2060
+ t2.textContent = opts.xLabel;
2061
+ svg.appendChild(t2);
1024
2062
  }
1025
2063
  pts.forEach((p, i) => {
1026
2064
  const c = svgEl("circle", {
@@ -1042,6 +2080,7 @@ function renderScatter(el, opts) {
1042
2080
  wrap.appendChild(svg);
1043
2081
  body.appendChild(wrap);
1044
2082
  });
2083
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderScatter(el, opts));
1045
2084
  attachChartInteraction(el, "scatter");
1046
2085
  return el;
1047
2086
  }
@@ -1091,7 +2130,7 @@ function pivotData(spec) {
1091
2130
  const labels = [];
1092
2131
  const seenLabel = /* @__PURE__ */ new Set();
1093
2132
  const hasSeries = data.some((r) => r[seriesField] != null && r[seriesField] !== "");
1094
- const seriesNames = [];
2133
+ const seriesNames = hasSeries ? [] : [""];
1095
2134
  const seenSeries = /* @__PURE__ */ new Set();
1096
2135
  for (const r of data) {
1097
2136
  const l = str(r[labelField]);
@@ -1180,8 +2219,8 @@ function normalizeChartSpec(raw) {
1180
2219
  const s = src;
1181
2220
  const spec = {};
1182
2221
  if (typeof s.type === "string") {
1183
- const t = s.type.trim().toLowerCase();
1184
- spec.type = CHART_TYPE_ALIASES[t] ?? t;
2222
+ const t2 = s.type.trim().toLowerCase();
2223
+ spec.type = CHART_TYPE_ALIASES[t2] ?? t2;
1185
2224
  }
1186
2225
  for (const k of ["title", "tone", "emptyLabel"]) {
1187
2226
  if (typeof s[k] === "string") spec[k] = s[k];
@@ -1203,7 +2242,7 @@ function normalizeChartSpec(raw) {
1203
2242
  if (Array.isArray(s.series)) {
1204
2243
  const series = s.series.filter((v) => !!v && typeof v === "object").map((v, i) => {
1205
2244
  const values = Array.isArray(v.values) ? v.values.map(toNum).filter((n) => n != null) : [];
1206
- const sv = { name: String(v.name ?? `\u7CFB\u5217${i + 1}`), values };
2245
+ const sv = { name: String(v.name ?? t("charts.seriesName", { p0: i + 1 })), values };
1207
2246
  const tone = v.tone;
1208
2247
  if (typeof tone === "string" || typeof tone === "number") sv.tone = tone;
1209
2248
  return sv;
@@ -1238,6 +2277,40 @@ function normalizeChartSpec(raw) {
1238
2277
  }
1239
2278
  spec.format = format;
1240
2279
  }
2280
+ if (typeof s.downsample === "boolean") spec.downsample = s.downsample;
2281
+ else {
2282
+ const n = toNum(s.downsample);
2283
+ if (n != null) spec.downsample = n;
2284
+ }
2285
+ if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2286
+ if (typeof s.loading === "boolean") spec.loading = s.loading;
2287
+ if (Array.isArray(s.marks)) {
2288
+ const marks = [];
2289
+ for (const raw2 of s.marks) {
2290
+ if (!raw2 || typeof raw2 !== "object" || Array.isArray(raw2)) continue;
2291
+ const m = raw2;
2292
+ if (m.type === "line") {
2293
+ if (m.axis !== "x" && m.axis !== "y") continue;
2294
+ if (typeof m.value !== "number" && typeof m.value !== "string") continue;
2295
+ const mark = { type: "line", axis: m.axis, value: m.value };
2296
+ if (typeof m.label === "string" && m.label !== "") mark.label = m.label;
2297
+ if (m.tone === "success" || m.tone === "warning" || m.tone === "error" || m.tone === "info") {
2298
+ mark.tone = m.tone;
2299
+ }
2300
+ marks.push(mark);
2301
+ } else if (m.type === "point") {
2302
+ if (typeof m.label !== "string" || m.label === "") continue;
2303
+ const mark = { type: "point", label: m.label };
2304
+ const si = toNum(m.seriesIndex);
2305
+ if (si != null && si >= 0) mark.seriesIndex = Math.floor(si);
2306
+ const v = toNum(m.value);
2307
+ if (v != null) mark.value = v;
2308
+ if (typeof m.text === "string") mark.text = m.text;
2309
+ marks.push(mark);
2310
+ }
2311
+ }
2312
+ if (marks.length > 0) spec.marks = marks;
2313
+ }
1241
2314
  const isDateRecords = spec.data?.length && spec.data[0] && "date" in spec.data[0];
1242
2315
  if (spec.data && spec.data.length > 0 && !isDateRecords && !spec.series && !spec.points && !spec.values && !spec.segments) {
1243
2316
  Object.assign(spec, pivotData(spec));
@@ -1277,6 +2350,392 @@ function inferChartType(spec) {
1277
2350
  if (typeof spec.max === "number" && spec.values && spec.values.length === 1) return "gauge";
1278
2351
  return "vbar";
1279
2352
  }
2353
+ var DOWNSAMPLE_DEFAULT_THRESHOLD = 1e3;
2354
+ var CHART_ZOOM_DRAG_MIN_PX = 5;
2355
+ var CHART_LINE_W = 360;
2356
+ var CHART_LINE_H = 150;
2357
+ var CHART_LINE_PAD = 14;
2358
+ function isDownsampleableType(type) {
2359
+ return type === "line" || type === "area" || type === "scatter";
2360
+ }
2361
+ function isZoomableType(type) {
2362
+ return type === "line" || type === "area" || type === "vbar";
2363
+ }
2364
+ function isStreamableType(type) {
2365
+ return type === "line" || type === "area" || type === "vbar";
2366
+ }
2367
+ function downsampleView(view, type) {
2368
+ const raw = view.downsample;
2369
+ if (raw == null || raw === false) return { view, note: null };
2370
+ const threshold = raw === true ? DOWNSAMPLE_DEFAULT_THRESHOLD : Math.floor(raw);
2371
+ if (!Number.isFinite(threshold)) return { view, note: null };
2372
+ if (type === "scatter") {
2373
+ const pts = view.points ?? [];
2374
+ if (pts.length === 0) return { view, note: null };
2375
+ const sampled2 = lttb(pts, threshold, (p) => p.x, (p) => p.y);
2376
+ if (sampled2.length === pts.length) return { view, note: null };
2377
+ return { view: { ...view, points: sampled2 }, note: t("charts.sampled", { p0: pts.length, p1: sampled2.length }) };
2378
+ }
2379
+ const labels = view.labels ?? [];
2380
+ if (labels.length === 0) return { view, note: null };
2381
+ const guide = view.series && view.series.length > 0 ? view.series[0]?.values ?? [] : view.values ?? [];
2382
+ const count = Math.min(labels.length, guide.length);
2383
+ if (count === 0) return { view, note: null };
2384
+ const indexed = guide.slice(0, count).map((v, i) => ({ i, v }));
2385
+ const sampled = lttb(indexed, threshold, (p) => p.i, (p) => p.v);
2386
+ if (sampled.length >= count) return { view, note: null };
2387
+ const idx = sampled.map((p) => p.i);
2388
+ return {
2389
+ view: {
2390
+ ...view,
2391
+ labels: idx.map((i) => labels[i] ?? ""),
2392
+ values: view.values ? idx.map((i) => view.values?.[i] ?? 0) : void 0,
2393
+ series: view.series?.map((s) => ({ ...s, values: idx.map((i) => s.values[i] ?? 0) }))
2394
+ },
2395
+ note: t("charts.sampled", { p0: count, p1: idx.length })
2396
+ };
2397
+ }
2398
+ function renderChartSkeleton(body) {
2399
+ const box = document.createElement("div");
2400
+ box.className = "icen-chart-skeleton";
2401
+ box.setAttribute("role", "status");
2402
+ box.setAttribute("aria-busy", "true");
2403
+ box.setAttribute("aria-label", t("charts.loading"));
2404
+ const widths = [100, 84, 92, 68, 76, 52];
2405
+ for (const w of widths) {
2406
+ const bar = document.createElement("div");
2407
+ bar.className = "icen-chart-skeleton-bar";
2408
+ bar.style.width = `${w}%`;
2409
+ box.appendChild(bar);
2410
+ }
2411
+ body.appendChild(box);
2412
+ }
2413
+ var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2414
+ var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
2415
+ function markToneVar(tone) {
2416
+ switch (tone) {
2417
+ case "success":
2418
+ return "var(--icen-token-success)";
2419
+ case "warning":
2420
+ return "var(--icen-token-warning)";
2421
+ case "error":
2422
+ return "var(--icen-token-error)";
2423
+ case "info":
2424
+ return "var(--icen-token-info)";
2425
+ default:
2426
+ return "var(--icen-token-text-faint)";
2427
+ }
2428
+ }
2429
+ function markWarnOnce(warned, mark, reason) {
2430
+ const key = JSON.stringify(mark);
2431
+ if (warned.has(key)) return;
2432
+ warned.add(key);
2433
+ console.warn(`[icen:chart] \u65E0\u6548\u6807\u8BB0\u5DF2\u8DF3\u8FC7\uFF08${reason}\uFF09`, mark);
2434
+ }
2435
+ function paintChartMarks(root, view, spec, formatValue, warned) {
2436
+ const marks = spec.marks;
2437
+ if (!marks || marks.length === 0) return;
2438
+ const type = spec.type;
2439
+ if (type === "line" || type === "area") paintSvgChartMarks(root, view, marks, formatValue, warned);
2440
+ else if (type === "vbar") paintVBarChartMarks(root, view, spec, marks, formatValue, warned);
2441
+ }
2442
+ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2443
+ const svg = root.querySelector(".icen-chart-line svg");
2444
+ if (!svg) return;
2445
+ const labels = view.labels ?? [];
2446
+ const n = labels.length;
2447
+ if (n === 0) return;
2448
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2449
+ let max = 1;
2450
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2451
+ const dims = svgDimsOf(svg);
2452
+ const W = dims.w;
2453
+ const H = dims.h;
2454
+ const PAD = CHART_LINE_PAD;
2455
+ const xAt = (i) => n <= 1 ? W / 2 : PAD + i / (n - 1) * (W - PAD * 2);
2456
+ const yAt = (v) => H - PAD - Math.max(0, v) / max * (H - PAD * 2);
2457
+ for (const mark of marks) {
2458
+ if (mark.type === "line") {
2459
+ const color = markToneVar(mark.tone);
2460
+ if (mark.axis === "y") {
2461
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2462
+ if (!Number.isFinite(v)) {
2463
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2464
+ continue;
2465
+ }
2466
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2467
+ svg.appendChild(svgEl("line", {
2468
+ class: "icen-chart-mark-line",
2469
+ x1: String(PAD),
2470
+ x2: String(W - PAD),
2471
+ y1: y.toFixed(1),
2472
+ y2: y.toFixed(1),
2473
+ stroke: color,
2474
+ "stroke-width": "1",
2475
+ "stroke-dasharray": "4 3"
2476
+ }));
2477
+ const label = svgEl("text", {
2478
+ class: "icen-chart-mark-label",
2479
+ x: String(W - PAD),
2480
+ y: String(clampNum(y - 4, 8, CHART_LINE_H - 4)),
2481
+ "text-anchor": "end",
2482
+ "font-size": "8",
2483
+ fill: color
2484
+ });
2485
+ label.textContent = mark.label ?? formatValue(v);
2486
+ svg.appendChild(label);
2487
+ } else {
2488
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2489
+ if (idx < 0 || idx >= n) {
2490
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2491
+ continue;
2492
+ }
2493
+ const x = xAt(idx);
2494
+ svg.appendChild(svgEl("line", {
2495
+ class: "icen-chart-mark-line",
2496
+ x1: x.toFixed(1),
2497
+ x2: x.toFixed(1),
2498
+ y1: String(PAD),
2499
+ y2: String(H - PAD),
2500
+ stroke: color,
2501
+ "stroke-width": "1",
2502
+ "stroke-dasharray": "4 3"
2503
+ }));
2504
+ const label = svgEl("text", {
2505
+ class: "icen-chart-mark-label",
2506
+ x: String(clampNum(x, 10, W - 10)),
2507
+ y: String(PAD + 8),
2508
+ "text-anchor": "middle",
2509
+ "font-size": "8",
2510
+ fill: color
2511
+ });
2512
+ label.textContent = mark.label ?? labels[idx] ?? "";
2513
+ svg.appendChild(label);
2514
+ }
2515
+ } else {
2516
+ const idx = labels.indexOf(mark.label);
2517
+ if (idx < 0 || idx >= n) {
2518
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2519
+ continue;
2520
+ }
2521
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2522
+ const s = seriesList[si];
2523
+ if (!s) {
2524
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2525
+ continue;
2526
+ }
2527
+ const v = mark.value ?? s.values[idx] ?? NaN;
2528
+ if (!Number.isFinite(v)) {
2529
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2530
+ continue;
2531
+ }
2532
+ const x = xAt(idx);
2533
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2534
+ const g = svgEl("g", { class: "icen-chart-mark-point" });
2535
+ g.appendChild(svgEl("circle", {
2536
+ cx: x.toFixed(1),
2537
+ cy: y.toFixed(1),
2538
+ r: "6",
2539
+ fill: "none",
2540
+ stroke: CHART_MARK_ACCENT,
2541
+ "stroke-width": "1.5"
2542
+ }));
2543
+ g.appendChild(svgEl("circle", { cx: x.toFixed(1), cy: y.toFixed(1), r: "2", fill: CHART_MARK_ACCENT }));
2544
+ const label = svgEl("text", {
2545
+ class: "icen-chart-mark-label",
2546
+ x: String(clampNum(x, 12, W - 12)),
2547
+ y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2548
+ "text-anchor": "middle",
2549
+ "font-size": "8",
2550
+ fill: CHART_MARK_ACCENT_TEXT
2551
+ });
2552
+ label.textContent = mark.text ?? mark.label;
2553
+ g.appendChild(label);
2554
+ svg.appendChild(g);
2555
+ }
2556
+ }
2557
+ }
2558
+ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2559
+ const wrap = root.querySelector(".icen-chart-vbar");
2560
+ if (!wrap) return;
2561
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2562
+ const labels = view.labels ?? [];
2563
+ const n = Math.min(labels.length, ...seriesList.map((s) => s.values.length));
2564
+ if (n === 0 || seriesList.length === 0) return;
2565
+ const multi = seriesList.length > 1;
2566
+ let max = 1;
2567
+ if (spec.stacked && multi) {
2568
+ for (let i = 0; i < n; i++) {
2569
+ let sum = 0;
2570
+ for (const s of seriesList) sum += Math.max(0, s.values[i] ?? 0);
2571
+ if (sum > max) max = sum;
2572
+ }
2573
+ } else {
2574
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2575
+ }
2576
+ const centerPct = (i) => (i + 0.5) / n * 100;
2577
+ for (const mark of marks) {
2578
+ if (mark.type === "line") {
2579
+ if (mark.axis === "y") {
2580
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2581
+ if (!Number.isFinite(v)) {
2582
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2583
+ continue;
2584
+ }
2585
+ const line = document.createElement("div");
2586
+ line.className = "icen-chart-mark-line icen-chart-mark-line--h";
2587
+ line.style.top = `${(clampNum(1 - Math.max(0, v) / max, 0.02, 0.98) * 100).toFixed(2)}%`;
2588
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2589
+ const lab = document.createElement("span");
2590
+ lab.className = "icen-chart-mark-label";
2591
+ lab.textContent = mark.label ?? formatValue(v);
2592
+ line.appendChild(lab);
2593
+ wrap.appendChild(line);
2594
+ } else {
2595
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2596
+ if (idx < 0 || idx >= n) {
2597
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2598
+ continue;
2599
+ }
2600
+ const line = document.createElement("div");
2601
+ line.className = "icen-chart-mark-line icen-chart-mark-line--v";
2602
+ line.style.left = `${centerPct(idx).toFixed(2)}%`;
2603
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2604
+ const lab = document.createElement("span");
2605
+ lab.className = "icen-chart-mark-label";
2606
+ lab.textContent = mark.label ?? labels[idx] ?? "";
2607
+ line.appendChild(lab);
2608
+ wrap.appendChild(line);
2609
+ }
2610
+ } else {
2611
+ const idx = labels.indexOf(mark.label);
2612
+ if (idx < 0 || idx >= n) {
2613
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2614
+ continue;
2615
+ }
2616
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2617
+ const s = seriesList[si];
2618
+ if (!s) {
2619
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2620
+ continue;
2621
+ }
2622
+ const v = mark.value ?? s.values[idx] ?? NaN;
2623
+ if (!Number.isFinite(v)) {
2624
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2625
+ continue;
2626
+ }
2627
+ const dot = document.createElement("div");
2628
+ dot.className = "icen-chart-mark-point";
2629
+ dot.style.left = `${centerPct(idx).toFixed(2)}%`;
2630
+ dot.style.bottom = `${(clampNum(Math.max(0, v) / max, 0, 1) * 100).toFixed(2)}%`;
2631
+ const lab = document.createElement("span");
2632
+ lab.className = "icen-chart-mark-label";
2633
+ lab.textContent = mark.text ?? mark.label;
2634
+ dot.appendChild(lab);
2635
+ wrap.appendChild(dot);
2636
+ }
2637
+ }
2638
+ }
2639
+ function chartAriaLabel(title, typeName) {
2640
+ return title ? `${typeName}\uFF1A${title}` : typeName;
2641
+ }
2642
+ function svgDimsOf(svg) {
2643
+ const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2644
+ const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
2645
+ const h = Number.isFinite(vb[3]) && (vb[3] ?? 0) > 0 ? vb[3] : CHART_LINE_H;
2646
+ return { w, h };
2647
+ }
2648
+ var fluidObservers = /* @__PURE__ */ new WeakMap();
2649
+ function fluidWidth(host) {
2650
+ const w = Math.round(host.getBoundingClientRect().width);
2651
+ return w > 0 ? Math.max(29, w) : 360;
2652
+ }
2653
+ function observeFluidWidth(el, rerender) {
2654
+ if (typeof ResizeObserver === "undefined") return;
2655
+ fluidObservers.get(el)?.disconnect();
2656
+ let last = Math.round(el.getBoundingClientRect().width);
2657
+ const ro = new ResizeObserver(() => {
2658
+ if (!el.isConnected) {
2659
+ ro.disconnect();
2660
+ fluidObservers.delete(el);
2661
+ return;
2662
+ }
2663
+ const w = Math.round(el.getBoundingClientRect().width);
2664
+ if (Math.abs(w - last) < 2) return;
2665
+ last = w;
2666
+ rerender();
2667
+ });
2668
+ ro.observe(el);
2669
+ fluidObservers.set(el, ro);
2670
+ }
2671
+ function releaseFluidWidth(el) {
2672
+ fluidObservers.get(el)?.disconnect();
2673
+ fluidObservers.delete(el);
2674
+ }
2675
+ function createChartToDataURL(root) {
2676
+ const cache = /* @__PURE__ */ new Map();
2677
+ return (opts) => {
2678
+ if (typeof document === "undefined") return void 0;
2679
+ const scale = clampNum(toNum(opts?.scale) ?? 2, 0.5, 4);
2680
+ const svgs = Array.from(root.querySelectorAll("svg"));
2681
+ if (svgs.length === 0) return void 0;
2682
+ const parts = [];
2683
+ for (const svg of svgs) {
2684
+ const { w, h } = svgDimsOf(svg);
2685
+ const clone = svg.cloneNode(true);
2686
+ clone.setAttribute("xmlns", SVG_NS);
2687
+ clone.setAttribute("width", String(w));
2688
+ clone.setAttribute("height", String(h));
2689
+ let str;
2690
+ try {
2691
+ str = new XMLSerializer().serializeToString(clone);
2692
+ } catch {
2693
+ return void 0;
2694
+ }
2695
+ parts.push({ src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(str)}`, w, h });
2696
+ }
2697
+ const key = `${scale}|${parts.map((p) => p.src).join("")}`;
2698
+ const hit = cache.get(key);
2699
+ if (hit) return hit;
2700
+ const canvas = document.createElement("canvas");
2701
+ let ctx = null;
2702
+ try {
2703
+ ctx = canvas.getContext("2d");
2704
+ } catch {
2705
+ return void 0;
2706
+ }
2707
+ if (!ctx) return void 0;
2708
+ const context = ctx;
2709
+ const totalW = Math.max(...parts.map((p) => p.w));
2710
+ const totalH = parts.reduce((sum, p) => sum + p.h, 0);
2711
+ canvas.width = Math.max(1, Math.round(totalW * scale));
2712
+ canvas.height = Math.max(1, Math.round(totalH * scale));
2713
+ let loaded = 0;
2714
+ let failed = false;
2715
+ let offsetY = 0;
2716
+ for (const part of parts) {
2717
+ const dy = offsetY;
2718
+ offsetY += part.h;
2719
+ const img = new Image();
2720
+ img.onload = () => {
2721
+ if (failed) return;
2722
+ context.drawImage(img, 0, dy * scale, part.w * scale, part.h * scale);
2723
+ loaded += 1;
2724
+ if (loaded === parts.length) {
2725
+ try {
2726
+ cache.set(key, canvas.toDataURL("image/png"));
2727
+ } catch {
2728
+ }
2729
+ }
2730
+ };
2731
+ img.onerror = () => {
2732
+ failed = true;
2733
+ };
2734
+ img.src = part.src;
2735
+ }
2736
+ return cache.get(key);
2737
+ };
2738
+ }
1280
2739
  function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1281
2740
  const read = (name) => mark.getAttribute(name) ?? void 0;
1282
2741
  const numOr = (v) => v == null ? void 0 : Number(v);
@@ -1284,11 +2743,11 @@ function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1284
2743
  type,
1285
2744
  phase,
1286
2745
  chart,
1287
- index: numOr(read("data-chart-index")),
1288
- seriesIndex: numOr(read("data-chart-series")),
1289
- seriesName: read("data-chart-series-name"),
1290
- label: read("data-chart-label"),
1291
- value: numOr(read("data-chart-value")),
2746
+ index: numOr(read("data-icen-chart-index")),
2747
+ seriesIndex: numOr(read("data-icen-chart-series")),
2748
+ seriesName: read("data-icen-chart-series-name"),
2749
+ label: read("data-icen-chart-label"),
2750
+ value: numOr(read("data-icen-chart-value")),
1292
2751
  target: mark,
1293
2752
  pointerX: pointer?.x,
1294
2753
  pointerY: pointer?.y
@@ -1299,7 +2758,7 @@ var tooltipEl = null;
1299
2758
  function chartTooltip() {
1300
2759
  if (!tooltipEl) {
1301
2760
  tooltipEl = document.createElement("div");
1302
- tooltipEl.className = "chart-tooltip";
2761
+ tooltipEl.className = "icen-chart-tooltip";
1303
2762
  tooltipEl.setAttribute("role", "tooltip");
1304
2763
  tooltipEl.hidden = true;
1305
2764
  document.body.appendChild(tooltipEl);
@@ -1308,14 +2767,14 @@ function chartTooltip() {
1308
2767
  }
1309
2768
  function applyTooltipSizing(host) {
1310
2769
  const tip = chartTooltip();
1311
- const raw = host?.closest(".chart, [data-chart-root]")?.getAttribute("data-panel-max") ?? null;
2770
+ const raw = host?.closest(".icen-chart, [data-icen-chart-root]")?.getAttribute("data-icen-panel-max") ?? null;
1312
2771
  const n = raw != null ? Number(raw) : NaN;
1313
2772
  tip.style.maxWidth = Number.isFinite(n) && n > 0 ? `${n}px` : "";
1314
2773
  }
1315
2774
  function tooltipText(mark) {
1316
- const label = mark.getAttribute("data-chart-label") ?? "";
1317
- const series = mark.getAttribute("data-chart-series-name");
1318
- const value = mark.getAttribute("data-chart-value");
2775
+ const label = mark.getAttribute("data-icen-chart-label") ?? "";
2776
+ const series = mark.getAttribute("data-icen-chart-series-name");
2777
+ const value = mark.getAttribute("data-icen-chart-value");
1319
2778
  const head = series ? label ? `${series} \xB7 ${label}` : series : label;
1320
2779
  return value != null ? `${head}\uFF1A${value}` : head;
1321
2780
  }
@@ -1347,8 +2806,8 @@ function bindChartEvents(root) {
1347
2806
  const typeNow = () => chartDelegateMeta.get(root)?.type() ?? "vbar";
1348
2807
  const tipEnabled = () => chartDelegateMeta.get(root)?.tooltip() ?? true;
1349
2808
  const markOf = (e) => {
1350
- const t = e.target;
1351
- return t instanceof Element ? t.closest("[data-chart-mark]") : null;
2809
+ const t2 = e.target;
2810
+ return t2 instanceof Element ? t2.closest("[data-icen-chart-mark]") : null;
1352
2811
  };
1353
2812
  let hoverMark = null;
1354
2813
  const enterMark = (mark, x, y) => {
@@ -1445,70 +2904,283 @@ function hasLegendOf(spec) {
1445
2904
  function renderChart(el, raw) {
1446
2905
  const noop = () => void 0;
1447
2906
  if (typeof document === "undefined") {
1448
- return { el, spec: {}, update: noop, on: () => noop, destroy: noop };
2907
+ return {
2908
+ el,
2909
+ spec: {},
2910
+ update: noop,
2911
+ append: noop,
2912
+ toDataURL: () => void 0,
2913
+ on: () => noop,
2914
+ destroy: noop
2915
+ };
1449
2916
  }
1450
2917
  const root = el;
1451
- let current = normalizeChartSpec(raw);
1452
- const typeOf = () => current.type ?? "vbar";
2918
+ let current2 = normalizeChartSpec(raw);
2919
+ const typeOf = () => current2.type ?? "vbar";
1453
2920
  const legendState = { hidden: null };
2921
+ let zoomWindow = null;
2922
+ const warnedMarks = /* @__PURE__ */ new Set();
2923
+ let warnedAppend = false;
2924
+ let zoomDragCleanup = null;
2925
+ const fullLength = () => {
2926
+ if (current2.type === "scatter") return current2.points?.length ?? 0;
2927
+ if (current2.series && current2.series.length > 0) {
2928
+ return Math.max(current2.labels?.length ?? 0, ...current2.series.map((s) => s.values.length));
2929
+ }
2930
+ return Math.max(current2.labels?.length ?? 0, current2.values?.length ?? 0);
2931
+ };
2932
+ const viewOf = () => {
2933
+ if (!zoomWindow) return current2;
2934
+ const { from, to } = zoomWindow;
2935
+ return {
2936
+ ...current2,
2937
+ labels: current2.labels?.slice(from, to + 1),
2938
+ values: current2.values?.slice(from, to + 1),
2939
+ series: current2.series?.map((s) => ({ ...s, values: s.values.slice(from, to + 1) })),
2940
+ points: current2.points?.slice(from, to + 1)
2941
+ };
2942
+ };
2943
+ const applyZoomSelection = (x0, x1) => {
2944
+ const len = fullLength();
2945
+ if (len < 2) return;
2946
+ const base = zoomWindow?.from ?? 0;
2947
+ const viewLen = zoomWindow ? zoomWindow.to - zoomWindow.from + 1 : len;
2948
+ const lo = Math.min(x0, x1);
2949
+ const hi = Math.max(x0, x1);
2950
+ let i0;
2951
+ let i1;
2952
+ const vbar = root.querySelector(".icen-chart-vbar");
2953
+ if (vbar) {
2954
+ const rect = vbar.getBoundingClientRect();
2955
+ const rel0 = rect.width > 0 ? Math.floor((lo - rect.left) / rect.width * viewLen) : 0;
2956
+ const rel1 = rect.width > 0 ? Math.max(rel0, Math.floor((hi - rect.left) / rect.width * viewLen)) : viewLen - 1;
2957
+ i0 = clampNum(rel0 + base, 0, len - 1);
2958
+ i1 = clampNum(rel1 + base, 0, len - 1);
2959
+ } else {
2960
+ const svg = root.querySelector(".icen-chart-line svg");
2961
+ if (!svg) return;
2962
+ const dims = svgDimsOf(svg);
2963
+ const p0 = svgClientPoint(svg, lo, 0, dims.w, dims.h);
2964
+ const p1 = svgClientPoint(svg, hi, 0, dims.w, dims.h);
2965
+ const rel0 = Math.round((p0.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
2966
+ const rel1 = Math.round((p1.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
2967
+ i0 = clampNum(rel0 + base, 0, len - 1);
2968
+ i1 = clampNum(rel1 + base, 0, len - 1);
2969
+ }
2970
+ if (i0 > i1) [i0, i1] = [i1, i0];
2971
+ if (i0 <= 0 && i1 >= len - 1) zoomWindow = null;
2972
+ else zoomWindow = { from: i0, to: Math.max(i1, i0) };
2973
+ render();
2974
+ emitIcen(root, "icen:chart-zoom", { chart: String(current2.type ?? ""), from: i0, to: Math.max(i1, i0) });
2975
+ };
2976
+ const bindZoomGesture = () => {
2977
+ if (current2.zoom !== "x" && current2.zoom !== "brush") return;
2978
+ const t2 = typeOf();
2979
+ if (!isZoomableType(t2) || fullLength() < 2) return;
2980
+ const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
2981
+ if (!plot) return;
2982
+ const on = (type, fn) => {
2983
+ plot.addEventListener(type, fn);
2984
+ };
2985
+ let drag = null;
2986
+ const onMove = (e) => {
2987
+ if (!drag) return;
2988
+ drag.x1 = e.clientX;
2989
+ drag.y1 = e.clientY;
2990
+ if (!drag.active && Math.hypot(drag.x1 - drag.x0, drag.y1 - drag.y0) >= CHART_ZOOM_DRAG_MIN_PX) {
2991
+ drag.active = true;
2992
+ const rect = document.createElement("div");
2993
+ rect.className = "icen-chart-zoom-rect";
2994
+ document.body.appendChild(rect);
2995
+ drag.rect = rect;
2996
+ }
2997
+ if (drag.active && drag.rect) {
2998
+ drag.rect.style.left = `${Math.round(Math.min(drag.x0, drag.x1))}px`;
2999
+ drag.rect.style.width = `${Math.round(Math.abs(drag.x1 - drag.x0))}px`;
3000
+ if (current2.zoom === "brush") {
3001
+ drag.rect.style.top = `${Math.round(Math.min(drag.y0, drag.y1))}px`;
3002
+ drag.rect.style.height = `${Math.round(Math.abs(drag.y1 - drag.y0))}px`;
3003
+ } else {
3004
+ const pr = plot.getBoundingClientRect();
3005
+ drag.rect.style.top = `${Math.round(pr.top)}px`;
3006
+ drag.rect.style.height = `${Math.round(pr.height)}px`;
3007
+ }
3008
+ }
3009
+ };
3010
+ const onUp = () => {
3011
+ window.removeEventListener("pointermove", onMove);
3012
+ window.removeEventListener("pointerup", onUp);
3013
+ window.removeEventListener("pointercancel", onUp);
3014
+ zoomDragCleanup = null;
3015
+ if (!drag) return;
3016
+ const d = drag;
3017
+ drag = null;
3018
+ d.rect?.remove();
3019
+ if (!d.active) return;
3020
+ applyZoomSelection(d.x0, d.x1);
3021
+ };
3022
+ const onDown = (e) => {
3023
+ if (e.button !== 0) return;
3024
+ drag = { x0: e.clientX, y0: e.clientY, x1: e.clientX, y1: e.clientY, active: false, rect: null };
3025
+ window.addEventListener("pointermove", onMove);
3026
+ window.addEventListener("pointerup", onUp);
3027
+ window.addEventListener("pointercancel", onUp);
3028
+ zoomDragCleanup = onUp;
3029
+ };
3030
+ on("pointerdown", onDown);
3031
+ on("dblclick", () => {
3032
+ if (!zoomWindow) return;
3033
+ zoomWindow = null;
3034
+ render();
3035
+ });
3036
+ };
1454
3037
  const render = () => {
1455
- if (!current.type) current = { ...current, type: inferChartType(current) };
1456
- const spec = current;
3038
+ if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
3039
+ const spec = current2;
3040
+ const type = spec.type;
1457
3041
  const formatValue = chartFormatValue(spec.format);
1458
3042
  if (spec.legend !== void 0) legendState.hidden = spec.legend === false;
3043
+ const loading = spec.loading === true;
3044
+ root.classList.toggle("is-loading", loading);
3045
+ let view = viewOf();
3046
+ let note = null;
3047
+ if (!loading && isDownsampleableType(type)) {
3048
+ const r = downsampleView(view, type);
3049
+ view = r.view;
3050
+ note = r.note;
3051
+ }
3052
+ const zoomReset = zoomWindow && (spec.zoom === "x" || spec.zoom === "brush") ? () => {
3053
+ zoomWindow = null;
3054
+ render();
3055
+ } : null;
1459
3056
  withChrome(root, spec, hasLegendOf(spec), (body) => {
1460
- switch (spec.type) {
3057
+ if (loading) {
3058
+ renderChartSkeleton(body);
3059
+ return;
3060
+ }
3061
+ switch (type) {
1461
3062
  case "line":
1462
- renderLine(body, { labels: spec.labels ?? [], values: spec.values ?? [], series: spec.series, tone: spec.tone, fill: spec.fill, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3063
+ renderLine(body, { labels: view.labels ?? [], values: view.values ?? [], series: view.series, tone: view.tone, fill: view.fill, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1463
3064
  break;
1464
3065
  case "area":
1465
- renderLine(body, { labels: spec.labels ?? [], values: spec.values ?? [], series: spec.series, tone: spec.tone, fill: true, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3066
+ renderLine(body, { labels: view.labels ?? [], values: view.values ?? [], series: view.series, tone: view.tone, fill: true, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1466
3067
  break;
1467
3068
  case "vbar":
1468
- renderVBar(body, { labels: spec.labels ?? [], values: spec.values ?? [], series: spec.series, stacked: spec.stacked, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3069
+ renderVBar(body, { labels: view.labels ?? [], values: view.values ?? [], series: view.series, stacked: view.stacked, tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1469
3070
  break;
1470
3071
  case "hbar":
1471
- renderHBar(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3072
+ renderHBar(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1472
3073
  break;
1473
3074
  case "stack":
1474
- renderStack(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3075
+ renderStack(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1475
3076
  break;
1476
3077
  case "donut":
1477
- renderDonut(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3078
+ renderDonut(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1478
3079
  break;
1479
3080
  case "radar": {
1480
- const series = spec.series ? spec.series.map((s) => ({ name: s.name, values: s.values, tone: typeof s.tone === "string" ? s.tone : void 0 })) : spec.values ? [{ name: "", values: spec.values }] : [];
1481
- renderRadar(body, { axes: spec.axes ?? spec.labels ?? [], series, max: spec.max, levels: spec.levels, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3081
+ const series = view.series ? view.series.map((s) => ({ name: s.name, values: s.values, tone: typeof s.tone === "string" ? s.tone : void 0 })) : view.values ? [{ name: "", values: view.values }] : [];
3082
+ renderRadar(body, { axes: view.axes ?? view.labels ?? [], series, max: view.max, levels: view.levels, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1482
3083
  break;
1483
3084
  }
1484
3085
  case "heatmap":
1485
- renderHeatmap(body, { values: spec.values, data: spec.data, weeks: spec.weeks, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend, weekStart: spec.i18n?.weekStart, labels: spec.i18n });
3086
+ renderHeatmap(body, { values: view.values, data: view.data, weeks: view.weeks, tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend, weekStart: view.i18n?.weekStart, labels: view.i18n });
1486
3087
  break;
1487
3088
  case "calendar":
1488
- renderCalendar(body, { dates: spec.dates, values: spec.values, data: spec.data, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend, weekStart: spec.i18n?.weekStart, labels: spec.i18n });
3089
+ renderCalendar(body, { dates: view.dates, values: view.values, data: view.data, tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend, weekStart: view.i18n?.weekStart, labels: view.i18n });
1489
3090
  break;
1490
3091
  case "sparkline":
1491
- renderSparkline(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3092
+ renderSparkline(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1492
3093
  break;
1493
3094
  case "gauge":
1494
- renderGauge(body, { value: spec.values?.[0] ?? 0, max: spec.max, tone: spec.tone, label: spec.labels?.[0], formatValue });
3095
+ renderGauge(body, { value: view.values?.[0] ?? 0, max: view.max, tone: view.tone, label: view.labels?.[0], formatValue });
1495
3096
  break;
1496
3097
  case "scatter":
1497
- renderScatter(body, { points: spec.points ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3098
+ renderScatter(body, { points: view.points ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1498
3099
  break;
1499
3100
  default:
1500
- renderEmpty(body, spec.emptyLabel);
3101
+ renderEmpty(body, view.emptyLabel);
1501
3102
  }
1502
- });
3103
+ }, legendState, { note, onZoomReset: zoomReset });
3104
+ if (!loading) {
3105
+ const graphic = root.querySelector('[role="img"]');
3106
+ if (graphic && !graphic.getAttribute("aria-label")) {
3107
+ graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3108
+ } else if (!graphic) {
3109
+ const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
3110
+ if (dom) {
3111
+ dom.setAttribute("role", "img");
3112
+ dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3113
+ }
3114
+ }
3115
+ }
3116
+ if (loading) return;
3117
+ paintChartMarks(root, view, spec, formatValue, warnedMarks);
3118
+ bindZoomGesture();
1503
3119
  };
1504
- chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current.tooltip !== false });
3120
+ chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current2.tooltip !== false });
1505
3121
  const unbindEvents = bindChartEvents(root);
1506
3122
  render();
3123
+ observeFluidWidth(root, render);
1507
3124
  return {
1508
3125
  el: root,
1509
- spec: current,
3126
+ /** 归一 + 推断后的当前规格(getter:update/append 换引用后永远读到最新) */
3127
+ get spec() {
3128
+ return current2;
3129
+ },
1510
3130
  update(next) {
1511
- current = normalizeChartSpec(next);
3131
+ const prev = current2;
3132
+ current2 = normalizeChartSpec(next);
3133
+ if (zoomWindow) {
3134
+ const sameLabels = JSON.stringify(prev.labels ?? null) === JSON.stringify(current2.labels ?? null);
3135
+ const t2 = current2.type ?? inferChartType(current2);
3136
+ const zoomable = isZoomableType(t2) && (current2.zoom === "x" || current2.zoom === "brush");
3137
+ if (!sameLabels || !zoomable) zoomWindow = null;
3138
+ else {
3139
+ const len = fullLength();
3140
+ if (len < 2) zoomWindow = null;
3141
+ else {
3142
+ const from = clampNum(zoomWindow.from, 0, len - 1);
3143
+ const to = clampNum(zoomWindow.to, 0, len - 1);
3144
+ zoomWindow = from <= to ? { from, to } : null;
3145
+ }
3146
+ }
3147
+ }
3148
+ render();
3149
+ },
3150
+ append(label, values, opts) {
3151
+ const t2 = current2.type ?? inferChartType(current2);
3152
+ if (!isStreamableType(t2)) {
3153
+ if (!warnedAppend) {
3154
+ warnedAppend = true;
3155
+ console.warn(`[icen:chart] append \u4EC5\u652F\u6301 line/area/vbar\uFF08\u5F53\u524D ${String(current2.type ?? t2)}\uFF09\uFF0C\u5DF2\u5FFD\u7565`);
3156
+ }
3157
+ return;
3158
+ }
3159
+ const labels = current2.labels ?? (current2.labels = []);
3160
+ labels.push(String(label ?? ""));
3161
+ const vals = Array.isArray(values) ? values : [];
3162
+ if (current2.series && current2.series.length > 0) {
3163
+ for (const [i, s] of current2.series.entries()) s.values.push(toNum(vals[i]) ?? 0);
3164
+ } else {
3165
+ const v = current2.values ?? (current2.values = []);
3166
+ v.push(toNum(vals[0]) ?? 0);
3167
+ }
3168
+ const maxPoints = opts?.maxPoints != null ? Math.max(1, Math.floor(toNum(opts.maxPoints) ?? 0)) : 0;
3169
+ let dropped = 0;
3170
+ if (maxPoints > 0) {
3171
+ while (labels.length > maxPoints) {
3172
+ labels.shift();
3173
+ if (current2.series) for (const s of current2.series) s.values.shift();
3174
+ else current2.values?.shift();
3175
+ dropped += 1;
3176
+ }
3177
+ }
3178
+ if (zoomWindow) {
3179
+ const len = Math.max(1, labels.length);
3180
+ const size = zoomWindow.to - zoomWindow.from + 1;
3181
+ const to = clampNum(zoomWindow.to - dropped + 1, 0, len - 1);
3182
+ zoomWindow = { from: Math.max(0, to - size + 1), to };
3183
+ }
1512
3184
  render();
1513
3185
  },
1514
3186
  on(name, listener) {
@@ -1518,8 +3190,13 @@ function renderChart(el, raw) {
1518
3190
  root.addEventListener(`icen:chart-${name}`, handler);
1519
3191
  return () => root.removeEventListener(`icen:chart-${name}`, handler);
1520
3192
  },
3193
+ toDataURL: createChartToDataURL(root),
1521
3194
  destroy() {
3195
+ releaseFluidWidth(root);
3196
+ hiddenLegendKeys.delete(root);
3197
+ zoomDragCleanup?.();
1522
3198
  root.textContent = "";
3199
+ root.classList.remove("is-loading");
1523
3200
  unbindEvents();
1524
3201
  chartTooltip().hidden = true;
1525
3202
  }
@@ -1683,11 +3360,11 @@ function dispatchDatumEvent(root, type, mark, phase, pointer) {
1683
3360
  type,
1684
3361
  phase,
1685
3362
  chart: chartDelegateMeta.get(root)?.type() ?? "vbar",
1686
- index: numOr(mark.getAttribute("data-chart-index")),
1687
- seriesIndex: numOr(mark.getAttribute("data-chart-series")),
1688
- seriesName: mark.getAttribute("data-chart-series-name") ?? void 0,
1689
- label: mark.getAttribute("data-chart-label") ?? void 0,
1690
- value: numOr(mark.getAttribute("data-chart-value")),
3363
+ index: numOr(mark.getAttribute("data-icen-chart-index")),
3364
+ seriesIndex: numOr(mark.getAttribute("data-icen-chart-series")),
3365
+ seriesName: mark.getAttribute("data-icen-chart-series-name") ?? void 0,
3366
+ label: mark.getAttribute("data-icen-chart-label") ?? void 0,
3367
+ value: numOr(mark.getAttribute("data-icen-chart-value")),
1691
3368
  target: mark,
1692
3369
  pointerX: pointer?.x,
1693
3370
  pointerY: pointer?.y,
@@ -1700,8 +3377,8 @@ function bindDatumEvents(root) {
1700
3377
  if (existing) return existing;
1701
3378
  const tipEnabled = () => chartDelegateMeta.get(root)?.tooltip() ?? true;
1702
3379
  const markOf = (e) => {
1703
- const t = e.target;
1704
- return t instanceof Element ? t.closest("[data-chart-mark]") : null;
3380
+ const t2 = e.target;
3381
+ return t2 instanceof Element ? t2.closest("[data-icen-chart-mark]") : null;
1705
3382
  };
1706
3383
  let hoverMark = null;
1707
3384
  let suppressClick = false;
@@ -1915,9 +3592,9 @@ var GRAPH_LH = GRAPH_H - GRAPH_PAD * 2;
1915
3592
  var graphMarkerSeq = 0;
1916
3593
  function renderGraph(el, raw) {
1917
3594
  const noop = () => void 0;
1918
- let current = normalizeGraphSpec(raw);
3595
+ let current2 = normalizeGraphSpec(raw);
1919
3596
  if (typeof document === "undefined") {
1920
- return { el, spec: current, update: noop, on: () => noop, destroy: noop };
3597
+ return { el, spec: current2, update: noop, on: () => noop, destroy: noop };
1921
3598
  }
1922
3599
  const legendState = { hidden: null };
1923
3600
  let layout = null;
@@ -1947,23 +3624,23 @@ function renderGraph(el, raw) {
1947
3624
  };
1948
3625
  };
1949
3626
  const paint = (body) => {
1950
- directed = current.directed === true;
3627
+ directed = current2.directed === true;
1951
3628
  layout = null;
1952
3629
  svgRef = null;
1953
3630
  nodeEls = [];
1954
3631
  edgeList = [];
1955
3632
  arrowId = "";
1956
- const nodes = current.nodes;
3633
+ const nodes = current2.nodes;
1957
3634
  if (nodes.length === 0) {
1958
3635
  nodeRadii = [];
1959
- renderEmpty(body, current.emptyLabel);
3636
+ renderEmpty(body, current2.emptyLabel);
1960
3637
  return;
1961
3638
  }
1962
- const clusters = buildClusterModel(nodes.map((n) => n.cluster), current.clusterLabels);
1963
- const tone = toneVar(current.tone);
3639
+ const clusters = buildClusterModel(nodes.map((n) => n.cluster), current2.clusterLabels);
3640
+ const tone = toneVar(current2.tone);
1964
3641
  const idOf = new Map(nodes.map((n, i) => [n.id, i]));
1965
3642
  const degree = nodes.map(() => 0);
1966
- for (const e of current.edges) {
3643
+ for (const e of current2.edges) {
1967
3644
  const a = idOf.get(e.source);
1968
3645
  const b = idOf.get(e.target);
1969
3646
  if (a == null || b == null || a === b) continue;
@@ -1980,16 +3657,16 @@ function renderGraph(el, raw) {
1980
3657
  nodeRadii = weights.map((w) => 6 + (wMax > wMin ? (w - wMin) / (wMax - wMin) : 0.5) * 12);
1981
3658
  let eMin = Infinity;
1982
3659
  let eMax = -Infinity;
1983
- for (const e of current.edges) {
3660
+ for (const e of current2.edges) {
1984
3661
  if (e.weight == null) continue;
1985
3662
  if (e.weight < eMin) eMin = e.weight;
1986
3663
  if (e.weight > eMax) eMax = e.weight;
1987
3664
  }
1988
3665
  const edgeWidth = (e) => e.weight == null ? 1 : 0.6 + (eMax > eMin ? (e.weight - eMin) / (eMax - eMin) : 0.5) * 1.9;
1989
3666
  const wrap = document.createElement("div");
1990
- wrap.className = "chart-graph";
1991
- if (current.tone) wrap.style.setProperty("--chart-tone", toneVar(current.tone));
1992
- const svg = svgEl("svg", { viewBox: `0 0 ${GRAPH_W} ${GRAPH_H}`, role: "img" });
3667
+ wrap.className = "icen-chart-graph";
3668
+ if (current2.tone) wrap.style.setProperty("--chart-tone", toneVar(current2.tone));
3669
+ const svg = svgEl("svg", { viewBox: `0 0 ${GRAPH_W} ${GRAPH_H}`, role: "img", "aria-label": chartAriaLabel(current2.title, t("charts.type.graph")) });
1993
3670
  svgRef = svg;
1994
3671
  svg.addEventListener("pointerdown", onNodePointerDown);
1995
3672
  const defs = svgEl("defs", {});
@@ -2004,30 +3681,30 @@ function renderGraph(el, raw) {
2004
3681
  markerHeight: "6",
2005
3682
  orient: "auto"
2006
3683
  });
2007
- marker.appendChild(svgEl("path", { d: "M0.5,0.8 L7.5,4 L0.5,7.2 Z", fill: "var(--token-text-faint)" }));
3684
+ marker.appendChild(svgEl("path", { d: "M0.5,0.8 L7.5,4 L0.5,7.2 Z", fill: "var(--icen-token-text-faint)" }));
2008
3685
  defs.appendChild(marker);
2009
3686
  }
2010
- layout = buildLayoutState(nodes, current.edges, GRAPH_LW, GRAPH_LH);
3687
+ layout = buildLayoutState(nodes, current2.edges, GRAPH_LW, GRAPH_LH);
2011
3688
  initRingLayout(layout, 0);
2012
3689
  relaxLayout(layout, 300);
2013
3690
  fitLayout(layout, 20);
2014
3691
  const edgeLayer = svgEl("g", { class: "chart-graph-edges" });
2015
3692
  const nodeLayer = svgEl("g", { class: "chart-graph-nodes" });
2016
- for (const e of current.edges) {
3693
+ for (const e of current2.edges) {
2017
3694
  const from = idOf.get(e.source);
2018
3695
  const to = idOf.get(e.target);
2019
3696
  if (from == null || to == null || from === to) continue;
2020
3697
  const line = svgEl("line", {
2021
3698
  ...edgeEnds(from, to),
2022
- stroke: "var(--token-line-soft)",
3699
+ stroke: "var(--icen-token-line-soft)",
2023
3700
  "stroke-width": edgeWidth(e).toFixed(2),
2024
3701
  ...directed ? { "marker-end": `url(#${arrowId})` } : {}
2025
3702
  });
2026
- line.classList.add("chart-graph-edge");
3703
+ line.classList.add("icen-chart-graph-edge");
2027
3704
  const fromKey = nodes[from]?.cluster;
2028
3705
  const toKey = nodes[to]?.cluster;
2029
- if (fromKey) line.setAttribute("data-edge-cluster-from", fromKey);
2030
- if (toKey) line.setAttribute("data-edge-cluster-to", toKey);
3706
+ if (fromKey) line.setAttribute("data-icen-edge-cluster-from", fromKey);
3707
+ if (toKey) line.setAttribute("data-icen-edge-cluster-to", toKey);
2031
3708
  edgeList.push({ el: line, from, to });
2032
3709
  edgeLayer.appendChild(line);
2033
3710
  }
@@ -2035,13 +3712,13 @@ function renderGraph(el, raw) {
2035
3712
  const clusterKey = node.cluster;
2036
3713
  const ci = clusterKey != null && clusters ? clusters.indexOf.get(clusterKey) : void 0;
2037
3714
  const clusterName = ci != null && clusters && clusterKey != null ? clusters.label(clusterKey) : void 0;
2038
- const fill = clusters ? ci != null ? clusters.color(ci) : "var(--token-text-faint)" : tone;
3715
+ const fill = clusters ? ci != null ? clusters.color(ci) : "var(--icen-token-text-faint)" : tone;
2039
3716
  const pos = { x: GRAPH_PAD + layout.x[i], y: GRAPH_PAD + layout.y[i] };
2040
3717
  const g = svgEl("g", {
2041
- class: "chart-graph-node",
3718
+ class: "icen-chart-graph-node",
2042
3719
  transform: `translate(${pos.x.toFixed(1)},${pos.y.toFixed(1)})`
2043
3720
  });
2044
- g.setAttribute("data-chart-node-id", node.id);
3721
+ g.setAttribute("data-icen-chart-node-id", node.id);
2045
3722
  setMarkData(g, {
2046
3723
  index: i,
2047
3724
  seriesIndex: ci,
@@ -2050,18 +3727,18 @@ function renderGraph(el, raw) {
2050
3727
  value: weights[i]
2051
3728
  });
2052
3729
  const dot = svgEl("circle", {
2053
- class: "chart-graph-dot",
3730
+ class: "icen-chart-graph-dot",
2054
3731
  r: (nodeRadii[i] ?? 6).toFixed(1),
2055
3732
  fill,
2056
3733
  "fill-opacity": "0.92",
2057
- stroke: "var(--token-card)",
3734
+ stroke: "var(--icen-token-card)",
2058
3735
  "stroke-width": "1.5"
2059
3736
  });
2060
3737
  const hit = svgEl("circle", {
2061
3738
  class: "chart-graph-hit",
2062
3739
  r: String(Math.max((nodeRadii[i] ?? 6) + 4, 11)),
2063
3740
  fill: "transparent",
2064
- "data-chart-hit": "1"
3741
+ "data-icen-chart-hit": "1"
2065
3742
  });
2066
3743
  const labelText = truncateText(node.label ?? node.id);
2067
3744
  const head = clusterName ? `${clusterName} \xB7 ${labelText}` : labelText;
@@ -2083,11 +3760,11 @@ function renderGraph(el, raw) {
2083
3760
  );
2084
3761
  body.appendChild(legend);
2085
3762
  const syncEdges = () => {
2086
- const hiddenOf = (key) => key != null && legend.querySelector(`[data-chart-key="${CSS.escape(key)}"]`)?.classList.contains("is-off") === true;
3763
+ const hiddenOf = (key) => key != null && legend.querySelector(`[data-icen-chart-key="${CSS.escape(key)}"]`)?.classList.contains("is-off") === true;
2087
3764
  for (const edge of edgeList) {
2088
3765
  edge.el.classList.toggle(
2089
3766
  "is-off",
2090
- hiddenOf(edge.el.getAttribute("data-edge-cluster-from")) || hiddenOf(edge.el.getAttribute("data-edge-cluster-to"))
3767
+ hiddenOf(edge.el.getAttribute("data-icen-edge-cluster-from")) || hiddenOf(edge.el.getAttribute("data-icen-edge-cluster-to"))
2091
3768
  );
2092
3769
  }
2093
3770
  };
@@ -2145,9 +3822,9 @@ function renderGraph(el, raw) {
2145
3822
  const onNodePointerDown = (e) => {
2146
3823
  if (e.button !== 0 || !layout) return;
2147
3824
  const target = e.target;
2148
- const g = target instanceof Element ? target.closest(".chart-graph-node") : null;
3825
+ const g = target instanceof Element ? target.closest(".icen-chart-graph-node") : null;
2149
3826
  if (!g) return;
2150
- const i = layout.index.get(g.getAttribute("data-chart-node-id") ?? "");
3827
+ const i = layout.index.get(g.getAttribute("data-icen-chart-node-id") ?? "");
2151
3828
  if (i == null) return;
2152
3829
  e.preventDefault();
2153
3830
  endDrag();
@@ -2158,20 +3835,23 @@ function renderGraph(el, raw) {
2158
3835
  window.addEventListener("pointerup", endDrag);
2159
3836
  window.addEventListener("pointercancel", endDrag);
2160
3837
  };
2161
- chartDelegateMeta.set(el, { type: () => GRAPH_CHART_TYPE, tooltip: () => current.tooltip !== false });
3838
+ chartDelegateMeta.set(el, { type: () => GRAPH_CHART_TYPE, tooltip: () => current2.tooltip !== false });
2162
3839
  const eventsControl = bindDatumEvents(el);
2163
3840
  const render = () => {
2164
3841
  if (drag) endDrag();
2165
- const clusters = buildClusterModel(current.nodes.map((n) => n.cluster), current.clusterLabels);
2166
- if (current.legend !== void 0) legendState.hidden = current.legend === false;
2167
- withChrome(el, current, clusters != null, paint, legendState);
3842
+ const clusters = buildClusterModel(current2.nodes.map((n) => n.cluster), current2.clusterLabels);
3843
+ if (current2.legend !== void 0) legendState.hidden = current2.legend === false;
3844
+ withChrome(el, current2, clusters != null, paint, legendState);
2168
3845
  };
2169
3846
  render();
2170
3847
  return {
2171
3848
  el,
2172
- spec: current,
3849
+ /** 当前规格(getter:update 换引用后读到最新) */
3850
+ get spec() {
3851
+ return current2;
3852
+ },
2173
3853
  update(next) {
2174
- current = normalizeGraphSpec(next);
3854
+ current2 = normalizeGraphSpec(next);
2175
3855
  render();
2176
3856
  },
2177
3857
  on(name, listener) {
@@ -2194,19 +3874,19 @@ var MAP_H = 220;
2194
3874
  var MAP_PAD = 14;
2195
3875
  function renderMap(el, raw) {
2196
3876
  const noop = () => void 0;
2197
- let current = normalizeMapSpec(raw);
3877
+ let current2 = normalizeMapSpec(raw);
2198
3878
  if (typeof document === "undefined") {
2199
- return { el, spec: current, update: noop, on: () => noop, destroy: noop };
3879
+ return { el, spec: current2, update: noop, on: () => noop, destroy: noop };
2200
3880
  }
2201
3881
  const legendState = { hidden: null };
2202
3882
  const paint = (body) => {
2203
- const points = current.points.filter((p) => Number.isFinite(p.x) && Number.isFinite(p.y));
3883
+ const points = current2.points.filter((p) => Number.isFinite(p.x) && Number.isFinite(p.y));
2204
3884
  if (points.length === 0) {
2205
- renderEmpty(body, current.emptyLabel);
3885
+ renderEmpty(body, current2.emptyLabel);
2206
3886
  return;
2207
3887
  }
2208
- const clusters = buildClusterModel(points.map((p) => p.cluster), current.clusters);
2209
- const tone = toneVar(current.tone);
3888
+ const clusters = buildClusterModel(points.map((p) => p.cluster), current2.clusters);
3889
+ const tone = toneVar(current2.tone);
2210
3890
  let xMin = Infinity;
2211
3891
  let xMax = -Infinity;
2212
3892
  let yMin = Infinity;
@@ -2222,9 +3902,9 @@ function renderMap(el, raw) {
2222
3902
  const xAt = (x) => MAP_PAD + (x - xMin) / (xMax - xMin) * (MAP_W - MAP_PAD * 2);
2223
3903
  const yAt = (y) => MAP_H - MAP_PAD - (y - yMin) / (yMax - yMin) * (MAP_H - MAP_PAD * 2);
2224
3904
  const wrap = document.createElement("div");
2225
- wrap.className = "chart-map";
2226
- if (current.tone) wrap.style.setProperty("--chart-tone", toneVar(current.tone));
2227
- const svg = svgEl("svg", { viewBox: `0 0 ${MAP_W} ${MAP_H}`, role: "img" });
3905
+ wrap.className = "icen-chart-map";
3906
+ if (current2.tone) wrap.style.setProperty("--chart-tone", toneVar(current2.tone));
3907
+ const svg = svgEl("svg", { viewBox: `0 0 ${MAP_W} ${MAP_H}`, role: "img", "aria-label": chartAriaLabel(current2.title, t("charts.type.map")) });
2228
3908
  for (let i = 0; i <= 3; i++) {
2229
3909
  const y = MAP_PAD + i * (MAP_H - MAP_PAD * 2) / 3;
2230
3910
  svg.appendChild(svgEl("line", {
@@ -2232,7 +3912,7 @@ function renderMap(el, raw) {
2232
3912
  x2: String(MAP_W - MAP_PAD),
2233
3913
  y1: String(y),
2234
3914
  y2: String(y),
2235
- stroke: "var(--token-line-soft)",
3915
+ stroke: "var(--icen-token-line-soft)",
2236
3916
  "stroke-width": "0.75",
2237
3917
  "stroke-dasharray": "2 4"
2238
3918
  }));
@@ -2244,7 +3924,7 @@ function renderMap(el, raw) {
2244
3924
  x2: String(x),
2245
3925
  y1: String(MAP_PAD),
2246
3926
  y2: String(MAP_H - MAP_PAD),
2247
- stroke: "var(--token-line-soft)",
3927
+ stroke: "var(--icen-token-line-soft)",
2248
3928
  "stroke-width": "0.75",
2249
3929
  "stroke-dasharray": "2 4"
2250
3930
  }));
@@ -2252,25 +3932,25 @@ function renderMap(el, raw) {
2252
3932
  points.forEach((p, i) => {
2253
3933
  const ci = p.cluster != null && clusters ? clusters.indexOf.get(p.cluster) : void 0;
2254
3934
  const clusterName = ci != null && clusters && p.cluster != null ? clusters.label(p.cluster) : void 0;
2255
- const color = clusters ? ci != null ? clusters.color(ci) : "var(--token-text-faint)" : tone;
3935
+ const color = clusters ? ci != null ? clusters.color(ci) : "var(--icen-token-text-faint)" : tone;
2256
3936
  const label = p.label ?? p.id;
2257
3937
  const labelText = truncateText(label);
2258
3938
  const tip = clusterName ? `${clusterName} \xB7 ${labelText}` : labelText;
2259
3939
  const g = svgEl("g", {
2260
- class: "chart-map-point",
3940
+ class: "icen-chart-map-point",
2261
3941
  transform: `translate(${xAt(p.x).toFixed(1)},${yAt(p.y).toFixed(1)})`
2262
3942
  });
2263
- g.setAttribute("data-chart-point-id", p.id);
3943
+ g.setAttribute("data-icen-chart-point-id", p.id);
2264
3944
  setMarkData(g, { index: i, seriesIndex: ci, seriesName: clusterName, label });
2265
3945
  const dot = svgEl("circle", {
2266
- class: "chart-map-dot",
3946
+ class: "icen-chart-map-dot",
2267
3947
  r: "4",
2268
3948
  fill: color,
2269
3949
  "fill-opacity": "0.7",
2270
3950
  stroke: color,
2271
3951
  "stroke-width": "1"
2272
3952
  });
2273
- const hit = svgEl("circle", { class: "chart-map-hit", r: "9", fill: "transparent", "data-chart-hit": "1" });
3953
+ const hit = svgEl("circle", { class: "chart-map-hit", r: "9", fill: "transparent", "data-icen-chart-hit": "1" });
2274
3954
  const title = svgEl("title", {});
2275
3955
  title.textContent = tip;
2276
3956
  g.append(dot, hit, title);
@@ -2288,19 +3968,19 @@ function renderMap(el, raw) {
2288
3968
  );
2289
3969
  }
2290
3970
  };
2291
- chartDelegateMeta.set(el, { type: () => MAP_CHART_TYPE, tooltip: () => current.tooltip !== false });
3971
+ chartDelegateMeta.set(el, { type: () => MAP_CHART_TYPE, tooltip: () => current2.tooltip !== false });
2292
3972
  const eventsControl = bindDatumEvents(el);
2293
3973
  const render = () => {
2294
- const clusters = buildClusterModel(current.points.map((p) => p.cluster), current.clusters);
2295
- if (current.legend !== void 0) legendState.hidden = current.legend === false;
2296
- withChrome(el, current, clusters != null, paint, legendState);
3974
+ const clusters = buildClusterModel(current2.points.map((p) => p.cluster), current2.clusters);
3975
+ if (current2.legend !== void 0) legendState.hidden = current2.legend === false;
3976
+ withChrome(el, current2, clusters != null, paint, legendState);
2297
3977
  };
2298
3978
  render();
2299
3979
  return {
2300
3980
  el,
2301
- spec: current,
3981
+ spec: current2,
2302
3982
  update(next) {
2303
- current = normalizeMapSpec(next);
3983
+ current2 = normalizeMapSpec(next);
2304
3984
  render();
2305
3985
  },
2306
3986
  on(name, listener) {
@@ -2322,6 +4002,7 @@ export {
2322
4002
  chartFormatValue,
2323
4003
  inferChartType,
2324
4004
  layoutGraph,
4005
+ lttb,
2325
4006
  normalizeChartSpec,
2326
4007
  registerChartTone,
2327
4008
  renderArea,