@icen.ai/ui 0.9.0 → 0.10.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 (281) hide show
  1. package/AGENTS.md +138 -80
  2. package/README.md +66 -91
  3. package/dist/base.css +208 -179
  4. package/dist/behaviors/accordion.mjs +8 -8
  5. package/dist/behaviors/ai-branch.d.mts +1 -1
  6. package/dist/behaviors/ai-branch.mjs +1010 -94
  7. package/dist/behaviors/ai-chat.d.mts +7 -7
  8. package/dist/behaviors/ai-chat.mjs +1071 -161
  9. package/dist/behaviors/ai-composer.d.mts +44 -12
  10. package/dist/behaviors/ai-composer.mjs +1997 -524
  11. package/dist/behaviors/ai-core.d.mts +1 -1
  12. package/dist/behaviors/ai-core.mjs +1016 -107
  13. package/dist/behaviors/ai-diff.mjs +1019 -127
  14. package/dist/behaviors/ai-feedback.d.mts +1 -1
  15. package/dist/behaviors/ai-feedback.mjs +1035 -126
  16. package/dist/behaviors/ai-panel.d.mts +8 -8
  17. package/dist/behaviors/ai-panel.mjs +1284 -266
  18. package/dist/behaviors/ai-provider.mjs +1003 -101
  19. package/dist/behaviors/ai-threads.d.mts +1 -1
  20. package/dist/behaviors/ai-threads.mjs +1068 -154
  21. package/dist/behaviors/ai-tool.d.mts +2 -2
  22. package/dist/behaviors/ai-tool.mjs +2037 -396
  23. package/dist/behaviors/ai-tools.d.mts +89 -16
  24. package/dist/behaviors/ai-tools.mjs +4448 -372
  25. package/dist/behaviors/autocomplete.d.mts +53 -0
  26. package/dist/behaviors/autocomplete.mjs +1600 -0
  27. package/dist/behaviors/back-top.d.mts +1 -1
  28. package/dist/behaviors/back-top.mjs +951 -14
  29. package/dist/behaviors/carousel.d.mts +1 -1
  30. package/dist/behaviors/carousel.mjs +906 -11
  31. package/dist/behaviors/cascader.d.mts +48 -0
  32. package/dist/behaviors/cascader.mjs +1853 -0
  33. package/dist/behaviors/charts.d.mts +72 -8
  34. package/dist/behaviors/charts.mjs +1901 -256
  35. package/dist/behaviors/code-block.d.mts +36 -0
  36. package/dist/behaviors/code-block.mjs +1611 -0
  37. package/dist/behaviors/command-palette.d.mts +9 -6
  38. package/dist/behaviors/command-palette.mjs +161 -59
  39. package/dist/behaviors/context-menu.d.mts +9 -8
  40. package/dist/behaviors/context-menu.mjs +1112 -44
  41. package/dist/behaviors/controls.d.mts +13 -13
  42. package/dist/behaviors/controls.mjs +989 -130
  43. package/dist/behaviors/copy.d.mts +21 -2
  44. package/dist/behaviors/copy.mjs +1206 -42
  45. package/dist/behaviors/datatable.d.mts +53 -3
  46. package/dist/behaviors/datatable.mjs +1963 -207
  47. package/dist/behaviors/date-picker.d.mts +0 -1
  48. package/dist/behaviors/date-picker.mjs +1340 -293
  49. package/dist/behaviors/design.d.mts +54 -0
  50. package/dist/behaviors/design.mjs +109 -0
  51. package/dist/behaviors/dropdown.d.mts +5 -6
  52. package/dist/behaviors/dropdown.mjs +262 -110
  53. package/dist/behaviors/events.d.mts +120 -3
  54. package/dist/behaviors/events.mjs +47 -2
  55. package/dist/behaviors/feedback.d.mts +30 -0
  56. package/dist/behaviors/feedback.mjs +296 -0
  57. package/dist/behaviors/focus.d.mts +8 -0
  58. package/dist/behaviors/focus.mjs +24 -0
  59. package/dist/behaviors/form-validate.d.mts +102 -0
  60. package/dist/behaviors/form-validate.mjs +6091 -0
  61. package/dist/behaviors/i18n.d.mts +789 -0
  62. package/dist/behaviors/i18n.mjs +1711 -0
  63. package/dist/behaviors/icons.d.mts +93 -0
  64. package/dist/behaviors/icons.mjs +113 -0
  65. package/dist/behaviors/input.d.mts +9 -1
  66. package/dist/behaviors/input.mjs +1056 -60
  67. package/dist/behaviors/kb-access.d.mts +1 -1
  68. package/dist/behaviors/kb-access.mjs +2129 -239
  69. package/dist/behaviors/kb-acl.d.mts +6 -6
  70. package/dist/behaviors/kb-acl.mjs +1119 -179
  71. package/dist/behaviors/kb-answer.mjs +2070 -418
  72. package/dist/behaviors/kb-audit.d.mts +1 -1
  73. package/dist/behaviors/kb-audit.mjs +1076 -154
  74. package/dist/behaviors/kb-canvas.mjs +1100 -177
  75. package/dist/behaviors/kb-chain.mjs +1022 -100
  76. package/dist/behaviors/kb-checkpoint.d.mts +1 -1
  77. package/dist/behaviors/kb-checkpoint.mjs +1319 -169
  78. package/dist/behaviors/kb-chunks.mjs +1152 -213
  79. package/dist/behaviors/kb-citation.d.mts +1 -1
  80. package/dist/behaviors/kb-citation.mjs +1201 -179
  81. package/dist/behaviors/kb-clarify.mjs +1058 -130
  82. package/dist/behaviors/kb-conflict.mjs +1041 -119
  83. package/dist/behaviors/kb-connector.mjs +1104 -176
  84. package/dist/behaviors/kb-core.d.mts +6 -1
  85. package/dist/behaviors/kb-core.mjs +1077 -162
  86. package/dist/behaviors/kb-eval.mjs +1971 -144
  87. package/dist/behaviors/kb-explain.d.mts +1 -1
  88. package/dist/behaviors/kb-explain.mjs +1024 -102
  89. package/dist/behaviors/kb-filter.mjs +2008 -178
  90. package/dist/behaviors/kb-gap.d.mts +1 -1
  91. package/dist/behaviors/kb-gap.mjs +1043 -121
  92. package/dist/behaviors/kb-hittest.d.mts +1 -1
  93. package/dist/behaviors/kb-hittest.mjs +1093 -150
  94. package/dist/behaviors/kb-metadata.mjs +1052 -130
  95. package/dist/behaviors/kb-passage.d.mts +2 -2
  96. package/dist/behaviors/kb-passage.mjs +1101 -161
  97. package/dist/behaviors/kb-pipeline.d.mts +2 -2
  98. package/dist/behaviors/kb-pipeline.mjs +1082 -162
  99. package/dist/behaviors/kb-qa.mjs +1088 -160
  100. package/dist/behaviors/kb-rerank.mjs +1047 -114
  101. package/dist/behaviors/kb-retrieval.mjs +2063 -224
  102. package/dist/behaviors/kb-review.mjs +1990 -159
  103. package/dist/behaviors/kb-sandbox.d.mts +1 -1
  104. package/dist/behaviors/kb-sandbox.mjs +1026 -104
  105. package/dist/behaviors/kb-segment.mjs +1111 -179
  106. package/dist/behaviors/kb-select.d.mts +24 -0
  107. package/dist/behaviors/kb-select.mjs +1989 -0
  108. package/dist/behaviors/kb-sources.d.mts +1 -1
  109. package/dist/behaviors/kb-sources.mjs +1084 -170
  110. package/dist/behaviors/kb-sql.d.mts +1 -1
  111. package/dist/behaviors/kb-sql.mjs +1143 -226
  112. package/dist/behaviors/kb-trace.d.mts +1 -1
  113. package/dist/behaviors/kb-trace.mjs +1042 -128
  114. package/dist/behaviors/kb-visibility.mjs +1086 -158
  115. package/dist/behaviors/kb-who-can.mjs +1974 -137
  116. package/dist/behaviors/mentions.d.mts +93 -0
  117. package/dist/behaviors/mentions.mjs +2152 -0
  118. package/dist/behaviors/modal.d.mts +4 -3
  119. package/dist/behaviors/modal.mjs +1055 -33
  120. package/dist/behaviors/nav.d.mts +1 -1
  121. package/dist/behaviors/nav.mjs +6 -6
  122. package/dist/behaviors/notification.d.mts +16 -8
  123. package/dist/behaviors/notification.mjs +1615 -265
  124. package/dist/behaviors/panel.d.mts +4 -0
  125. package/dist/behaviors/panel.mjs +994 -0
  126. package/dist/behaviors/popover.d.mts +28 -5
  127. package/dist/behaviors/popover.mjs +225 -24
  128. package/dist/behaviors/select.d.mts +5 -2
  129. package/dist/behaviors/select.mjs +1410 -117
  130. package/dist/behaviors/sidebar.d.mts +1 -1
  131. package/dist/behaviors/sidebar.mjs +13 -13
  132. package/dist/behaviors/slider.d.mts +1 -1
  133. package/dist/behaviors/slider.mjs +9 -9
  134. package/dist/behaviors/split-pane.d.mts +1 -1
  135. package/dist/behaviors/split-pane.mjs +7 -7
  136. package/dist/behaviors/suggestions.d.mts +27 -0
  137. package/dist/behaviors/suggestions.mjs +1089 -0
  138. package/dist/behaviors/svg-parse.d.mts +14 -0
  139. package/dist/behaviors/svg-parse.mjs +37 -0
  140. package/dist/behaviors/tabs.d.mts +2 -2
  141. package/dist/behaviors/tabs.mjs +25 -25
  142. package/dist/behaviors/tag-input.d.mts +23 -5
  143. package/dist/behaviors/tag-input.mjs +1359 -104
  144. package/dist/behaviors/theme-switcher.d.mts +24 -0
  145. package/dist/behaviors/theme-switcher.mjs +1981 -0
  146. package/dist/behaviors/theme.d.mts +15 -8
  147. package/dist/behaviors/theme.mjs +390 -28
  148. package/dist/behaviors/toast.d.mts +24 -25
  149. package/dist/behaviors/toast.mjs +1266 -88
  150. package/dist/behaviors/tooltip.d.mts +4 -0
  151. package/dist/behaviors/tooltip.mjs +378 -0
  152. package/dist/behaviors/tree-select.d.mts +69 -0
  153. package/dist/behaviors/tree-select.mjs +1907 -0
  154. package/dist/behaviors/tree.d.mts +1 -1
  155. package/dist/behaviors/tree.mjs +15 -15
  156. package/dist/behaviors/upload.d.mts +3 -2
  157. package/dist/behaviors/upload.mjs +1076 -66
  158. package/dist/cli.mjs +5 -6
  159. package/dist/components/ai-chat.css +666 -573
  160. package/dist/components/ai-diff.css +153 -132
  161. package/dist/components/ai-panel.css +351 -343
  162. package/dist/components/ai-tool.css +393 -238
  163. package/dist/components/autocomplete.css +61 -0
  164. package/dist/components/autocomplete.mjs +3 -0
  165. package/dist/components/back-top.css +34 -31
  166. package/dist/components/badge.css +44 -41
  167. package/dist/components/breadcrumb.css +67 -46
  168. package/dist/components/btn.css +80 -74
  169. package/dist/components/card.css +117 -106
  170. package/dist/components/cascader.css +311 -0
  171. package/dist/components/cascader.mjs +3 -0
  172. package/dist/components/chart-area.css +8 -2
  173. package/dist/components/chart-bar.css +95 -33
  174. package/dist/components/chart-gauge.css +14 -11
  175. package/dist/components/chart-graph.css +20 -17
  176. package/dist/components/chart-heatmap.css +96 -90
  177. package/dist/components/chart-line.css +8 -3
  178. package/dist/components/chart-pie.css +9 -6
  179. package/dist/components/chart-radar.css +8 -5
  180. package/dist/components/chart-scatter.css +9 -6
  181. package/dist/components/chart-sparkline.css +5 -2
  182. package/dist/components/chart-stack.css +14 -11
  183. package/dist/components/charts.css +164 -73
  184. package/dist/components/code-block.css +418 -0
  185. package/dist/components/code-block.mjs +4 -0
  186. package/dist/components/command-palette.css +138 -117
  187. package/dist/components/content.css +257 -251
  188. package/dist/components/copy.css +72 -44
  189. package/dist/components/datatable.css +423 -181
  190. package/dist/components/date-picker.css +135 -104
  191. package/dist/components/empty.css +68 -65
  192. package/dist/components/feedback.css +201 -183
  193. package/dist/components/form-validate.css +120 -0
  194. package/dist/components/form-validate.mjs +3 -0
  195. package/dist/components/form.css +150 -127
  196. package/dist/components/icon.css +102 -0
  197. package/dist/components/icon.mjs +3 -0
  198. package/dist/components/input.css +159 -104
  199. package/dist/components/kb-agent.css +188 -173
  200. package/dist/components/kb-data.css +257 -253
  201. package/dist/components/kb-ground.css +197 -185
  202. package/dist/components/kb-ingest.css +334 -350
  203. package/dist/components/kb-ops.css +265 -259
  204. package/dist/components/kb-perm.css +260 -271
  205. package/dist/components/kb-search.css +317 -360
  206. package/dist/components/kb.css +120 -109
  207. package/dist/components/layout.css +85 -82
  208. package/dist/components/material-chinese.css +73 -0
  209. package/dist/components/material-soviet.css +76 -0
  210. package/dist/components/material.css +275 -0
  211. package/dist/components/media.css +220 -166
  212. package/dist/components/mentions.css +189 -0
  213. package/dist/components/mentions.mjs +3 -0
  214. package/dist/components/menu.css +113 -105
  215. package/dist/components/modal.css +107 -112
  216. package/dist/components/nav.css +118 -115
  217. package/dist/components/notification.css +238 -174
  218. package/dist/components/pagination.css +56 -53
  219. package/dist/components/panel.css +66 -63
  220. package/dist/components/panel.mjs +1 -0
  221. package/dist/components/pill.css +81 -71
  222. package/dist/components/popover.css +67 -53
  223. package/dist/components/scroll-area.css +113 -110
  224. package/dist/components/segmented.css +146 -143
  225. package/dist/components/select.css +206 -186
  226. package/dist/components/sidebar.css +137 -127
  227. package/dist/components/slider.css +117 -114
  228. package/dist/components/split-pane.css +112 -109
  229. package/dist/components/stat.css +112 -106
  230. package/dist/components/steps.css +109 -103
  231. package/dist/components/switch.css +138 -134
  232. package/dist/components/table.css +131 -107
  233. package/dist/components/tabs.css +114 -108
  234. package/dist/components/tag-input.css +48 -133
  235. package/dist/components/tag.css +81 -71
  236. package/dist/components/theme-switcher.css +105 -0
  237. package/dist/components/theme-switcher.mjs +3 -0
  238. package/dist/components/toast.css +100 -86
  239. package/dist/components/toolbar.css +45 -42
  240. package/dist/components/tooltip.css +102 -43
  241. package/dist/components/tooltip.mjs +1 -0
  242. package/dist/components/tree-select.css +416 -0
  243. package/dist/components/tree-select.mjs +3 -0
  244. package/dist/components/upload.css +135 -92
  245. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  246. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  247. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  248. package/dist/fonts/OFL.txt +96 -0
  249. package/dist/fonts/README.md +14 -0
  250. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  251. package/dist/index.d.mts +28 -14
  252. package/dist/index.mjs +20705 -9601
  253. package/dist/react.d.mts +91 -0
  254. package/dist/react.mjs +8208 -0
  255. package/dist/registry.json +130 -13
  256. package/dist/tokens/chinese.css +44 -0
  257. package/dist/tokens/colors.css +365 -1222
  258. package/dist/tokens/design.css +109 -0
  259. package/dist/tokens/dtcg.json +11198 -0
  260. package/dist/tokens/figma.variables.json +7017 -0
  261. package/dist/tokens/icon-masks.css +78 -0
  262. package/dist/tokens/pixel.css +50 -0
  263. package/dist/tokens/soviet.css +44 -0
  264. package/dist/tokens/style-profiles.css +36 -547
  265. package/dist/tokens/themes.json +308 -0
  266. package/dist/tokens/tokens-studio.json +6728 -0
  267. package/dist/tokens/typography.css +21 -18
  268. package/dist/tokens.css +1555 -1801
  269. package/dist/ui.css +11975 -9831
  270. package/dist/vue.d.mts +344 -0
  271. package/dist/vue.mjs +7781 -0
  272. package/docs/spec/ai-input-experience.md +75 -0
  273. package/docs/spec/ai-native.md +238 -147
  274. package/docs/spec/design-philosophy.md +189 -0
  275. package/docs/spec/design-primitives.md +196 -0
  276. package/docs/spec/kb-family.md +147 -115
  277. package/package.json +43 -8
  278. package/dist/retro-effects.css +0 -255
  279. package/dist/tokens/retro-effects.css +0 -255
  280. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  281. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -1,3 +1,989 @@
1
+ // src/behaviors/events.ts
2
+ function emitIcen(source, type, detail) {
3
+ return source.dispatchEvent(
4
+ new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
5
+ );
6
+ }
7
+
8
+ // src/behaviors/i18n.ts
9
+ var ICEN_LOCALE_ZH_CN = {
10
+ /* ── aiBranch ── */
11
+ "aiBranch.nextVersion": "\u4E0B\u4E00\u7248\u672C",
12
+ "aiBranch.prevVersion": "\u4E0A\u4E00\u7248\u672C",
13
+ "aiBranch.version": "\u5206\u652F\u7248\u672C",
14
+ /* ── aiChat ── */
15
+ "aiChat.backToBottom": "\u56DE\u5230\u5E95\u90E8",
16
+ "aiChat.backToBottomCount": "\u56DE\u5230\u5E95\u90E8 \xB7 {p0} \u6761\u65B0\u6D88\u606F",
17
+ "aiChat.continue": "\u7EE7\u7EED\u751F\u6210",
18
+ "aiChat.download": "\u4E0B\u8F7D",
19
+ "aiChat.file": "\u6587\u4EF6",
20
+ "aiChat.roleSystem": "\u7CFB",
21
+ "aiChat.roleTool": "\u5DE5",
22
+ "aiChat.roleUser": "\u6211",
23
+ "aiChat.thinking": "\u601D\u8003 {p0}",
24
+ /* ── aiComposer ── */
25
+ "aiComposer.attachAgent": "\u4EE3\u7406",
26
+ "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
27
+ "aiComposer.searchLibrary": "\u641C\u7D22\u6280\u80FD\u3001\u5DE5\u5177\u3001\u6587\u4EF6\u4E0E\u547D\u4EE4",
28
+ "aiComposer.all": "\u5168\u90E8",
29
+ "aiComposer.skills": "\u6280\u80FD",
30
+ "aiComposer.tools": "\u5DE5\u5177",
31
+ "aiComposer.libraryHint": "\u4E0A\u4E0B\u6587\u968F\u6D88\u606F\u53D1\u9001 \xB7 \u547D\u4EE4\u5148\u586B\u5165\u8F93\u5165\u6846",
32
+ "aiComposer.commandHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u6267\u884C \xB7 Esc \u8FD4\u56DE",
33
+ "aiComposer.refHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u5F15\u7528 \xB7 Esc \u8FD4\u56DE",
34
+ "aiComposer.noLibraryMatch": "\u6CA1\u6709\u5339\u914D\u7684\u9879\u76EE\uFF0C\u8BD5\u8BD5\u5176\u4ED6\u5173\u952E\u8BCD",
35
+ "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",
36
+ "aiComposer.attachDoc": "\u6587\u6863",
37
+ "aiComposer.attachFile": "\u6587\u4EF6",
38
+ "aiComposer.attachFolder": "\u6587\u4EF6\u5939",
39
+ "aiComposer.cacheInvalidHint": "\u5207\u6362\u6A21\u578B\u4F1A\u4F7F prompt \u7F13\u5B58\u5931\u6548",
40
+ "aiComposer.commands": "\u547D\u4EE4",
41
+ "aiComposer.currentTodos": "\u5F53\u524D\u5F85\u529E",
42
+ "aiComposer.done": "\u5B8C\u6210",
43
+ "aiComposer.justNow": "\u521A\u521A \xB7 {p0}",
44
+ "aiComposer.modelAria": "\u6A21\u578B {p0}\uFF08{p1}\uFF09",
45
+ "aiComposer.noCommandMatch": "\u65E0\u5339\u914D\u547D\u4EE4",
46
+ "aiComposer.noModelMatch": "\u65E0\u5339\u914D\u6A21\u578B",
47
+ "aiComposer.noRefMatch": "\u65E0\u5339\u914D\u5F15\u7528",
48
+ "aiComposer.placeholder": "\u8F93\u5165\u6D88\u606F\uFF0C/ \u547D\u4EE4 \xB7 @ \u5F15\u7528 \xB7 Enter \u53D1\u9001",
49
+ "aiComposer.refs": "\u5F15\u7528",
50
+ "aiComposer.removeAttachment": "\u79FB\u9664\u9644\u4EF6 {p0}",
51
+ "aiComposer.removeQueued": "\u79FB\u9664\u6392\u961F\u6D88\u606F {p0}",
52
+ "aiComposer.removeRef": "\u79FB\u9664\u5F15\u7528 {p0}",
53
+ "aiComposer.searchModels": "\u641C\u7D22\u6A21\u578B",
54
+ "aiComposer.selectModel": "\u9009\u62E9\u6A21\u578B",
55
+ "aiComposer.send": "\u53D1\u9001",
56
+ "aiComposer.stop": "\u505C\u6B62\u751F\u6210",
57
+ "aiComposer.stopped": "\u5DF2\u505C\u6B62",
58
+ "aiComposer.todoChip": "\u5F53\u524D\u5F85\u529E {p0}/{p1}{p2}",
59
+ "aiComposer.todoHasError": "\uFF08\u6709\u5931\u8D25\u9879\uFF09",
60
+ /* ── aiCore ── */
61
+ "aiCore.kindBrowser": "\u6D4F\u89C8",
62
+ "aiCore.kindChart": "\u56FE\u8868",
63
+ "aiCore.kindDelete": "\u5220\u9664",
64
+ "aiCore.kindEdit": "\u7F16\u8F91",
65
+ "aiCore.kindFetch": "\u8BF7\u6C42",
66
+ "aiCore.kindGlob": "\u5339\u914D",
67
+ "aiCore.kindGrep": "\u641C\u7D22",
68
+ "aiCore.kindNote": "\u7B14\u8BB0",
69
+ "aiCore.kindPlan": "\u8BA1\u5212",
70
+ "aiCore.kindRead": "\u8BFB\u53D6",
71
+ "aiCore.kindSearch": "\u68C0\u7D22",
72
+ "aiCore.kindShell": "\u547D\u4EE4",
73
+ "aiCore.kindSkill": "\u6280\u80FD",
74
+ "aiCore.kindSubagent": "\u5B50\u4EE3\u7406",
75
+ "aiCore.kindTodo": "\u5F85\u529E",
76
+ "aiCore.kindWrite": "\u5199\u5165",
77
+ "aiCore.statusApproval": "\u5F85\u786E\u8BA4",
78
+ "aiCore.statusCancelled": "\u5DF2\u53D6\u6D88",
79
+ "aiCore.statusDone": "\u5B8C\u6210",
80
+ "aiCore.statusError": "\u5931\u8D25",
81
+ "aiCore.statusPending": "\u7B49\u5F85",
82
+ "aiCore.statusRunning": "\u6267\u884C\u4E2D",
83
+ "aiCore.statusStreaming": "\u6D41\u5F0F\u4E2D",
84
+ "aiCore.todoProgress": "{p0}/{p1} \u5B8C\u6210",
85
+ /* ── aiDiff ── */
86
+ "aiDiff.accepted": "\u5DF2\u63A5\u53D7",
87
+ "aiDiff.binary": "\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u663E\u793A\u6587\u672C\u5DEE\u5F02",
88
+ "aiDiff.empty": "\u65E0\u5DEE\u5F02\u5185\u5BB9",
89
+ "aiDiff.rejected": "\u5DF2\u62D2\u7EDD",
90
+ /* ── aiFeedback ── */
91
+ "aiFeedback.helpful": "\u6709\u5E2E\u52A9",
92
+ "aiFeedback.notHelpful": "\u65E0\u5E2E\u52A9",
93
+ "aiFeedback.reasonCitationMismatch": "\u5F15\u7528\u4E0D\u7B26",
94
+ "aiFeedback.reasonOutdated": "\u5185\u5BB9\u8FC7\u65F6",
95
+ "aiFeedback.reasonUnauthorized": "\u8D8A\u6743\u4FE1\u606F",
96
+ "aiFeedback.reasonUnsourced": "\u65E0\u5F15\u7528\u4F9D\u636E",
97
+ "aiFeedback.reasonWrong": "\u7B54\u6848\u6709\u8BEF",
98
+ "aiFeedback.thanks": "\u611F\u8C22\u53CD\u9988\uFF0C\u5DF2\u5173\u8054\u5230\u8BE5\u6761\u56DE\u7B54\u7684\u8FFD\u8E2A\u8BB0\u5F55",
99
+ /* ── aiPanel ── */
100
+ "aiPanel.audit": "\u5BA1\u8BA1",
101
+ "aiPanel.cacheRead": "\u7F13\u5B58\u8BFB",
102
+ "aiPanel.cacheWrite": "\u7F13\u5B58\u5199",
103
+ "aiPanel.callsTokens": "{p0} \u6B21 \xB7 {p1} tok{p2}",
104
+ "aiPanel.clearAudit": "\u6E05\u9664\u5BA1\u8BA1",
105
+ "aiPanel.context": "\u4E0A\u4E0B\u6587",
106
+ "aiPanel.contextWindow": "\u4E0A\u4E0B\u6587\u7A97\u53E3",
107
+ "aiPanel.errorsCount": "{p0} \u5931\u8D25",
108
+ "aiPanel.files": "\u6587\u4EF6 ({p0})",
109
+ "aiPanel.itemStatus": "{p0}\uFF0C\u72B6\u6001\uFF1A{p1}",
110
+ "aiPanel.noAudit": "\u6682\u65E0\u5BA1\u8BA1\u8BB0\u5F55",
111
+ "aiPanel.noUsage": "\u6682\u65E0\u7528\u91CF",
112
+ "aiPanel.reasoning": "\u63A8\u7406",
113
+ "aiPanel.requestsCount": "{p0} \u6B21\u8BF7\u6C42",
114
+ "aiPanel.ringPercent": "\u4E0A\u4E0B\u6587\u7A97\u53E3\u5360\u7528 {p0}%\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
115
+ "aiPanel.ringUsed": "\u5DF2\u7528 {p0}\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
116
+ "aiPanel.taskProgress": "\u4EFB\u52A1\u8FDB\u5EA6",
117
+ "aiPanel.toolsCount": "{p0} \u5DE5\u5177",
118
+ "aiPanel.usage": "\u7528\u91CF",
119
+ "aiPanel.usageAria": "\u7528\u91CF\uFF1A{p0}",
120
+ /* ── aiProvider ── */
121
+ "aiProvider.audioUrlOnly": "\u4EC5 URL \u7684\u97F3\u9891\uFF08input_audio \u9700 base64\uFF0C\u8BF7\u5148\u53D6\u56DE\u5185\u8054\uFF09",
122
+ "aiProvider.audioUrlOnlyAnthropic": "\u4EC5 URL \u7684\u97F3\u9891\uFF08audio \u5757\u9700 base64 source\uFF09",
123
+ "aiProvider.base64File": "base64 \u6587\u4EF6\uFF08file \u90E8\u4EF6\u9700 Files API file_id\uFF0C\u8BF7\u7F6E\u4E8E url \u69FD\uFF09",
124
+ "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",
125
+ "aiProvider.emptyResponse": "\u54CD\u5E94\u4E3A\u7A7A",
126
+ "aiProvider.glmLabel": "GLM\uFF08\u667A\u8C31\uFF09",
127
+ "aiProvider.invalidJson": "\u54CD\u5E94\u4E0D\u662F\u5408\u6CD5 JSON",
128
+ "aiProvider.kimiLabel": "Kimi\uFF08\u6708\u4E4B\u6697\u9762\uFF09",
129
+ "aiProvider.networkFailed": "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF1A{p0}{p1}",
130
+ "aiProvider.nonPdfDocument": "\u975E PDF \u6587\u4EF6\u5757\uFF08document \u5757\u4E3A application/pdf\uFF0C\u6536\u5230 {p0}\uFF09",
131
+ "aiProvider.requestCancelled": "\u8BF7\u6C42\u5DF2\u53D6\u6D88",
132
+ "aiProvider.resourceRef": "[\u8D44\u6E90] {p0} ({p1})",
133
+ "aiProvider.streamError": "\u6D41\u5F0F\u54CD\u5E94\u9519\u8BEF",
134
+ "aiProvider.toolRoleNoCallId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08openai \u65CF\u9700 tool_call_id\uFF09",
135
+ "aiProvider.toolRoleNoUseId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08anthropic \u65CF\u6620\u5C04 tool_result \u9700 tool_use_id\uFF09",
136
+ "aiProvider.unsupported": "{p0} \u7EBF\u534F\u8BAE\u4E0D\u652F\u6301 {p1}",
137
+ "aiProvider.videoUnsupported": "video \u8F93\u5165\uFF08\u65E0\u4E3B\u6D41 chat API \u652F\u6301\uFF09",
138
+ "aiProvider.videoUnsupportedAnthropic": "video \u8F93\u5165",
139
+ /* ── aiThreads ── */
140
+ "aiThreads.actionsAria": "\u4F1A\u8BDD\u64CD\u4F5C",
141
+ "aiThreads.archived": "\u5DF2\u5F52\u6863",
142
+ /* ── aiTool ── */
143
+ "aiTool.allow": "\u5141\u8BB8",
144
+ "aiTool.reject": "\u62D2\u7EDD",
145
+ /* ── aiTools ── */
146
+ "aiTools.chart.area": "line \u591A\u7CFB\u5217\u586B\u5145\u9762\u79EF",
147
+ "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",
148
+ "aiTools.chart.dates": "\u8D21\u732E\u65E5\u5386 ISO \u65E5\u671F\uFF08\u4E0E values \u914D\u5BF9\uFF09",
149
+ "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",
150
+ "aiTools.chart.dims": "data[] \u7684\u5B57\u6BB5\u6620\u5C04\uFF1A{label?, series?, value?, x?, y?}",
151
+ "aiTools.chart.format": "\u6570\u503C\u683C\u5F0F\u5316\uFF1A{notation?: compact|percent|ms, unit?}",
152
+ "aiTools.chart.labels": "\u7C7B\u76EE\u8F74\uFF08line/vbar/hbar\uFF09",
153
+ "aiTools.chart.legend": "false = \u521D\u59CB\u9690\u85CF\u56FE\u4F8B",
154
+ "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",
155
+ "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",
156
+ "aiTools.chart.points": "\u6563\u70B9/\u6C14\u6CE1\uFF1A[{x,y,size?,label?}]",
157
+ "aiTools.chart.radarAxes": "\u96F7\u8FBE\u8F74\u540D",
158
+ "aiTools.chart.segments": "\u5360\u6BD4\u578B\uFF08donut/stack\uFF09\uFF1A[{label,value}]",
159
+ "aiTools.chart.series": "\u591A\u7CFB\u5217\uFF08line/vbar/radar\uFF09",
160
+ "aiTools.chart.stacked": "vbar \u591A\u7CFB\u5217\u5806\u53E0\uFF08\u9ED8\u8BA4\u5206\u7EC4\uFF09",
161
+ "aiTools.chart.title": "\u56FE\u8868\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5934\u90E8\u884C\u5DE6\u4FA7\uFF09",
162
+ "aiTools.chart.tooltip": "false = \u5173\u95ED\u5185\u7F6E\u63D0\u793A",
163
+ "aiTools.chart.type": "\u56FE\u8868\u7C7B\u578B\uFF0C\u7F3A\u7701\u81EA\u52A8\u63A8\u65AD",
164
+ "aiTools.chart.values": "\u5355\u7CFB\u5217\u6570\u503C\uFF08\u4E0E labels \u914D\u5BF9\uFF09",
165
+ "aiTools.chart.zoom": "\u7F29\u653E\u4EA4\u4E92\uFF1A'x'=\u7C7B\u76EE\u8F74\u533A\u95F4\u7F29\u653E\uFF0C'brush'=\u5237\u9009\u7F29\u653E",
166
+ "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",
167
+ "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",
168
+ "aiTools.datatable.rows": "\u884C\u6570\u636E\u6570\u7EC4\uFF1A\u6BCF\u9879\u4E3A\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u5B57\u6BB5\u540D\u5BF9\u9F50 columns[].key",
169
+ "aiTools.datatable.title": "\u8868\u683C\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5DE5\u5177\u680F\u5DE6\u4FA7\uFF09",
170
+ "aiTools.execFailed": "\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A{p0}",
171
+ "aiTools.execTimeout": "\u6267\u884C\u8D85\u65F6\uFF08{p0}ms\uFF09",
172
+ "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",
173
+ "aiTools.missingRequired": "\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5",
174
+ "aiTools.none": "\uFF08\u65E0\u5DF2\u6CE8\u518C\u7684 UI \u5DE5\u5177\uFF09",
175
+ "aiTools.notInEnum": "\u4E0D\u5728\u5141\u8BB8\u53D6\u503C\u5185\uFF08{p0}\uFF09",
176
+ "aiTools.numMax": "\u6570\u503C {p0} \u5927\u4E8E\u6700\u5927\u503C {p1}",
177
+ "aiTools.numMin": "\u6570\u503C {p0} \u5C0F\u4E8E\u6700\u5C0F\u503C {p1}",
178
+ "aiTools.removeMount": "\u79FB\u9664 {p0} \u6302\u8F7D",
179
+ "aiTools.strMax": "\u957F\u5EA6 {p0} \u8D85\u8FC7\u4E0A\u9650 {p1}",
180
+ "aiTools.strMin": "\u957F\u5EA6 {p0} \u5C0F\u4E8E\u4E0B\u9650 {p1}",
181
+ "aiTools.typeMismatch": "\u671F\u671B {p0}\uFF0C\u5B9E\u5F97 {p1}",
182
+ "aiTools.validationFailed": "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF08{p0} \u9879\uFF09",
183
+ /* ── autocomplete ── */
184
+ "suggestions.loading": "\u6B63\u5728\u67E5\u627E\u5EFA\u8BAE\u2026",
185
+ "suggestions.error": "\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\u5EFA\u8BAE\uFF0C\u8BF7\u91CD\u8BD5\u3002",
186
+ "suggestions.options": "\u5EFA\u8BAE",
187
+ "suggestions.empty": "\u6CA1\u6709\u5339\u914D\u7684\u5EFA\u8BAE",
188
+ "autocomplete.empty": "\u65E0\u5339\u914D\u7ED3\u679C",
189
+ /* ── backTop ── */
190
+ "backTop.label": "\u56DE\u5230\u9876\u90E8",
191
+ /* ── carousel ── */
192
+ "carousel.item": "\u7B2C {p0} \u5F20",
193
+ "carousel.region": "\u8F6E\u64AD",
194
+ "carousel.slide": "\u5E7B\u706F\u7247",
195
+ "carousel.status": "\u7B2C {p0} / {p1} \u5F20",
196
+ /* ── charts ── */
197
+ "charts.calendarWeekdays": ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"],
198
+ "charts.few": "\u5C11",
199
+ "charts.hideLegend": "\u9690\u85CF\u56FE\u4F8B",
200
+ "charts.loading": "\u52A0\u8F7D\u4E2D",
201
+ "charts.many": "\u591A",
202
+ "charts.monthLabel": "{p0}\u6708",
203
+ "charts.noData": "\u6682\u65E0\u6570\u636E",
204
+ "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
205
+ "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
206
+ "charts.type.area": "\u9762\u79EF\u56FE",
207
+ "charts.type.donut": "\u73AF\u5F62\u56FE",
208
+ "charts.type.gauge": "\u4EEA\u8868\u76D8",
209
+ "charts.type.graph": "\u77E5\u8BC6\u56FE\u8C31",
210
+ "charts.type.heatmap": "\u70ED\u529B\u56FE",
211
+ "charts.type.line": "\u6298\u7EBF\u56FE",
212
+ "charts.type.map": "\u5730\u56FE",
213
+ "charts.type.radar": "\u96F7\u8FBE\u56FE",
214
+ "charts.type.scatter": "\u6563\u70B9\u56FE",
215
+ "charts.type.sparkline": "\u8FF7\u4F60\u8D8B\u52BF",
216
+ "charts.seriesName": "\u7CFB\u5217{p0}",
217
+ "charts.showLegend": "\u663E\u793A\u56FE\u4F8B",
218
+ "charts.value": "\u6570\u503C",
219
+ /* ── themeSwitcher ── */
220
+ "themeSwitcher.appearance": "\u5916\u89C2",
221
+ "themeSwitcher.theme": "\u4E3B\u9898",
222
+ "themeSwitcher.primitive": "\u539F\u8BED",
223
+ "themeSwitcher.mode": "\u660E\u6697",
224
+ "themeSwitcher.light": "\u6D45\u8272",
225
+ "themeSwitcher.dark": "\u6DF1\u8272",
226
+ "themeSwitcher.modern": "\u73B0\u4EE3",
227
+ "themeSwitcher.dongyun": "\u4E1C\u97F5",
228
+ "themeSwitcher.jugou": "\u5DE8\u6784",
229
+ "themeSwitcher.piano": "\u94A2\u7434",
230
+ "themeSwitcher.monet": "\u83AB\u5948",
231
+ "themeSwitcher.vangogh": "\u68B5\u9AD8",
232
+ "themeSwitcher.chinese": "\u4E2D\u5F0F",
233
+ "themeSwitcher.soviet": "\u82CF\u5F0F",
234
+ "themeSwitcher.pixel": "\u50CF\u7D20",
235
+ /* ── codeBlock ── */
236
+ "codeBlock.collapse": "\u6536\u8D77",
237
+ "codeBlock.region": "\u4EE3\u7801\u5185\u5BB9",
238
+ "codeBlock.copyFailed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
239
+ "codeBlock.copyRetry": "\u91CD\u8BD5\u590D\u5236",
240
+ "codeBlock.copy": "\u590D\u5236",
241
+ "codeBlock.foldCollapse": "\u6298\u53E0\u4EE3\u7801",
242
+ "codeBlock.foldExpand": "\u5C55\u5F00\u4EE3\u7801",
243
+ "codeBlock.linesTotal": "\u5171 {p0} \u884C",
244
+ "codeBlock.numHide": "\u9690\u85CF\u884C\u53F7",
245
+ "codeBlock.numShow": "\u663E\u793A\u884C\u53F7",
246
+ "codeBlock.tailAria": "\u5C55\u5F00\u6216\u6536\u8D77\u4EE3\u7801",
247
+ "codeBlock.wrapOff": "\u5173\u95ED\u6362\u884C",
248
+ "codeBlock.wrapOn": "\u81EA\u52A8\u6362\u884C",
249
+ /* ── common ── */
250
+ "common.accept": "\u63A5\u53D7",
251
+ "common.add": "\u65B0\u589E",
252
+ "common.all": "\u5168\u90E8",
253
+ "common.approve": "\u6279\u51C6",
254
+ "common.cancel": "\u53D6\u6D88",
255
+ "common.actionFailed": "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002",
256
+ "common.close": "\u5173\u95ED",
257
+ "common.confirm": "\u786E\u8BA4",
258
+ "common.copied": "\u5DF2\u590D\u5236",
259
+ "common.copy": "\u590D\u5236",
260
+ "common.delete": "\u5220\u9664",
261
+ "common.enable": "\u542F\u7528",
262
+ "common.exportCsv": "\u5BFC\u51FA CSV",
263
+ "common.healthy": "\u6B63\u5E38",
264
+ "common.input": "\u8F93\u5165",
265
+ "common.loadingEllipsis": "\u52A0\u8F7D\u4E2D\u2026",
266
+ "common.official": "\u5B98\u65B9",
267
+ "common.output": "\u8F93\u51FA",
268
+ "common.page": "\u7B2C {p0} \u9875",
269
+ "common.reject": "\u62D2\u7EDD",
270
+ "common.remove": "\u79FB\u9664",
271
+ "common.requestAccess": "\u7533\u8BF7\u8BBF\u95EE",
272
+ "common.requestAccessFor": "\u7533\u8BF7\u8BBF\u95EE {p0}",
273
+ "common.restricted": "\u53D7\u9650",
274
+ "common.retry": "\u91CD\u8BD5",
275
+ "common.rows": "{p0} \u884C",
276
+ "common.run": "\u8FD0\u884C",
277
+ "common.steps": "{p0} \u6B65",
278
+ "common.submit": "\u63D0\u4EA4",
279
+ "common.unknown": "\u672A\u77E5",
280
+ /* ── contextMenu ── */
281
+ "contextMenu.back": "\u540E\u9000",
282
+ "contextMenu.copyPageLink": "\u590D\u5236\u9875\u9762\u94FE\u63A5",
283
+ "contextMenu.forward": "\u524D\u8FDB",
284
+ "contextMenu.refresh": "\u5237\u65B0",
285
+ /* ── copy ── */
286
+ "copy.copied": "\u5DF2\u590D\u5236",
287
+ "copy.failed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
288
+ "copy.denied": "clipboard API \u88AB\u62D2\uFF08{p0}\uFF09\u4E14\u56DE\u9000 execCommand \u5931\u8D25",
289
+ "copy.unavailable": "\u526A\u8D34\u677F\u4E0D\u53EF\u7528\uFF08\u65E0 clipboard API \u4E14 execCommand \u56DE\u9000\u5931\u8D25\uFF09",
290
+ "copy.unknown": "\u672A\u77E5\u9519\u8BEF",
291
+ /* ── datatable ── */
292
+ "datatable.clear": "\u6E05\u7A7A",
293
+ "datatable.collapseGroup": "\u6298\u53E0\u5206\u7EC4 {p0}",
294
+ "datatable.columnSettingsAria": "\u5217\u8BBE\u7F6E",
295
+ "datatable.countUnit": "{p0} \u6761",
296
+ "datatable.editHint": "\u7F16\u8F91\u300C{p0}\u300D\uFF1A\u53CC\u51FB\u6216\u6309 Enter",
297
+ "datatable.editHintWithValue": "{p0}\uFF08\u53CC\u51FB\u6216\u6309 Enter \u7F16\u8F91\u300C{p1}\u300D\uFF09",
298
+ "datatable.empty": "\u6682\u65E0\u6570\u636E",
299
+ "datatable.emptyValue": "\uFF08\u7A7A\uFF09",
300
+ "datatable.expandGroup": "\u5C55\u5F00\u5206\u7EC4 {p0}",
301
+ "datatable.expandRow": "\u5C55\u5F00\u884C",
302
+ "datatable.filterChipAria": "\u7B5B\u9009\u300C{p0}\u300D",
303
+ "datatable.pageSizeAria": "\u6BCF\u9875\u6761\u6570",
304
+ "datatable.paginationAria": "\u5206\u9875",
305
+ "datatable.reset": "\u91CD\u7F6E",
306
+ "datatable.resizeAria": "\u8C03\u6574\u300C{p0}\u300D\u5217\u5BBD",
307
+ "datatable.searchAria": "\u641C\u7D22\u8868\u683C",
308
+ "datatable.searchPlaceholder": "\u641C\u7D22\u2026",
309
+ "datatable.selectAll": "\u5168\u9009",
310
+ "datatable.selectRow": "\u9009\u62E9\u8BE5\u884C",
311
+ "datatable.selectedCount": "\u5DF2\u9009 {p0} \u9879",
312
+ "datatable.totalCount": "\u5171 {p0} \u6761",
313
+ "datatable.totalLabel": "\u5408\u8BA1",
314
+ /* ── datePicker ── */
315
+ "datePicker.noDates": "\u6CA1\u6709\u53EF\u9009\u65E5\u671F",
316
+ "datePicker.clear": "\u6E05\u9664",
317
+ "datePicker.nextMonth": "\u4E0B\u4E00\u6708",
318
+ "datePicker.prevMonth": "\u4E0A\u4E00\u6708",
319
+ "datePicker.selectDate": "\u9009\u62E9\u65E5\u671F",
320
+ "datePicker.today": "\u4ECA\u5929",
321
+ "datePicker.weekdays": ["\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u65E5"],
322
+ "datePicker.weekdaysSunFirst": ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"],
323
+ "datePicker.yearMonth": "{p0} \u5E74 {p1} \u6708",
324
+ /* ── formValidate ── */
325
+ "formValidate.email": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u90AE\u7BB1\u5730\u5740",
326
+ "formValidate.invalid": "\u8F93\u5165\u4E0D\u5408\u6CD5",
327
+ "formValidate.matches": "\u4E24\u6B21\u8F93\u5165\u4E0D\u4E00\u81F4",
328
+ "formValidate.max": "\u4E0D\u80FD\u5927\u4E8E {max}",
329
+ "formValidate.maxlength": "\u6700\u591A\u8F93\u5165 {max} \u4E2A\u5B57\u7B26",
330
+ "formValidate.min": "\u4E0D\u80FD\u5C0F\u4E8E {min}",
331
+ "formValidate.minlength": "\u81F3\u5C11\u8F93\u5165 {min} \u4E2A\u5B57\u7B26",
332
+ "formValidate.number": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57",
333
+ "formValidate.pattern": "\u8F93\u5165\u683C\u5F0F\u4E0D\u6B63\u786E",
334
+ "formValidate.required": "\u6B64\u9879\u4E3A\u5FC5\u586B\u9879",
335
+ "formValidate.selectPlaceholder": "\u8BF7\u9009\u62E9",
336
+ "formValidate.step": "\u6570\u503C\u5FC5\u987B\u662F {step} \u7684\u500D\u6570",
337
+ "formValidate.summary": "\u8868\u5355\u6709 {p0} \u9879\u5185\u5BB9\u9700\u8981\u4FEE\u6B63\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u65B0\u63D0\u4EA4",
338
+ "formValidate.tool.description": "\u5411\u7528\u6237\u6E32\u67D3\u4E00\u4E2A\u7ED3\u6784\u5316\u8868\u5355\u6536\u96C6\u8F93\u5165",
339
+ "formValidate.tool.fields": "\u5B57\u6BB5\u5217\u8868",
340
+ "formValidate.tool.help": "\u5B57\u6BB5\u4E0B\u65B9\u7684\u5E2E\u52A9\u6587\u6848",
341
+ "formValidate.tool.label": "\u5B57\u6BB5\u6807\u7B7E",
342
+ "formValidate.tool.max": "\u6700\u5927\u503C\uFF08number \u7528\uFF09",
343
+ "formValidate.tool.min": "\u6700\u5C0F\u503C\uFF08number \u7528\uFF09",
344
+ "formValidate.tool.name": "\u5B57\u6BB5\u540D\uFF08\u63D0\u4EA4\u503C\u7684 key\uFF09",
345
+ "formValidate.tool.options": "select \u9009\u9879\uFF08\u5B57\u7B26\u4E32\u6216 {label,value}\uFF09",
346
+ "formValidate.tool.pattern": "\u6B63\u5219\u7EA6\u675F\uFF08HTML pattern \u8BED\u6CD5\uFF0C\u6574\u4E32\u5339\u914D\uFF09",
347
+ "formValidate.tool.required": "\u662F\u5426\u5FC5\u586B",
348
+ "formValidate.tool.submitText": "\u63D0\u4EA4\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4\u300C\u63D0\u4EA4\u300D",
349
+ "formValidate.tool.title": "\u8868\u5355\u6807\u9898\uFF08\u53EF\u9009\uFF09",
350
+ "formValidate.tool.type": "\u63A7\u4EF6\u7C7B\u578B\uFF0C\u9ED8\u8BA4 text",
351
+ "formValidate.url": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u94FE\u63A5\u5730\u5740",
352
+ /* ── input ── */
353
+ "input.clearSearch": "\u6E05\u7A7A\u641C\u7D22",
354
+ "input.hidePassword": "\u9690\u85CF\u5BC6\u7801",
355
+ "input.otpPosition": "\u7B2C {p0} \u4F4D\uFF0C\u5171 {p1} \u4F4D",
356
+ "panel.expand": "\u5C55\u5F00",
357
+ "panel.collapse": "\u6298\u53E0",
358
+ "input.showPassword": "\u663E\u793A\u5BC6\u7801",
359
+ /* ── kbAccess ── */
360
+ "kbAccess.approveTip": "\u6279\u51C6\u8BE5\u8BBF\u95EE\u7533\u8BF7",
361
+ "kbAccess.approvedBadge": "\u5DF2\u6279\u51C6 \xB7 {p0}",
362
+ "kbAccess.approverNotePlaceholder": "\u7ED9\u8BF7\u6C42\u4EBA\u7684\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
363
+ "kbAccess.daysLeft": "{p0} \u5929\u540E",
364
+ "kbAccess.defaultSubject": "\u8BE5\u5185\u5BB9",
365
+ "kbAccess.deniedHint": "\u672A\u901A\u8FC7\u2014\u2014\u53EF\u8C03\u6574\u7406\u7531\u540E\u91CD\u65B0\u7533\u8BF7",
366
+ "kbAccess.denyNoteLabel": "\u62D2\u7EDD\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
367
+ "kbAccess.duration30d": "30 \u5929",
368
+ "kbAccess.duration7d": "7 \u5929",
369
+ "kbAccess.durationForever": "\u6C38\u4E45",
370
+ "kbAccess.durationLabel": "\u8BBF\u95EE\u65F6\u957F",
371
+ "kbAccess.expired": "\u5DF2\u5230\u671F",
372
+ "kbAccess.expiresAt": "{p0}\u5230\u671F",
373
+ "kbAccess.grantAsPrefix": "\u6279\u51C6\u4E3A{p0}",
374
+ "kbAccess.grantRoleLabel": "\u6279\u51C6\u89D2\u8272",
375
+ "kbAccess.hoursLeft": "{p0} \u5C0F\u65F6\u540E",
376
+ "kbAccess.minutesLeft": "{p0} \u5206\u949F\u540E",
377
+ "kbAccess.ownerLabel": "\u5185\u5BB9\u8D1F\u8D23\u4EBA",
378
+ "kbAccess.ownerPrefix": "\u8D1F\u8D23\u4EBA\uFF1A{p0}",
379
+ "kbAccess.reapply": "\u91CD\u65B0\u7533\u8BF7",
380
+ "kbAccess.reasonLabel": "\u7533\u8BF7\u7406\u7531",
381
+ "kbAccess.reasonPlaceholder": "\u8BF4\u660E\u4E1A\u52A1\u539F\u56E0\uFF08\u5BA1\u6279\u4EBA\u53EF\u89C1\uFF09",
382
+ "kbAccess.rejectTip": "\u62D2\u7EDD\u8BE5\u8BBF\u95EE\u7533\u8BF7",
383
+ "kbAccess.requestRenewal": "\u7533\u8BF7\u7EED\u671F",
384
+ "kbAccess.requestToPrefix": "\u8BF7\u6C42\u5C06\u53D1\u9001\u7ED9\uFF1A{p0}",
385
+ "kbAccess.restrictedContent": "\u53D7\u9650\u5185\u5BB9",
386
+ "kbAccess.restrictedHint": "\u6B64\u5185\u5BB9\u4EC5\u5BF9\u6388\u6743\u8005\u5F00\u653E",
387
+ "kbAccess.revokedHint": "\u8BBF\u95EE\u5DF2\u88AB\u6536\u56DE",
388
+ "kbAccess.roleLabel": "\u7533\u8BF7\u89D2\u8272",
389
+ "kbAccess.submitRequest": "\u63D0\u4EA4\u7533\u8BF7",
390
+ "kbAccess.switchIdentity": "\u5207\u6362\u8EAB\u4EFD",
391
+ "kbAccess.switchIdentityTip": "\u5207\u6362\u8EAB\u4EFD\u540E\u91CD\u65B0\u68C0\u67E5\u6743\u9650",
392
+ "kbAccess.unknownRequester": "\u672A\u77E5\u8BF7\u6C42\u4EBA",
393
+ "kbAccess.waitingApproval": "\u7B49\u5F85 {p0} \u5BA1\u6279",
394
+ /* ── kbAcl ── */
395
+ "kbAcl.breakHint": "\u505C\u6B62\u4ECE\u7236\u7EA7\u7EE7\u627F\uFF0C\u6539\u4E3A\u72EC\u7ACB\u7BA1\u7406\u672C\u9879\u6743\u9650",
396
+ "kbAcl.breakInheritance": "\u505C\u6B62\u7EE7\u627F",
397
+ "kbAcl.brokenNotice": "\u5DF2\u505C\u6B62\u7EE7\u627F\u2014\u2014\u672C\u9879\u6743\u9650\u72EC\u7ACB\u4E8E\u7236\u7EA7",
398
+ "kbAcl.detachedChildren": "{p0}\uFF1A{p1} \u4E2A\u5B50\u9879\u5DF2\u8131\u79BB",
399
+ "kbAcl.directAccess": "\u76F4\u63A5\u8BBF\u95EE",
400
+ "kbAcl.exception": "\u4F8B\u5916",
401
+ "kbAcl.expiredOn": "\u5DF2\u8FC7\u671F\uFF08{p0}\uFF09",
402
+ "kbAcl.expiresIn": "{p0} \u5230\u671F",
403
+ "kbAcl.grantAccess": "\u6388\u4E88\u8BBF\u95EE",
404
+ "kbAcl.inheritedFrom": "\u7EE7\u627F\u81EA {p0}",
405
+ "kbAcl.inheritedFromLabel": "\u7EE7\u627F\u81EA",
406
+ "kbAcl.linkAccess": "\u94FE\u63A5\u8BBF\u95EE",
407
+ "kbAcl.noDirect": "\u6682\u65E0\u76F4\u63A5\u6388\u6743",
408
+ "kbAcl.noLinks": "\u65E0\u94FE\u63A5",
409
+ "kbAcl.removeEntry": "\u79FB\u9664 {p0}",
410
+ "kbAcl.restoreHint": "\u6062\u590D\u7EE7\u627F\u5C06\u4E22\u5F03\u672C\u9879\u81EA\u5B9A\u4E49\u7684\u6743\u9650",
411
+ "kbAcl.restoreInheritance": "\u6062\u590D\u7EE7\u627F",
412
+ "kbAcl.rootNotice": "\u6839\u7EA7\u8D44\u6E90\u2014\u2014\u65E0\u7236\u7EA7\u7EE7\u627F",
413
+ "kbAcl.systemBadge": "\u7CFB\u7EDF\u7BA1\u7406",
414
+ "kbAcl.systemNote": "\u7CFB\u7EDF\u81EA\u52A8\uFF0C\u4E0D\u53EF\u624B\u5DE5\u79FB\u9664",
415
+ "kbAcl.unnamedResource": "\u672A\u547D\u540D\u8D44\u6E90",
416
+ "kbAcl.visibleToCount": "\u5BF9 {p0} \u4EBA\u53EF\u89C1",
417
+ /* ── kbAnswer ── */
418
+ "kbAnswer.chartBar": "\u67F1\u72B6",
419
+ "kbAnswer.chartLine": "\u6298\u7EBF",
420
+ "kbAnswer.chartPie": "\u997C\u56FE",
421
+ "kbAnswer.exportNoun": "\u5BFC\u51FA {p0}",
422
+ "kbAnswer.filtered": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4",
423
+ "kbAnswer.filteredDetail": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4\uFF1A{p0}",
424
+ "kbAnswer.followups": "\u8FFD\u95EE\u5EFA\u8BAE",
425
+ "kbAnswer.hitAssets": "\u547D\u4E2D\u8D44\u4EA7\uFF1A{p0}",
426
+ "kbAnswer.kindCurated": "\u4EBA\u5DE5\u7B56\u5C55",
427
+ "kbAnswer.kindFunction": "\u51FD\u6570",
428
+ "kbAnswer.kindParameterized": "\u53C2\u6570\u5316\u67E5\u8BE2",
429
+ "kbAnswer.maskedPrefix": "\u5DF2\u8131\u654F\u5217\uFF1A",
430
+ "kbAnswer.rerunTip": "\u53C2\u6570\u53EF\u6539\u91CD\u8DD1",
431
+ "kbAnswer.truncated": "\u5DF2\u622A\u65AD\uFF1A\u663E\u793A {p0}/{p1} \u884C{p2}",
432
+ "kbAnswer.verifiedBadge": "\u8BA4\u8BC1\u7B54\u6848",
433
+ /* ── kbAudit ── */
434
+ "kbAudit.actionDetail": "\u5904\u7F6E\uFF1A{p0} \xB7 {p1}",
435
+ "kbAudit.actionLabel": "\u5904\u7F6E",
436
+ "kbAudit.alertedNote": "\u5DF2\u5B9E\u65F6\u544A\u8B66\u5B89\u5168\u56E2\u961F",
437
+ "kbAudit.channelFilterAria": "\u5BA1\u8BA1\u901A\u9053\u8FC7\u6EE4",
438
+ "kbAudit.channelPermission": "\u6743\u9650\u53D8\u66F4",
439
+ "kbAudit.channelRead": "\u8BFB\u53D6",
440
+ "kbAudit.channelRequest": "\u7533\u8BF7",
441
+ "kbAudit.channelSystem": "\u7CFB\u7EDF",
442
+ "kbAudit.empty": "\u6682\u65E0\u5BA1\u8BA1\u4E8B\u4EF6",
443
+ "kbAudit.exportTip": "\u5BFC\u51FA\u5F53\u524D\u8FC7\u6EE4\u89C6\u56FE\u4E3A CSV",
444
+ "kbAudit.hygieneLabel": "\u6743\u9650\u5F02\u5473",
445
+ "kbAudit.noHygiene": "\u672A\u53D1\u73B0\u6743\u9650\u5F02\u5473",
446
+ /* ── kbCanvas ── */
447
+ "kbCanvas.splitterAria": "\u8C03\u6574\u753B\u5E03\u53CC\u680F\u6BD4\u4F8B",
448
+ "kbCanvas.splitterTip": "\u62D6\u62FD\u8C03\u6574\u6BD4\u4F8B\uFF08\u2190/\u2192 \u5FAE\u8C03\uFF0C\u53CC\u51FB\u590D\u4F4D\uFF09",
449
+ /* ── kbCheckpoint ── */
450
+ "kbCheckpoint.chatAuditNote": "\u8BA8\u8BBA\u5386\u53F2\u6709\u5BA1\u8BA1\u4EF7\u503C",
451
+ "kbCheckpoint.label": "\u68C0\u67E5\u70B9",
452
+ "kbCheckpoint.restore": "\u6062\u590D\u68C0\u67E5\u70B9",
453
+ "kbCheckpoint.scopeBoth": "\u5185\u5BB9\u4E0E\u5BF9\u8BDD",
454
+ "kbCheckpoint.scopeChat": "\u4EC5\u5BF9\u8BDD",
455
+ "kbCheckpoint.scopeContent": "\u4EC5\u5185\u5BB9\uFF08\u4FDD\u7559\u5BF9\u8BDD\uFF09",
456
+ "kbCheckpoint.scopeMissing": "\u8BE5\u68C0\u67E5\u70B9\u672A\u5305\u542B\u6B64\u6062\u590D\u8303\u56F4",
457
+ /* ── kbChunks ── */
458
+ "kbChunks.addKeyword": "+ \u5173\u952E\u8BCD",
459
+ "kbChunks.chunkAddKeywordAria": "chunk {p0} \u65B0\u589E\u5173\u952E\u8BCD",
460
+ "kbChunks.chunkContentAria": "chunk {p0} \u5185\u5BB9",
461
+ "kbChunks.chunkEnableAria": "chunk {p0} \u542F\u7528",
462
+ "kbChunks.deleteChunkAria": "\u5220\u9664 chunk {p0}",
463
+ "kbChunks.disableNote": "\u5173\u95ED\u540E\u4E0D\u5220\u9664\uFF0C\u4EC5\u6392\u9664\u51FA\u68C0\u7D22",
464
+ "kbChunks.edited": "\u5DF2\u7F16\u8F91",
465
+ "kbChunks.empty": "\u6682\u65E0 chunk",
466
+ "kbChunks.modeFull": "\u5168\u6587",
467
+ "kbChunks.modeLabel": "\u641C\u7D22\u6A21\u5F0F",
468
+ "kbChunks.modeVector": "\u8BED\u4E49",
469
+ "kbChunks.removeKeyword": "\u79FB\u9664\u5173\u952E\u8BCD {p0}",
470
+ "kbChunks.searchAria": "\u641C\u7D22 chunk",
471
+ "kbChunks.searchFullPlaceholder": "\u5168\u6587\u641C\u7D22 chunk\u2026",
472
+ "kbChunks.searchVectorPlaceholder": "\u8BED\u4E49\u641C\u7D22 chunk\u2026",
473
+ /* ── kbCitation ── */
474
+ "kbCitation.sourceN": "\u6765\u6E90 {p0}",
475
+ "kbCitation.unavailable": "\u6765\u6E90\u5DF2\u4E0D\u53EF\u7528",
476
+ /* ── kbClarify ── */
477
+ "kbClarify.parsedPrefix": "\u5DF2\u89E3\u6790\uFF1A",
478
+ /* ── kbConflict ── */
479
+ "kbConflict.owner": "\u8D23\u4EFB\u4EBA {p0}",
480
+ /* ── kbConnector ── */
481
+ "kbConnector.changeRate": "\u53D8\u66F4\u7387",
482
+ "kbConnector.crawlRate": "\u6293\u53D6\u7387",
483
+ "kbConnector.credentials": "\u51ED\u8BC1",
484
+ "kbConnector.credentialsExpired": "\u51ED\u8BC1\u8FC7\u671F",
485
+ "kbConnector.editSchedule": "\u7F16\u8F91\u8BA1\u5212",
486
+ "kbConnector.empty": "\u6682\u65E0\u8FDE\u63A5\u5668",
487
+ "kbConnector.failing": "\u5F02\u5E38",
488
+ "kbConnector.lastSync": "\u6700\u8FD1\u540C\u6B65 {p0}",
489
+ "kbConnector.neverSynced": "\u4ECE\u672A\u540C\u6B65",
490
+ "kbConnector.notConfigured": "\u672A\u914D\u7F6E",
491
+ "kbConnector.off": "\u5DF2\u505C\u7528",
492
+ "kbConnector.perDay": "{p0}/\u5929",
493
+ "kbConnector.reauth": "\u91CD\u65B0\u6388\u6743",
494
+ "kbConnector.stale": "\u505C\u6EDE",
495
+ "kbConnector.syncNow": "\u7ACB\u5373\u540C\u6B65",
496
+ "kbConnector.synced": "\u5DF2\u540C\u6B65",
497
+ /* ── kbCore ── */
498
+ "kbCore.accessDenied": "\u672A\u901A\u8FC7",
499
+ "kbCore.accessExpired": "\u5DF2\u8FC7\u671F",
500
+ "kbCore.accessExpiring": "\u5373\u5C06\u5230\u671F",
501
+ "kbCore.accessGranted": "\u5DF2\u5F00\u901A",
502
+ "kbCore.accessNotRequested": "\u672A\u7533\u8BF7",
503
+ "kbCore.accessPending": "\u5F85\u5BA1\u6279",
504
+ "kbCore.accessRequested": "\u5DF2\u63D0\u4EA4",
505
+ "kbCore.accessRevoked": "\u5DF2\u6536\u56DE",
506
+ "kbCore.auditApprove": "\u6279\u51C6",
507
+ "kbCore.auditBreakGlass": "\u5E94\u6025\u8BBF\u95EE",
508
+ "kbCore.auditDelegation": "\u59D4\u6D3E",
509
+ "kbCore.auditDeny": "\u62D2\u7EDD",
510
+ "kbCore.auditGrant": "\u6388\u4E88",
511
+ "kbCore.auditPermissionChange": "\u6743\u9650\u53D8\u66F4",
512
+ "kbCore.auditPreview": "\u9884\u89C8",
513
+ "kbCore.auditRead": "\u8BFB\u53D6",
514
+ "kbCore.auditRequest": "\u7533\u8BF7",
515
+ "kbCore.auditRevoke": "\u6536\u56DE",
516
+ "kbCore.auditSync": "\u6743\u9650\u540C\u6B65",
517
+ "kbCore.daysAgo": "{p0} \u5929\u524D",
518
+ "kbCore.hoursAgo": "{p0} \u5C0F\u65F6\u524D",
519
+ "kbCore.hygieneBroadGroup": "\u8FC7\u5BBD\u7EC4\u6388\u6743",
520
+ "kbCore.hygieneBrokenInheritance": "\u65AD\u7EE7\u627F",
521
+ "kbCore.hygieneOrgWideLink": "\u7EC4\u7EC7\u7EA7\u94FE\u63A5",
522
+ "kbCore.hygieneOrphanedOwner": "\u8D1F\u8D23\u4EBA\u7F3A\u4F4D",
523
+ "kbCore.hygieneOverexposed": "\u8FC7\u5EA6\u66B4\u9732",
524
+ "kbCore.hygieneSensitiveMismatch": "\u654F\u611F\u5EA6\u9519\u914D",
525
+ "kbCore.justNow": "\u521A\u521A",
526
+ "kbCore.levelComment": "\u53EF\u8BC4\u8BBA",
527
+ "kbCore.levelEdit": "\u53EF\u7F16\u8F91",
528
+ "kbCore.levelNone": "\u65E0\u6743\u9650",
529
+ "kbCore.levelOwner": "\u8D1F\u8D23\u4EBA",
530
+ "kbCore.levelView": "\u53EF\u67E5\u770B",
531
+ "kbCore.minutesAgo": "{p0} \u5206\u949F\u524D",
532
+ "kbCore.runCancelled": "\u5DF2\u53D6\u6D88",
533
+ "kbCore.runDone": "\u5DF2\u5B8C\u6210",
534
+ "kbCore.runFailed": "\u5931\u8D25",
535
+ "kbCore.runQueued": "\u6392\u961F\u4E2D",
536
+ "kbCore.runRunning": "\u8FDB\u884C\u4E2D",
537
+ "kbCore.runUnstarted": "\u672A\u5F00\u59CB",
538
+ "kbCore.stageAgent": "\u4EE3\u7406",
539
+ "kbCore.stageChunk": "\u5207\u7247",
540
+ "kbCore.stageEmbed": "\u5411\u91CF\u5316",
541
+ "kbCore.stageGeneration": "\u751F\u6210",
542
+ "kbCore.stageGuard": "\u62A4\u680F",
543
+ "kbCore.stageQuery": "\u67E5\u8BE2",
544
+ "kbCore.stageRerank": "\u91CD\u6392",
545
+ "kbCore.stageRetrieval": "\u68C0\u7D22",
546
+ "kbCore.stageTool": "\u5DE5\u5177",
547
+ "kbCore.typeApi": "\u63A5\u53E3",
548
+ "kbCore.typeCode": "\u4EE3\u7801",
549
+ "kbCore.typeDatabase": "\u6570\u636E\u5E93",
550
+ "kbCore.typeDocument": "\u6587\u6863",
551
+ "kbCore.typeEmail": "\u90AE\u4EF6",
552
+ "kbCore.typeImage": "\u56FE\u7247",
553
+ "kbCore.typeKb": "\u77E5\u8BC6\u5E93",
554
+ "kbCore.typeTable": "\u8868\u683C",
555
+ "kbCore.typeTicket": "\u5DE5\u5355",
556
+ "kbCore.typeWebpage": "\u7F51\u9875",
557
+ "kbCore.unnamedSource": "\u672A\u547D\u540D\u6765\u6E90",
558
+ "kbCore.unnamedSubject": "\u672A\u547D\u540D\u4E3B\u4F53",
559
+ "kbCore.visHidden": "\u4E0D\u53EF\u89C1",
560
+ "kbCore.visMetadataOnly": "\u4EC5\u5143\u6570\u636E",
561
+ "kbCore.visSummaryOnly": "\u4EC5\u6458\u8981",
562
+ "kbCore.visVisible": "\u53EF\u89C1",
563
+ /* ── kbEval ── */
564
+ "kbEval.avgA": "A \u5747\u5206 {p0}",
565
+ "kbEval.avgB": "B \u5747\u5206 {p0}",
566
+ "kbEval.compare": "\u5BF9\u6BD4",
567
+ "kbEval.runSelectAria": "\u9009\u62E9\u5BF9\u6BD4\u8FD0\u884C",
568
+ "kbEval.expected": "\u671F\u671B",
569
+ "kbEval.gradeImprovement": "\u63D0\u5347",
570
+ "kbEval.gradeRegression": "\u56DE\u5F52",
571
+ "kbEval.gradeTie": "\u6301\u5E73",
572
+ "kbEval.gradeTradeoff": "\u6743\u8861",
573
+ "kbEval.noData": "\u6CA1\u6709\u5BF9\u6BD4\u6570\u636E",
574
+ "kbEval.onlyRegression": "\u4EC5\u770B\u56DE\u5F52",
575
+ "kbEval.outputA": "\u8F93\u51FA A",
576
+ "kbEval.outputB": "\u8F93\u51FA B",
577
+ "kbEval.outputN": "\u8F93\u51FA {p0}",
578
+ /* ── kbExplain ── */
579
+ "kbExplain.empty": "\u6682\u65E0\u53E3\u5F84\u4FE1\u606F",
580
+ "kbExplain.groupAgg": "\u805A\u5408",
581
+ "kbExplain.groupColumn": "\u5217",
582
+ "kbExplain.groupFilter": "\u7B5B\u9009",
583
+ "kbExplain.groupTable": "\u8868",
584
+ "kbExplain.trigger": "\u8FD9\u4E2A\u6570\u5B57\u662F\u600E\u4E48\u7B97\u51FA\u6765\u7684",
585
+ "kbExplain.viewDefinition": "\u67E5\u770B\u53E3\u5F84",
586
+ /* ── kbFilter ── */
587
+ "kbFilter.addGroup": "+ \u7EC4",
588
+ "kbFilter.addRule": "+ \u89C4\u5219",
589
+ "kbFilter.and": "\u4E14",
590
+ "kbFilter.combineMode": "\u7EC4\u5408\u65B9\u5F0F {p0}",
591
+ "kbFilter.copyDsl": "\u590D\u5236 DSL",
592
+ "kbFilter.deleteGroup": "\u5220\u9664\u7EC4",
593
+ "kbFilter.deleteRule": "\u5220\u9664\u89C4\u5219",
594
+ "kbFilter.fieldLabel": "\u5B57\u6BB5",
595
+ "kbFilter.fieldPlaceholder": "\u8FC7\u6EE4\u5B57\u6BB5",
596
+ "kbFilter.noValueNeeded": "\uFF08\u65E0\u9700\u503C\uFF09",
597
+ "kbFilter.none": "\uFF08\u65E0\u8FC7\u6EE4\uFF09",
598
+ "kbFilter.opContains": "\u5305\u542B",
599
+ "kbFilter.opEq": "\u7B49\u4E8E",
600
+ "kbFilter.opExists": "\u5B58\u5728",
601
+ "kbFilter.opGt": "\u5927\u4E8E",
602
+ "kbFilter.opGte": "\u5927\u4E8E\u7B49\u4E8E",
603
+ "kbFilter.opIn": "\u5C5E\u4E8E",
604
+ "kbFilter.opLt": "\u5C0F\u4E8E",
605
+ "kbFilter.opLte": "\u5C0F\u4E8E\u7B49\u4E8E",
606
+ "kbFilter.opNe": "\u4E0D\u7B49\u4E8E",
607
+ "kbFilter.operatorLabel": "\u64CD\u4F5C\u7B26",
608
+ "kbFilter.or": "\u6216",
609
+ "kbFilter.toggleAndOr": "\u5207\u6362 AND / OR",
610
+ "kbFilter.valueAria": "\u8FC7\u6EE4\u503C",
611
+ "kbFilter.valueLabel": "\u503C",
612
+ "kbFilter.valuePlaceholder": "\u503C 1, \u503C 2\uFF08\u9017\u53F7\u5206\u9694\uFF09",
613
+ /* ── kbGap ── */
614
+ "kbGap.addSynonym": "\u52A0\u540C\u4E49\u8BCD",
615
+ "kbGap.colCount": "\u6B21\u6570",
616
+ "kbGap.colLastSeen": "\u6700\u8FD1\u51FA\u73B0",
617
+ "kbGap.colQuery": "\u67E5\u8BE2",
618
+ "kbGap.colShare": "\u5360\u6BD4",
619
+ "kbGap.createDoc": "\u5EFA\u6587\u6863",
620
+ "kbGap.empty": "\u6CA1\u6709\u672A\u547D\u4E2D\u67E5\u8BE2\u2014\u2014\u8986\u76D6\u826F\u597D",
621
+ "kbGap.title": "\u672A\u547D\u4E2D\u67E5\u8BE2\u8D8B\u52BF",
622
+ "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",
623
+ "kbGap.zeroClickRate": "\u96F6\u70B9\u51FB\u7387",
624
+ "kbGap.zeroClickTitle": "\u96F6\u70B9\u51FB \u2260 \u5931\u8D25",
625
+ /* ── kbHittest ── */
626
+ "kbHittest.addAria": "\u65B0\u589E\u6D4B\u8BD5\u95EE\u9898",
627
+ "kbHittest.addPlaceholder": "\u65B0\u589E\u95EE\u9898\uFF0CEnter \u6DFB\u52A0",
628
+ "kbHittest.avgScore": "\u5747\u5206",
629
+ "kbHittest.deleteQuestion": "\u5220\u9664\u95EE\u9898",
630
+ "kbHittest.empty": "\u6682\u65E0\u6D4B\u8BD5\u95EE\u9898\u2014\u2014\u6DFB\u52A0\u7B2C\u4E00\u6761\uFF0C\u5F00\u59CB\u53EC\u56DE\u56DE\u5F52",
631
+ "kbHittest.expectHit": "\u671F\u671B\u547D\u4E2D\u5728\u524D\u6392\u547D\u4E2D\u4E2D",
632
+ "kbHittest.expectMiss": "\u671F\u671B\u672A\u547D\u4E2D",
633
+ "kbHittest.hitRate": "\u547D\u4E2D\u7387",
634
+ "kbHittest.noExpectation": "\u672A\u8BBE\u671F\u671B",
635
+ "kbHittest.notRun": "\u672A\u8FD0\u884C",
636
+ "kbHittest.pass": "\u901A\u8FC7",
637
+ "kbHittest.pin": "\u7F6E\u9876\u56FA\u5B9A",
638
+ "kbHittest.runAll": "\u8FD0\u884C\u5168\u90E8",
639
+ "kbHittest.sessionOnly": "\u53C2\u6570\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
640
+ "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",
641
+ "kbHittest.unpin": "\u53D6\u6D88\u7F6E\u9876",
642
+ /* ── kbMetadata ── */
643
+ "kbMetadata.addField": "\u65B0\u589E\u5B57\u6BB5",
644
+ "kbMetadata.builtIn": "\u5185\u7F6E",
645
+ "kbMetadata.colField": "\u5B57\u6BB5",
646
+ "kbMetadata.colType": "\u7C7B\u578B",
647
+ "kbMetadata.colValue": "\u503C",
648
+ "kbMetadata.empty": "\u6682\u65E0\u5143\u6570\u636E\u5B57\u6BB5",
649
+ "kbMetadata.nameLabel": "\u65B0\u5B57\u6BB5\u540D",
650
+ "kbMetadata.namePlaceholder": "\u5B57\u6BB5\u540D\uFF0C\u5982 department",
651
+ "kbMetadata.removeField": "\u79FB\u9664\u5B57\u6BB5 {p0}",
652
+ "kbMetadata.typeLabel": "\u65B0\u5B57\u6BB5\u7C7B\u578B",
653
+ "kbMetadata.valueOf": "{p0} \u7684\u503C",
654
+ /* ── kbPassage ── */
655
+ "kbPassage.blockRange": "\u5757 {p0}\u2013{p1}",
656
+ "kbPassage.close": "\u5173\u95ED\u539F\u6587",
657
+ "kbPassage.expandContext": "\u5C55\u5F00\u4E0A\u4E0B\u6587",
658
+ "kbPassage.locate": "\u539F\u6587\u5B9A\u4F4D",
659
+ "kbPassage.none": "\uFF08\u65E0\u539F\u6587\uFF09",
660
+ "kbPassage.pageRange": "\u7B2C {p0}\u2013{p1} \u9875",
661
+ "kbPassage.restricted": "\u5185\u5BB9\u53D7\u9650",
662
+ "kbPassage.unitByte": "\u5B57\u8282",
663
+ "kbPassage.unitChar": "\u5B57\u7B26",
664
+ /* ── kbPipeline ── */
665
+ "kbPipeline.empty": "\u6682\u65E0\u89E3\u6790\u4EFB\u52A1",
666
+ "kbPipeline.progress": "\u89E3\u6790\u8FDB\u5EA6",
667
+ "kbPipeline.rerun": "\u91CD\u8DD1",
668
+ "kbPipeline.unknownStage": "\u672A\u77E5\u9636\u6BB5",
669
+ /* ── kbQa ── */
670
+ "kbQa.colAnswer": "\u7B54\u6848",
671
+ "kbQa.colQuestion": "\u95EE\u9898",
672
+ "kbQa.csvHint": "CSV \u6A21\u677F\uFF1Aquestion,answer\uFF08\u6BCF\u884C\u4E00\u5BF9\uFF0CUTF-8\uFF09",
673
+ "kbQa.deleteRow": "\u5220\u9664\u7B2C {p0} \u884C",
674
+ "kbQa.empty": "\u6682\u65E0\u8BA4\u8BC1\u95EE\u7B54\u5BF9",
675
+ "kbQa.importCsv": "\u5BFC\u5165 CSV",
676
+ /* ── kbRerank ── */
677
+ "kbRerank.after": "\u91CD\u6392\u540E",
678
+ "kbRerank.before": "\u91CD\u6392\u524D",
679
+ "kbRerank.compareTitle": "\u91CD\u6392\u5BF9\u6BD4",
680
+ "kbRerank.down": "\u4E0B\u964D {p0} \u4F4D",
681
+ "kbRerank.dropped": "\u843D\u9009",
682
+ "kbRerank.empty": "\u4E24\u4FA7\u5747\u4E3A\u7A7A\u2014\u2014\u8FD0\u884C\u68C0\u7D22\u540E\u518D\u5BF9\u6BD4",
683
+ "kbRerank.enableCompare": "\u542F\u7528\u91CD\u6392\u5BF9\u6BD4",
684
+ "kbRerank.newIn": "\u65B0\u8FDB",
685
+ "kbRerank.unmarked": "\u672A\u6807",
686
+ "kbRerank.up": "\u4E0A\u5347 {p0} \u4F4D",
687
+ /* ── kbRetrieval ── */
688
+ "kbRetrieval.breakdown": "\u62C6\u89E3",
689
+ "kbRetrieval.copyParams": "\u590D\u5236\u53C2\u6570 JSON",
690
+ "kbRetrieval.decreaseTopK": "\u51CF\u5C11 topK",
691
+ "kbRetrieval.empty": "\u8F93\u5165\u95EE\u9898\u5E76\u8FD0\u884C\uFF0C\u547D\u4E2D\u7ED3\u679C\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
692
+ "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",
693
+ "kbRetrieval.hybridWeight": "\u6DF7\u5408\u6743\u91CD\uFF08\u5DE6\u8BED\u4E49\u53F3\u5173\u952E\u8BCD\uFF09",
694
+ "kbRetrieval.identityLabel": "\u68C0\u7D22\u8EAB\u4EFD",
695
+ "kbRetrieval.identityShort": "\u8EAB\u4EFD",
696
+ "kbRetrieval.increaseTopK": "\u589E\u52A0 topK",
697
+ "kbRetrieval.keywordHint": "\u5173\u952E\u8BCD\uFF1A\u5927\u5E93\u5FEB\u901F\u7CBE\u786E",
698
+ "kbRetrieval.layerLabel": "\u8FC7\u6EE4\u5C42",
699
+ "kbRetrieval.layerNone": "none\uFF1Afail-open\uFF0C\u65E0\u8EAB\u4EFD\u8FC7\u6EE4\u8FD4\u56DE\u5168\u90E8\u2014\u2014\u5371\u9669\uFF0C\u4EC5\u6F14\u793A",
700
+ "kbRetrieval.layerPost": "post-filter\uFF1A\u5206\u6570\u5DF2\u53EF\u89C2\u5BDF\u2014\u2014\u7F3A\u9677\u5C42\uFF0C\u4EC5\u6F14\u793A",
701
+ "kbRetrieval.layerPre": "pre-filter\uFF1AACL \u5728\u68C0\u7D22\u6267\u884C\u4F53\u5185\u751F\u6548\u2014\u2014\u5B89\u5168\u57FA\u7EBF",
702
+ "kbRetrieval.leakNote": "\u5206\u6BCD\u672A\u8FC7\u6EE4\u524D\u8BA1\u6570\u5C5E\u6CC4\u9732\uFF0C\u4E0D\u663E\u793A",
703
+ "kbRetrieval.modeHybrid": "\u6DF7\u5408",
704
+ "kbRetrieval.modeKeyword": "\u5173\u952E\u8BCD",
705
+ "kbRetrieval.modeLabel": "\u68C0\u7D22\u6A21\u5F0F",
706
+ "kbRetrieval.modeVector": "\u5411\u91CF",
707
+ "kbRetrieval.postFilterNotice": "post-filter\uFF1A\u5206\u6570\u5DF2\u5728\u8FC7\u6EE4\u524D\u4EA7\u751F\uFF08\u7F3A\u9677\u5C42\u6F14\u793A\uFF09",
708
+ "kbRetrieval.queryLabel": "\u68C0\u7D22\u95EE\u9898",
709
+ "kbRetrieval.queryPlaceholder": "\u68C0\u7D22\u95EE\u9898\uFF0CEnter \u8FD0\u884C",
710
+ "kbRetrieval.rerankLabel": "\u91CD\u6392",
711
+ "kbRetrieval.rerankThresholdOff": "\u9608\u503C \u5173 \xB7 \u5B58\u6D3B {p0}",
712
+ "kbRetrieval.rerankThresholdOn": "\u9608\u503C {p0} \xB7 \u5B58\u6D3B {p1}",
713
+ "kbRetrieval.running": "\u8FD0\u884C\u4E2D\u2026",
714
+ "kbRetrieval.thresholdLabel": "\u5206\u6570\u9608\u503C",
715
+ "kbRetrieval.thresholdValue": "\u9608\u503C N/A",
716
+ "kbRetrieval.vectorHint": "\u8BED\u4E49\uFF1A\u8DE8\u8BED\u8A00/\u65E0\u7CBE\u786E\u8BCD",
717
+ "kbRetrieval.vectorPercent": "\u8BED\u4E49 {p0}",
718
+ "kbRetrieval.weightValue": "\u5411\u91CF {p0}% / \u5173\u952E\u8BCD {p1}%",
719
+ /* ── kbReview ── */
720
+ "kbReview.assignee": "\u5206\u914D\u4EBA",
721
+ "kbReview.doneNext": "\u5B8C\u6210\u5E76\u4E0B\u4E00\u6761",
722
+ "kbReview.empty": "\u6CA1\u6709\u5F85\u5BA1\u67E5\u6761\u76EE",
723
+ "kbReview.emptyAssignee": "\u8BE5\u5206\u914D\u4EBA\u4E0B\u6CA1\u6709\u6761\u76EE",
724
+ "kbReview.emptyQueue": "\u961F\u5217\u4E3A\u7A7A",
725
+ "kbReview.kbCloseHint": "\u5173\u95ED\u63D0\u793A",
726
+ "kbReview.kbSelectOption": "\u9009\u62E9\u9009\u9879",
727
+ "kbReview.kbSwitchItem": "\u5207\u6362\u6761\u76EE",
728
+ "kbReview.kbToggleHint": "\u663E\u793A/\u9690\u85CF\u672C\u63D0\u793A",
729
+ "kbReview.shortcuts": "? \u5FEB\u6377\u952E",
730
+ "kbReview.typeAnswer": "\u56DE\u7B54",
731
+ "kbReview.typeMessage": "\u6D88\u606F",
732
+ "kbReview.typeTrace": "\u8F68\u8FF9",
733
+ "kbReview.unassigned": "\u672A\u5206\u914D",
734
+ /* ── kbSandbox ── */
735
+ "kbSandbox.noResolver": "\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668",
736
+ "kbSandbox.notReady": "kb-sandbox: \u5E94\u7528\u672A\u5C31\u7EEA",
737
+ "kbSandbox.resolveFailed": "ui:// \u89E3\u6790\u5931\u8D25\uFF1A{p0}",
738
+ "kbSandbox.timeout": "kb-sandbox: \u8C03\u7528\u8D85\u65F6\uFF08{p0}ms\uFF09",
739
+ "kbSandbox.title": "MCP App \u6C99\u7BB1",
740
+ /* ── kbSegment ── */
741
+ "kbSegment.avgLength": "\u5747\u957F {p0}",
742
+ "kbSegment.childNote": "\u5B50\u5206\u6BB5\u6309\u957F\u5EA6\u81EA\u52A8\u751F\u6210",
743
+ "kbSegment.cleanBlankLines": "\u5408\u5E76\u8FDE\u7EED\u7A7A\u884C",
744
+ "kbSegment.cleanEmails": "\u53BB\u9664\u90AE\u7BB1",
745
+ "kbSegment.cleanLinks": "\u53BB\u9664\u94FE\u63A5",
746
+ "kbSegment.empty": "\u6837\u672C\u4E3A\u7A7A\uFF0C\u6682\u65E0\u53EF\u9884\u89C8\u5206\u6BB5",
747
+ "kbSegment.maxLengthLabel": "\u6700\u5927\u957F\u5EA6",
748
+ "kbSegment.maxLengthPlaceholder": "\u5206\u6BB5\u6700\u5927\u957F\u5EA6",
749
+ "kbSegment.modeAuto": "\u81EA\u52A8",
750
+ "kbSegment.modeCustom": "\u81EA\u5B9A\u4E49",
751
+ "kbSegment.modeLabel": "\u5206\u6BB5\u6A21\u5F0F",
752
+ "kbSegment.modeNote": "\u5206\u6BB5\u6A21\u5F0F\u521B\u5EFA\u540E\u4E0D\u53EF\u66F4\u6539\uFF0C\u53C2\u6570\u53EF\u968F\u65F6\u8C03\u6574",
753
+ "kbSegment.modeParentChild": "\u7236\u5B50",
754
+ "kbSegment.overlapInvalid": "\u91CD\u53E0\u9700\u5C0F\u4E8E\u6700\u5927\u957F\u5EA6",
755
+ "kbSegment.overlapLabel": "\u91CD\u53E0",
756
+ "kbSegment.overlapPlaceholder": "\u5206\u6BB5\u91CD\u53E0",
757
+ "kbSegment.previewNote": "\u5171 {p0} \u6BB5\uFF0C\u4EC5\u9884\u89C8\u524D {p1} \u6BB5",
758
+ "kbSegment.segmentsCount": "{p0} \u6BB5",
759
+ "kbSegment.separatorLabel": "\u5206\u9694\u7B26",
760
+ "kbSegment.separatorPlaceholder": "\u5206\u6BB5\u5206\u9694\u7B26",
761
+ "kbSegment.toggleTip": "\u70B9\u51FB\u5C55\u5F00/\u6536\u8D77",
762
+ /* ── kbSources ── */
763
+ "kbSources.cited": "\u88AB\u5F15 \xD7{p0}",
764
+ "kbSources.empty": "\u4E0B\u4E00\u6761\u7B54\u6848\u5F15\u7528\u7684\u6BB5\u843D\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
765
+ /* ── kbSql ── */
766
+ "kbSql.adminOnly": "\u4EC5\u7BA1\u7406\u5458\u53EF\u89C1",
767
+ "kbSql.applyFix": "\u5E94\u7528\u4FEE\u590D\u5E76\u91CD\u8DD1",
768
+ "kbSql.confirmRerun": "\u786E\u8BA4\u5E76\u91CD\u8DD1",
769
+ "kbSql.editRerun": "\u7F16\u8F91\u91CD\u8DD1",
770
+ "kbSql.fixReady": "\u68C0\u6D4B\u5230\u4E0A\u7248\u62A5\u9519\uFF0C\u4FEE\u590D\u5EFA\u8BAE\u5DF2\u5C31\u7EEA",
771
+ "kbSql.generated": "\u751F\u6210\u7684 SQL",
772
+ /* ── kbTrace ── */
773
+ "kbTrace.empty": "\u6682\u65E0\u8C03\u7528\u94FE\u6570\u636E",
774
+ "kbTrace.hits": "\u547D\u4E2D {p0}",
775
+ /* ── kbVisibility ── */
776
+ "kbVisibility.adminOnlyNote": "\u4EE5\u4E0A\u5BF9\u7167\u4EC5\u9650 admin \u5BA1\u8BA1",
777
+ "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",
778
+ "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",
779
+ "kbVisibility.focusColumn": "\u805A\u7126\u8EAB\u4EFD {p0} \u7684\u5217",
780
+ "kbVisibility.layerValue": "\u8FC7\u6EE4\u5C42\uFF1A{p0}",
781
+ "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",
782
+ "kbVisibility.postFilterNote": "post-filter\uFF1AtopK \u88AB\u65E0\u6743\u7ED3\u679C\u5360\u7528\u4E14\u76F8\u4F3C\u5EA6\u5206\u6570\u53EF\u88AB\u89C2\u5BDF",
783
+ "kbVisibility.queryLabel": "\u67E5\u8BE2\uFF1A{p0}",
784
+ "kbVisibility.safeCount": "\u5B89\u5168\u8BA1\u6570 {p0}",
785
+ "kbVisibility.sourceUnavailable": "\u539F\u6587\u4E0D\u53EF\u7528",
786
+ "kbVisibility.unnamedHit": "\u672A\u547D\u540D\u547D\u4E2D",
787
+ /* ── kbWhoCan ── */
788
+ "kbWhoCan.check": "\u68C0\u67E5",
789
+ "kbWhoCan.checkIdentity": "\u68C0\u67E5\u8EAB\u4EFD",
790
+ "kbWhoCan.daysUntil": "{p0} \u5929\u540E",
791
+ "kbWhoCan.deniedBy": "\u88AB\u7B56\u7565\u62D2\u7EDD\uFF1A{p0}",
792
+ "kbWhoCan.denyVeto": "\u88AB Deny \u4E00\u7968\u5426\u51B3",
793
+ "kbWhoCan.direct": "\u76F4\u63A5",
794
+ "kbWhoCan.expiresSoon": "\u6700\u8FD1\u5230\u671F {p0}",
795
+ "kbWhoCan.hoursUntil": "{p0} \u5C0F\u65F6\u540E",
796
+ "kbWhoCan.inherit": "\u7EE7\u627F",
797
+ "kbWhoCan.link": "\u94FE\u63A5",
798
+ "kbWhoCan.noDeny": "\u65E0 Deny \u751F\u6548",
799
+ "kbWhoCan.noIdentity": "\u672A\u63D0\u4F9B\u53EF\u68C0\u67E5\u7684\u8EAB\u4EFD",
800
+ "kbWhoCan.none": "\u672A\u547D\u4E2D\u4EFB\u4F55\u6388\u6743\u2014\u2014\u9ED8\u8BA4\u62D2\u7EDD",
801
+ "kbWhoCan.recheckTip": "\u91CD\u65B0\u68C0\u67E5\u5F53\u524D\u8EAB\u4EFD\u7684\u6709\u6548\u6743\u9650",
802
+ "kbWhoCan.stackRule": "\u53E0\u52A0\u89C4\u5219\uFF1A\u591A\u6765\u6E90\u5E76\u96C6 \u2192 {p0}\uFF1B{p1}",
803
+ /* ── mentions ── */
804
+ "mentions.create": "\u521B\u5EFA\u201C{p0}\u201D",
805
+ "mentions.customBadge": "\u81EA\u5B9A\u4E49",
806
+ "mentions.loading": "\u52A0\u8F7D\u4E2D\u2026",
807
+ /* ── notification ── */
808
+ "notification.groupBusy": "\u64CD\u4F5C\u7ED3\u675F\u540E\u53EF\u4EE5\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5\u3002",
809
+ "notification.groupUnread": "{count} \u6761\u540C\u7EC4\u901A\u77E5\uFF0C{unread} \u6761\u672A\u8BFB",
810
+ "notification.groupCount": "{count} \u6761\u540C\u7EC4\u901A\u77E5",
811
+ "notification.groupExpanded": "\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5",
812
+ "notification.ariaLabel": "\u901A\u77E5",
813
+ "notification.viewDetails": "\u67E5\u770B\u8BE6\u60C5",
814
+ /* ── pagination ── */
815
+ "pagination.next": "\u4E0B\u4E00\u9875",
816
+ "pagination.pageSize": "{p0} \u6761/\u9875",
817
+ "pagination.prev": "\u4E0A\u4E00\u9875",
818
+ /* ── select ── */
819
+ "select.fieldLabel": "\u9009\u62E9\u9009\u9879",
820
+ "select.noMatch": "\u65E0\u5339\u914D\u9879",
821
+ "select.remove": "\u79FB\u9664 {p0}",
822
+ "select.searchPlaceholder": "\u641C\u7D22\u2026",
823
+ /* ── cascader / tree-select ── */
824
+ "cascader.placeholder": "\u8BF7\u9009\u62E9",
825
+ "cascader.noMatch": "\u65E0\u5339\u914D",
826
+ "cascader.search": "\u641C\u7D22",
827
+ "treeSelect.placeholder": "\u8BF7\u9009\u62E9",
828
+ "treeSelect.noMatch": "\u65E0\u5339\u914D",
829
+ "treeSelect.search": "\u641C\u7D22",
830
+ /* ── tagInput ── */
831
+ "tagInput.ariaLabel": "\u6807\u7B7E\u8F93\u5165\uFF0C\u5171 {p0} \u4E2A",
832
+ "tagInput.remove": "\u79FB\u9664 {p0}",
833
+ "tagInput.field": "\u6DFB\u52A0\u6807\u7B7E",
834
+ "tagInput.added": "\u5DF2\u6DFB\u52A0 {p0} \u4E2A\u6807\u7B7E\u3002",
835
+ "tagInput.removed": "\u5DF2\u79FB\u9664 {p0}\u3002",
836
+ "tagInput.duplicate": "\u5DF2\u6709\u300C{p0}\u300D\uFF0C\u53EF\u4EE5\u7F16\u8F91\u540E\u91CD\u8BD5\u3002",
837
+ "tagInput.limit": "\u6700\u591A {p0} \u4E2A\u6807\u7B7E\uFF0C\u8BF7\u5148\u79FB\u9664\u4E00\u4E2A\u3002",
838
+ /* ── upload ── */
839
+ "upload.remove": "\u79FB\u9664 {p0}",
840
+ "upload.tooBig": "\u6587\u4EF6\u8D85\u8FC7 {p0}",
841
+ "upload.tooMany": "\u6700\u591A {p0} \u4E2A\u6587\u4EF6",
842
+ "upload.typeNotAllowed": "\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301"
843
+ };
844
+ var current = { ...ICEN_LOCALE_ZH_CN };
845
+ function t(key, vars) {
846
+ const raw = current[key] ?? ICEN_LOCALE_ZH_CN[key];
847
+ if (vars == null || Array.isArray(raw)) return raw;
848
+ return raw.replace(/\{(\w+)\}/g, (m, name) => name in vars ? String(vars[name]) : m);
849
+ }
850
+
851
+ // src/behaviors/icons.ts
852
+ var ICON_PATHS = {
853
+ 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",
854
+ 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",
855
+ 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",
856
+ 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",
857
+ 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",
858
+ 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",
859
+ 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",
860
+ 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",
861
+ 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",
862
+ "line-numbers": "M3 5h2M3 10h2M3 15h2M8 5h9M8 10h9M8 15h9",
863
+ wrap: "M3 5h14M3 10h10a3 3 0 0 1 0 6h-3M12.5 13.5 10 16l2.5 2.5",
864
+ 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",
865
+ close: "M6 6l8 8M14 6l-8 8",
866
+ check: "M4.5 10.2l3.6 3.6 7.4-7.6",
867
+ "chevron-down": "M5.5 7.75 10 12.25l4.5-4.5",
868
+ "chevron-up": "M5.5 12.25 10 7.75l4.5 4.5",
869
+ "chevron-right": "M7.75 5.5 12.25 10l-4.5 4.5",
870
+ "chevron-left": "M12.25 5.5 7.75 10l4.5 4.5",
871
+ "arrow-right": "M3.5 10h13M11 4.5l5.5 5.5-5.5 5.5",
872
+ "arrow-left": "M16.5 10h-13M9 4.5 3.5 10 9 15.5",
873
+ "arrow-up": "M10 16.5v-13M4.5 9 10 3.5 15.5 9",
874
+ "arrow-down": "M10 3.5v13M4.5 11l5.5 5.5 5.5-5.5",
875
+ plus: "M10 4v12M4 10h12",
876
+ minus: "M4 10h12",
877
+ sort: "M6 15V4M3 7l3-3 3 3M14 5v11M11 13l3 3 3-3",
878
+ search: "M13.3 13.3 17 17M14.5 8.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0",
879
+ 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",
880
+ 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",
881
+ 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",
882
+ pixel: "M3 3h5v5H3ZM12 3h5v5h-5ZM3 12h5v5H3ZM12 12h5v5h-5Z",
883
+ chinese: "M3 8c3 0 5-2 7-5 2 3 4 5 7 5M4 8h12M6 8v8m8-8v8M3 16h14M8 16v-5h4v5",
884
+ soviet: "M3 17h14M5 17V8h4v9m0-12h6v12M7 8V5h2m2 3h2m-2 3h2m-2 3h2M10 5V3h4v2",
885
+ more: "M4 9.9v.2M10 9.9v.2M16 9.9v.2",
886
+ 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",
887
+ 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",
888
+ 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",
889
+ trash: "M3.5 5.5h13M7 5.5V3h6v2.5M5 5.5l.7 11.5h8.6L15 5.5M8 9v5M12 9v5",
890
+ spinner: "M10 3a7 7 0 1 1-7 7",
891
+ "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",
892
+ "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",
893
+ "circle-info": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM10 9v5M10 6.1v.15",
894
+ "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",
895
+ 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",
896
+ 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",
897
+ 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",
898
+ settings: "M3.5 5.5h13M3.5 10h13M3.5 14.5h13M7 4v3M12.5 8.5v3M8 13v3",
899
+ 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",
900
+ 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",
901
+ "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",
902
+ 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",
903
+ 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",
904
+ 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",
905
+ activity: "M17 10h-2.6l-2 5.8L8 4.2 6 10H3",
906
+ "trend-up": "M3.5 14.5l4.2-4.2 2.8 2.8 5.9-5.9M12.4 7.2h4.2v4.2",
907
+ "trend-down": "M3.5 5.5l4.2 4.2 2.8-2.8 5.9 5.9M12.4 12.8h4.2V8.6",
908
+ 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",
909
+ bold: "M6.5 4h4.2a3 3 0 0 1 0 6H6.5M6.5 10h5a3 3 0 0 1 0 6H6.5M6.5 4v12",
910
+ italic: "M8.5 4.5h7M4.5 15.5h7M12.5 4.5l-5 11",
911
+ underline: "M6 4v5.5a4 4 0 0 0 8 0V4M4.5 16h11",
912
+ "align-left": "M3.5 4.5h13M3.5 10h8.5M3.5 15.5h11",
913
+ "align-center": "M3.5 4.5h13M5.75 10h8.5M4.5 15.5h11",
914
+ "align-right": "M3.5 4.5h13M8 10h8.5M5.5 15.5h11",
915
+ list: "M6.5 5h10M6.5 10h10M6.5 15h10M3.5 5h.01M3.5 10h.01M3.5 15h.01",
916
+ 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",
917
+ 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",
918
+ 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",
919
+ "chart-line": "M3.5 3.5v13h13M6.5 12l2.8-2.8 2.2 2.2 4-4.4",
920
+ 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",
921
+ box: "M17 6 10 3.2 3 6v8l7 2.8 7-2.8ZM3 6l7 2.8L17 6M10 9v7.8",
922
+ filter: "M4 4.5h12l-4.4 5.1v5l-3.2-1.6V9.6Z",
923
+ columns: "M3.5 4h13v12h-13ZM8.2 4v12M12.8 4v12",
924
+ 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"
925
+ };
926
+ var custom = /* @__PURE__ */ new Map();
927
+ var escape = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
928
+ function iconPath(name) {
929
+ return Object.hasOwn(ICON_PATHS, name) ? ICON_PATHS[name] : custom.get(name) ?? null;
930
+ }
931
+ function iconAttributes(o = {}) {
932
+ const size = Number.isFinite(o.size) && o.size > 0 ? o.size : 16;
933
+ 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" } };
934
+ }
935
+ function iconHTML(name, o = {}) {
936
+ const path = iconPath(name);
937
+ if (!path) return "";
938
+ return `<svg${Object.entries(iconAttributes(o)).map(([k, v]) => ` ${k}="${escape(v)}"`).join("")}><path d="${escape(path)}"></path></svg>`;
939
+ }
940
+ function createIcon(name, o = {}) {
941
+ if (typeof document === "undefined") return null;
942
+ const path = iconPath(name);
943
+ if (!path) return null;
944
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
945
+ for (const [key, value] of Object.entries(iconAttributes(o))) svg.setAttribute(key, value);
946
+ const line = document.createElementNS(svg.namespaceURI, "path");
947
+ line.setAttribute("d", path);
948
+ svg.append(line);
949
+ return svg;
950
+ }
951
+
952
+ // src/behaviors/svg-parse.ts
953
+ function parseSvg(source) {
954
+ if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
955
+ const trimmed = source.trimStart();
956
+ if (!trimmed.startsWith("<svg")) return null;
957
+ const src = /^<svg(?![^>]*\bxmlns[=:])/i.test(trimmed) ? trimmed.replace(/^<svg/i, '<svg xmlns="http://www.w3.org/2000/svg"') : trimmed;
958
+ let parsed;
959
+ try {
960
+ parsed = new DOMParser().parseFromString(src, "image/svg+xml");
961
+ } catch {
962
+ return null;
963
+ }
964
+ const root = parsed.documentElement;
965
+ if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) return null;
966
+ const sanitize = (el) => {
967
+ for (const attr of Array.from(el.attributes)) {
968
+ const name = attr.name.toLowerCase();
969
+ if (name.startsWith("on")) el.removeAttribute(attr.name);
970
+ if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
971
+ el.removeAttribute(attr.name);
972
+ }
973
+ }
974
+ for (const child of Array.from(el.children)) {
975
+ const tag = child.tagName.toLowerCase();
976
+ if (tag === "script" || tag === "foreignobject") {
977
+ child.remove();
978
+ continue;
979
+ }
980
+ sanitize(child);
981
+ }
982
+ };
983
+ sanitize(root);
984
+ return document.importNode(root, true);
985
+ }
986
+
1
987
  // src/behaviors/ai-core.ts
2
988
  var AI_STATUSES = [
3
989
  "pending",
@@ -10,64 +996,33 @@ var AI_STATUSES = [
10
996
  ];
11
997
  function aiStatusLabel(s) {
12
998
  const labels = {
13
- pending: "\u7B49\u5F85",
14
- running: "\u6267\u884C\u4E2D",
15
- streaming: "\u6D41\u5F0F\u4E2D",
16
- approval: "\u5F85\u786E\u8BA4",
17
- done: "\u5B8C\u6210",
18
- error: "\u5931\u8D25",
19
- cancelled: "\u5DF2\u53D6\u6D88"
999
+ pending: t("aiCore.statusPending"),
1000
+ running: t("aiCore.statusRunning"),
1001
+ streaming: t("aiCore.statusStreaming"),
1002
+ approval: t("aiCore.statusApproval"),
1003
+ done: t("aiCore.statusDone"),
1004
+ error: t("aiCore.statusError"),
1005
+ cancelled: t("aiCore.statusCancelled")
20
1006
  };
21
1007
  return labels[s] ?? s;
22
1008
  }
23
- var svg = (body) => `<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">${body}</svg>`;
24
- var ICON_TERMINAL = svg('<path d="m4 17 6-6-6-6"/><path d="M12 19h8"/>');
25
- var ICON_FILE = svg(
26
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>'
27
- );
28
- var ICON_FILE_PEN = svg(
29
- '<path d="M12.5 22H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8l5 5v3.5"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M19 6.5 16.5 4"/><path d="M21.378 16.626a1 1 0 0 0-3.004-3.004l-4.01 4.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"/>'
30
- );
31
- var ICON_FILE_PLUS = svg(
32
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M9 15h6"/><path d="M12 12v6"/>'
33
- );
34
- var ICON_TRASH = svg(
35
- '<path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M10 11v6"/><path d="M14 11v6"/>'
36
- );
37
- var ICON_SEARCH = svg('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>');
38
- var ICON_FOLDER_SEARCH = svg(
39
- '<path d="M11 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v4"/><circle cx="17" cy="17" r="3"/><path d="m21 21-1.9-1.9"/>'
40
- );
41
- var ICON_SCAN_SEARCH = svg(
42
- '<path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><circle cx="12" cy="12" r="3"/><path d="m16 16-1.9-1.9"/>'
43
- );
44
- var ICON_GLOBE = svg(
45
- '<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>'
46
- );
47
- var ICON_DOWNLOAD = svg(
48
- '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/>'
49
- );
50
- var ICON_BLOCKS = svg(
51
- '<rect width="7" height="7" x="4" y="4" rx="1"/><rect width="7" height="7" x="13" y="4" rx="1"/><rect width="7" height="7" x="4" y="13" rx="1"/><rect width="7" height="7" x="13" y="13" rx="1"/>'
52
- );
53
- var ICON_ZAP = svg(
54
- '<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>'
55
- );
56
- var ICON_LIST = svg(
57
- '<path d="M3 12h.01"/><path d="M3 18h.01"/><path d="M3 6h.01"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M8 6h13"/>'
58
- );
59
- var ICON_LIST_CHECKS = svg(
60
- '<path d="m3 17 2 2 4-4"/><path d="m3 7 2 2 4-4"/><path d="M13 6h8"/><path d="M13 12h8"/><path d="M13 18h8"/>'
61
- );
62
- var ICON_BOT = svg(
63
- '<path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/>'
64
- );
65
- var ICON_CHART = svg(
66
- '<path d="M3 3v18h18"/><path d="M7 15l4-6 3 4 5-8"/>'
67
- );
68
- var ICON_FILE_TEXT = svg(
69
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/>'
70
- );
1009
+ var ICON_TERMINAL = iconHTML("terminal");
1010
+ var ICON_FILE = iconHTML("file");
1011
+ var ICON_FILE_PEN = iconHTML("edit");
1012
+ var ICON_FILE_PLUS = iconHTML("plus");
1013
+ var ICON_TRASH = iconHTML("trash");
1014
+ var ICON_SEARCH = iconHTML("search");
1015
+ var ICON_FOLDER_SEARCH = iconHTML("folder");
1016
+ var ICON_SCAN_SEARCH = iconHTML("search");
1017
+ var ICON_GLOBE = iconHTML("globe");
1018
+ var ICON_DOWNLOAD = iconHTML("download");
1019
+ var ICON_BLOCKS = iconHTML("server");
1020
+ var ICON_ZAP = iconHTML("sparkle");
1021
+ var ICON_LIST = iconHTML("list");
1022
+ var ICON_LIST_CHECKS = iconHTML("list");
1023
+ var ICON_BOT = iconHTML("agent");
1024
+ var ICON_CHART = iconHTML("chart-line");
1025
+ var ICON_FILE_TEXT = iconHTML("document");
71
1026
  function isObj(v) {
72
1027
  return typeof v === "object" && v !== null;
73
1028
  }
@@ -117,32 +1072,32 @@ var sum = (fn) => {
117
1072
  return (input) => fn(input) ?? "";
118
1073
  };
119
1074
  var BUILTIN_KINDS = {
120
- shell: { label: "\u547D\u4EE4", icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
121
- read: { label: "\u8BFB\u53D6", icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
122
- edit: { label: "\u7F16\u8F91", icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
123
- write: { label: "\u5199\u5165", icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
124
- rm: { label: "\u5220\u9664", icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
125
- grep: { label: "\u641C\u7D22", icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
126
- glob: { label: "\u5339\u914D", icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
127
- browser: { label: "\u6D4F\u89C8", icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
128
- search: { label: "\u68C0\u7D22", icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
129
- fetch: { label: "\u8BF7\u6C42", icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
1075
+ shell: { label: t("aiCore.kindShell"), icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
1076
+ read: { label: t("aiCore.kindRead"), icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
1077
+ edit: { label: t("aiCore.kindEdit"), icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
1078
+ write: { label: t("aiCore.kindWrite"), icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
1079
+ rm: { label: t("aiCore.kindDelete"), icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
1080
+ grep: { label: t("aiCore.kindGrep"), icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
1081
+ glob: { label: t("aiCore.kindGlob"), icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
1082
+ browser: { label: t("aiCore.kindBrowser"), icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
1083
+ search: { label: t("aiCore.kindSearch"), icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
1084
+ fetch: { label: t("aiCore.kindFetch"), icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
130
1085
  mcp: { label: "MCP", icon: ICON_BLOCKS, tint: "muted", summarize: sum((i) => pickStr(i, ["tool", "method", "name"])) },
131
- skill: { label: "\u6280\u80FD", icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
1086
+ skill: { label: t("aiCore.kindSkill"), icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
132
1087
  todo: {
133
- label: "\u5F85\u529E",
1088
+ label: t("aiCore.kindTodo"),
134
1089
  icon: ICON_LIST,
135
1090
  tint: "info",
136
1091
  summarize: sum((input) => {
137
1092
  const items = input && typeof input === "object" && Array.isArray(input.items) ? input.items : Array.isArray(input) ? input : [];
138
1093
  const done = items.filter((it) => it?.status === "done").length;
139
- return items.length > 0 ? `${done}/${items.length} \u5B8C\u6210` : "";
1094
+ return items.length > 0 ? t("aiCore.todoProgress", { p0: done, p1: items.length }) : "";
140
1095
  })
141
1096
  },
142
- plan: { label: "\u8BA1\u5212", icon: ICON_LIST_CHECKS, tint: "info" },
143
- subagent: { label: "\u5B50\u4EE3\u7406", icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
144
- note: { label: "\u7B14\u8BB0", icon: ICON_FILE_TEXT, tint: "muted" },
145
- chart: { label: "\u56FE\u8868", icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
1097
+ plan: { label: t("aiCore.kindPlan"), icon: ICON_LIST_CHECKS, tint: "info" },
1098
+ subagent: { label: t("aiCore.kindSubagent"), icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
1099
+ note: { label: t("aiCore.kindNote"), icon: ICON_FILE_TEXT, tint: "muted" },
1100
+ chart: { label: t("aiCore.kindChart"), icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
146
1101
  };
147
1102
  var kindRegistry = new Map(Object.entries(BUILTIN_KINDS));
148
1103
  function getAiKind(name) {
@@ -169,10 +1124,10 @@ function formatDuration(ms) {
169
1124
  var PART_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "file", "resource-link"]);
170
1125
  function isAiContentPart(v) {
171
1126
  if (!isObj(v)) return false;
172
- const t = v.type;
173
- if (typeof t !== "string" || !PART_TYPES.has(t)) return false;
174
- if (t === "text") return typeof v.text === "string";
175
- if (t === "resource-link") return typeof v.uri === "string";
1127
+ const t2 = v.type;
1128
+ if (typeof t2 !== "string" || !PART_TYPES.has(t2)) return false;
1129
+ if (t2 === "text") return typeof v.text === "string";
1130
+ if (t2 === "resource-link") return typeof v.uri === "string";
176
1131
  return typeof v.url === "string" || typeof v.data === "string" && typeof v.mimeType === "string";
177
1132
  }
178
1133
  function aiContentUrl(part) {
@@ -276,52 +1231,25 @@ function normalizeContentParts(raw) {
276
1231
  return out;
277
1232
  }
278
1233
  function h(tag, className, text) {
1234
+ if (typeof document === "undefined") throw new Error("h() \u4EC5\u6D4F\u89C8\u5668\u73AF\u5883\u53EF\u7528\uFF08SSR \u65F6\u7531\u8C03\u7528\u65B9\u5B88\u536B\uFF0C\u89C1\u6A21\u5757\u5934\u6CE8\u91CA\uFF09");
279
1235
  const node = document.createElement(tag);
280
1236
  if (className) node.className = className;
281
1237
  if (text != null) node.textContent = text;
282
1238
  return node;
283
1239
  }
284
- function svgIcon(svg2) {
285
- if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
286
- let parsed;
287
- try {
288
- parsed = new DOMParser().parseFromString(svg2, "image/svg+xml");
289
- } catch {
290
- return null;
291
- }
292
- const root = parsed.documentElement;
293
- if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
294
- return null;
295
- }
296
- const sanitize = (el) => {
297
- for (const attr of Array.from(el.attributes)) {
298
- const name = attr.name.toLowerCase();
299
- if (name.startsWith("on")) el.removeAttribute(attr.name);
300
- if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
301
- el.removeAttribute(attr.name);
302
- }
303
- }
304
- for (const child of Array.from(el.children)) {
305
- const tag = child.tagName.toLowerCase();
306
- if (tag === "script" || tag === "foreignobject") {
307
- child.remove();
308
- continue;
309
- }
310
- sanitize(child);
311
- }
312
- };
313
- sanitize(root);
314
- return document.importNode(root, true);
315
- }
316
-
317
- // src/behaviors/events.ts
318
- function emitIcen(source, type, detail) {
319
- return source.dispatchEvent(
320
- new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
321
- );
1240
+ function svgIcon(svg) {
1241
+ return parseSvg(svg);
322
1242
  }
323
1243
 
324
1244
  // src/behaviors/ai-chat.ts
1245
+ var ICON_COPY = iconHTML("copy");
1246
+ var ICON_RETRY = iconHTML("refresh");
1247
+ var ROLE_AVATAR = {
1248
+ user: t("aiChat.roleUser"),
1249
+ assistant: "AI",
1250
+ system: t("aiChat.roleSystem"),
1251
+ tool: t("aiChat.roleTool")
1252
+ };
325
1253
  function safeHref(uri) {
326
1254
  const s = uri.trim().toLowerCase();
327
1255
  if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
@@ -329,7 +1257,7 @@ function safeHref(uri) {
329
1257
  }
330
1258
  function renderAiContentPart(part) {
331
1259
  if (part.type === "text") {
332
- const span = h("span", "ai-msg-text");
1260
+ const span = h("span", "icen-ai-msg-text");
333
1261
  span.textContent = part.text;
334
1262
  if (part.state === "streaming") span.classList.add("is-streaming");
335
1263
  return span;
@@ -338,7 +1266,7 @@ function renderAiContentPart(part) {
338
1266
  const src = aiContentUrl(part);
339
1267
  if (!src) return void 0;
340
1268
  const img = document.createElement("img");
341
- img.className = "ai-msg-media ai-msg-media--image";
1269
+ img.className = "icen-ai-msg-media icen-ai-msg-media--image";
342
1270
  img.alt = part.alt ?? "";
343
1271
  img.setAttribute("loading", "lazy");
344
1272
  img.setAttribute("src", src);
@@ -348,7 +1276,7 @@ function renderAiContentPart(part) {
348
1276
  const src = aiContentUrl(part);
349
1277
  if (!src) return void 0;
350
1278
  const audio = document.createElement("audio");
351
- audio.className = "ai-msg-media ai-msg-media--audio";
1279
+ audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
352
1280
  audio.controls = true;
353
1281
  audio.setAttribute("src", src);
354
1282
  return audio;
@@ -357,28 +1285,28 @@ function renderAiContentPart(part) {
357
1285
  const src = aiContentUrl(part);
358
1286
  if (!src) return void 0;
359
1287
  const video = document.createElement("video");
360
- video.className = "ai-msg-media ai-msg-media--video";
1288
+ video.className = "icen-ai-msg-media icen-ai-msg-media--video";
361
1289
  video.controls = true;
362
1290
  video.setAttribute("playsinline", "");
363
1291
  video.setAttribute("src", src);
364
1292
  return video;
365
1293
  }
366
1294
  if (part.type === "file") {
367
- const chip = h("span", "ai-msg-file");
368
- chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? "\u6587\u4EF6"));
1295
+ const chip = h("span", "icen-ai-msg-file");
1296
+ chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
369
1297
  const href2 = part.url ? safeHref(part.url) : void 0;
370
1298
  if (href2 && /^(https?:|data:)/i.test(href2)) {
371
1299
  const a2 = document.createElement("a");
372
- a2.className = "ai-msg-file-link";
1300
+ a2.className = "icen-ai-msg-file-link";
373
1301
  a2.href = href2;
374
1302
  a2.download = part.filename ?? "";
375
- a2.textContent = "\u4E0B\u8F7D";
1303
+ a2.textContent = t("aiChat.download");
376
1304
  chip.appendChild(a2);
377
1305
  }
378
1306
  return chip;
379
1307
  }
380
1308
  const a = document.createElement("a");
381
- a.className = "ai-msg-link";
1309
+ a.className = "icen-ai-msg-link";
382
1310
  const href = safeHref(part.uri);
383
1311
  if (href) a.href = href;
384
1312
  a.textContent = part.name ?? part.uri;
@@ -394,16 +1322,16 @@ function toneVar(tone = "accent") {
394
1322
  if (registered) return registered;
395
1323
  switch (tone) {
396
1324
  case "success":
397
- return "var(--token-success)";
1325
+ return "var(--icen-token-success)";
398
1326
  case "warning":
399
- return "var(--token-warning)";
1327
+ return "var(--icen-token-warning)";
400
1328
  case "error":
401
- return "var(--token-error)";
1329
+ return "var(--icen-token-error)";
402
1330
  case "muted":
403
- return "var(--token-text-faint)";
1331
+ return "var(--icen-token-text-faint)";
404
1332
  case "accent":
405
1333
  default:
406
- return "var(--token-accent)";
1334
+ return "var(--icen-token-accent)";
407
1335
  }
408
1336
  }
409
1337
  function fmt(opts, value) {
@@ -414,13 +1342,66 @@ function maxOf(values) {
414
1342
  for (const v of values) if (v > max) max = v;
415
1343
  return max;
416
1344
  }
417
- function sampleLabels(labels, max = 7) {
418
- if (labels.length <= max) return labels;
419
- const out = [];
420
- for (let i = 0; i < max; i++) {
421
- out.push(labels[Math.round(i * (labels.length - 1) / (max - 1))] ?? "");
1345
+ function pointLabelsRow(labels, width, pad) {
1346
+ const row = document.createElement("div");
1347
+ row.className = "icen-chart-labels icen-chart-labels--points";
1348
+ const count = Math.min(labels.length, Math.max(2, Math.min(7, Math.floor(width / 64))));
1349
+ const step = count > 1 ? (width - 2 * pad) / (count - 1) : width;
1350
+ for (let tick = 0; tick < count; tick++) {
1351
+ const index = count <= 1 ? 0 : Math.round(tick * (labels.length - 1) / (count - 1));
1352
+ const x = labels.length <= 1 ? width / 2 : pad + index / (labels.length - 1) * (width - 2 * pad);
1353
+ const span = document.createElement("span");
1354
+ span.textContent = labels[index] ?? "";
1355
+ span.title = span.textContent;
1356
+ span.dir = "auto";
1357
+ span.dataset.icenChartIndex = String(index);
1358
+ span.style.left = `${x / width * 100}%`;
1359
+ span.style.width = `${Math.max(0, Math.min(step * 0.9, 2 * x, 2 * (width - x)))}px`;
1360
+ row.appendChild(span);
422
1361
  }
423
- return out;
1362
+ return row;
1363
+ }
1364
+ function clampNum(v, lo, hi) {
1365
+ return Math.min(hi, Math.max(lo, v));
1366
+ }
1367
+ function lttb(points, threshold, getX, getY) {
1368
+ const len = points.length;
1369
+ const n = Math.floor(threshold);
1370
+ if (!Number.isFinite(n) || n < 3 || n >= len || len <= 3) return points;
1371
+ const sampled = new Array(n);
1372
+ sampled[0] = points[0];
1373
+ sampled[n - 1] = points[len - 1];
1374
+ const every = (len - 2) / (n - 2);
1375
+ let a = 0;
1376
+ for (let i = 0; i < n - 2; i++) {
1377
+ const avgStart = Math.floor((i + 1) * every) + 1;
1378
+ const avgEnd = Math.min(Math.floor((i + 2) * every) + 1, len);
1379
+ let avgX = 0;
1380
+ let avgY = 0;
1381
+ for (let j = avgStart; j < avgEnd; j++) {
1382
+ avgX += getX(points[j]);
1383
+ avgY += getY(points[j]);
1384
+ }
1385
+ const avgLen = Math.max(1, avgEnd - avgStart);
1386
+ avgX /= avgLen;
1387
+ avgY /= avgLen;
1388
+ const rangeStart = Math.floor(i * every) + 1;
1389
+ const rangeEnd = Math.min(Math.floor((i + 1) * every) + 1, len);
1390
+ const ax = getX(points[a]);
1391
+ const ay = getY(points[a]);
1392
+ let maxArea = -1;
1393
+ let nextA = rangeStart;
1394
+ for (let j = rangeStart; j < rangeEnd; j++) {
1395
+ const area = Math.abs((ax - avgX) * (getY(points[j]) - ay) - (ax - getX(points[j])) * (avgY - ay)) * 0.5;
1396
+ if (area > maxArea) {
1397
+ maxArea = area;
1398
+ nextA = j;
1399
+ }
1400
+ }
1401
+ sampled[i + 1] = points[nextA];
1402
+ a = nextA;
1403
+ }
1404
+ return sampled;
424
1405
  }
425
1406
  function svgEl(tag, attrs) {
426
1407
  const el = document.createElementNS(SVG_NS, tag);
@@ -429,28 +1410,28 @@ function svgEl(tag, attrs) {
429
1410
  }
430
1411
  function renderEmpty(el, label) {
431
1412
  const box = document.createElement("div");
432
- box.className = "chart-empty";
433
- box.textContent = label ?? "\u6682\u65E0\u6570\u636E";
1413
+ box.className = "icen-chart-empty";
1414
+ box.textContent = label ?? t("charts.noData");
434
1415
  el.appendChild(box);
435
1416
  }
436
1417
  function legendItem(label, valueText, tone) {
437
1418
  const row = document.createElement("div");
438
- row.className = "chart-legend-item";
1419
+ row.className = "icen-chart-legend-item";
439
1420
  const dot = document.createElement("span");
440
- dot.className = "chart-legend-dot";
1421
+ dot.className = "icen-chart-legend-dot";
441
1422
  if (tone) dot.style.setProperty("--chart-tone", toneVar(tone));
442
1423
  const name = document.createElement("span");
443
- name.className = "chart-legend-label";
1424
+ name.className = "icen-chart-legend-label";
444
1425
  name.textContent = label;
445
1426
  const val = document.createElement("span");
446
- val.className = "chart-legend-value";
1427
+ val.className = "icen-chart-legend-value";
447
1428
  val.textContent = valueText;
448
1429
  row.append(dot, name, val);
449
1430
  return row;
450
1431
  }
451
1432
  function labelsRow(labels) {
452
1433
  const row = document.createElement("div");
453
- row.className = "chart-labels";
1434
+ row.className = "icen-chart-labels";
454
1435
  for (const label of labels) {
455
1436
  const span = document.createElement("span");
456
1437
  span.textContent = label;
@@ -465,85 +1446,90 @@ function normalizeSeriesInput(opts) {
465
1446
  function toneOf(tone, seriesIndex) {
466
1447
  if (typeof tone === "string") return toneVar(tone);
467
1448
  if (typeof tone === "number") return paletteVar(tone);
468
- return seriesIndex > 0 ? paletteVar((seriesIndex - 1) % 6 + 1) : void 0;
1449
+ return seriesIndex > 0 ? paletteVar(seriesIndex % 6 + 1) : void 0;
469
1450
  }
470
1451
  var PALETTE_VARS = [
471
- "var(--token-accent)",
472
- "var(--token-accent-cold)",
473
- "var(--token-success)",
474
- "var(--token-warning)",
475
- "var(--token-info)",
476
- "color-mix(in srgb, var(--token-text) 50%, transparent)"
1452
+ "var(--icen-token-accent)",
1453
+ "var(--icen-token-accent-cold)",
1454
+ "var(--icen-token-success)",
1455
+ "var(--icen-token-warning)",
1456
+ "var(--icen-token-info)",
1457
+ "color-mix(in srgb, var(--icen-token-text) 50%, transparent)"
477
1458
  ];
478
1459
  function paletteVar(index) {
479
1460
  const i = ((Math.floor(index) - 1) % 6 + 6) % 6;
480
1461
  return PALETTE_VARS[i];
481
1462
  }
482
1463
  function setMarkData(node, data) {
483
- node.setAttribute("data-chart-mark", "1");
484
- if (data.index != null) node.setAttribute("data-chart-index", String(data.index));
485
- if (data.seriesIndex != null) node.setAttribute("data-chart-series", String(data.seriesIndex));
486
- if (data.seriesName != null) node.setAttribute("data-chart-series-name", String(data.seriesName));
487
- if (data.label != null) node.setAttribute("data-chart-label", String(data.label));
488
- if (data.value != null) node.setAttribute("data-chart-value", String(data.value));
1464
+ node.setAttribute("data-icen-chart-mark", "1");
1465
+ if (data.index != null) node.setAttribute("data-icen-chart-index", String(data.index));
1466
+ if (data.seriesIndex != null) node.setAttribute("data-icen-chart-series", String(data.seriesIndex));
1467
+ if (data.seriesName != null) node.setAttribute("data-icen-chart-series-name", String(data.seriesName));
1468
+ if (data.label != null) node.setAttribute("data-icen-chart-label", String(data.label));
1469
+ if (data.value != null) node.setAttribute("data-icen-chart-value", String(data.value));
489
1470
  }
490
1471
  function copyMarkData(target, source) {
491
1472
  for (const attr of Array.from(source.attributes)) {
492
- if (attr.name.startsWith("data-chart-")) target.setAttribute(attr.name, attr.value);
493
- }
494
- }
495
- 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>';
496
- 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>';
497
- function parseChartSvg(svg2) {
498
- try {
499
- const doc = new DOMParser().parseFromString(svg2, "image/svg+xml");
500
- const el = doc.documentElement;
501
- return el && el.tagName.toLowerCase() === "svg" && !doc.querySelector("parsererror") ? document.importNode(el, true) : null;
502
- } catch {
503
- return null;
1473
+ if (attr.name.startsWith("data-icen-chart-")) target.setAttribute(attr.name, attr.value);
504
1474
  }
505
1475
  }
506
- function withChrome(el, opts, hasLegend, paint, state) {
507
- if (el.dataset.chartBody != null) {
1476
+ function withChrome(el, opts, hasLegend, paint, state, extras) {
1477
+ if (el.dataset.icenChartBody != null) {
508
1478
  el.textContent = "";
509
1479
  paint(el);
510
1480
  return;
511
1481
  }
512
1482
  el.textContent = "";
513
1483
  const body = document.createElement("div");
514
- body.className = "chart-body";
515
- body.dataset.chartBody = "";
516
- if (!opts.title && !hasLegend) {
1484
+ body.className = "icen-chart-body";
1485
+ body.dataset.icenChartBody = "";
1486
+ const note = extras?.note ?? null;
1487
+ const onZoomReset = extras?.onZoomReset ?? null;
1488
+ if (!opts.title && !hasLegend && note == null && !onZoomReset) {
517
1489
  el.appendChild(body);
518
1490
  paint(body);
519
1491
  return;
520
1492
  }
521
1493
  let hidden = state && state.hidden != null ? state.hidden : opts.legend === false;
522
1494
  if (state) state.hidden = hidden;
523
- el.setAttribute("data-legend-hidden", String(hidden));
1495
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
524
1496
  const head = document.createElement("div");
525
- head.className = "chart-head";
1497
+ head.className = "icen-chart-head";
526
1498
  const title = document.createElement("div");
527
- title.className = "chart-title";
1499
+ title.className = "icen-chart-title";
528
1500
  title.textContent = opts.title ?? "";
529
1501
  if (!opts.title) title.setAttribute("aria-hidden", "true");
1502
+ if (note != null) {
1503
+ const noteEl = document.createElement("span");
1504
+ noteEl.className = "icen-chart-note";
1505
+ noteEl.textContent = note;
1506
+ head.appendChild(noteEl);
1507
+ }
1508
+ if (onZoomReset) {
1509
+ const chip = document.createElement("button");
1510
+ chip.type = "button";
1511
+ chip.className = "icen-chart-zoom-reset";
1512
+ chip.textContent = t("charts.resetZoom");
1513
+ chip.addEventListener("click", onZoomReset);
1514
+ head.appendChild(chip);
1515
+ }
530
1516
  const eye = document.createElement("button");
531
1517
  eye.type = "button";
532
- eye.className = "chart-legend-eye";
533
- eye.dataset.chartLegendEye = "";
1518
+ eye.className = "icen-chart-legend-eye";
1519
+ eye.dataset.icenChartLegendEye = "";
534
1520
  const syncEye = () => {
535
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1521
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
536
1522
  eye.setAttribute("aria-pressed", String(!nowHidden));
537
- eye.setAttribute("aria-label", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
538
- eye.setAttribute("title", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
539
- const icon = parseChartSvg(nowHidden ? CHART_EYE_OFF_SVG : CHART_EYE_SVG);
1523
+ eye.setAttribute("aria-label", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1524
+ eye.setAttribute("title", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1525
+ const icon = createIcon(nowHidden ? "eye-off" : "eye");
540
1526
  if (icon) eye.replaceChildren(icon);
541
1527
  };
542
1528
  eye.addEventListener("click", () => {
543
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1529
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
544
1530
  hidden = !nowHidden;
545
1531
  if (state) state.hidden = hidden;
546
- el.setAttribute("data-legend-hidden", String(hidden));
1532
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
547
1533
  syncEye();
548
1534
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
549
1535
  });
@@ -552,23 +1538,30 @@ function withChrome(el, opts, hasLegend, paint, state) {
552
1538
  el.append(head, body);
553
1539
  paint(body);
554
1540
  }
1541
+ var hiddenLegendKeys = /* @__PURE__ */ new WeakMap();
555
1542
  function toggleLegend(items, scope) {
556
1543
  const legend = document.createElement("div");
557
- legend.className = "chart-legend chart-legend--toggle";
1544
+ legend.className = "icen-chart-legend icen-chart-legend--toggle";
1545
+ const owner = scope instanceof Element ? scope.closest("[data-icen-chart-body]")?.parentElement ?? scope : null;
1546
+ const hidden = owner ? hiddenLegendKeys.get(owner) ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
1547
+ if (owner) hiddenLegendKeys.set(owner, hidden);
558
1548
  for (const item of items) {
559
1549
  const row = legendItem(item.label, "", item.tone);
560
- row.classList.add("chart-legend-toggle-item");
1550
+ row.classList.add("icen-chart-legend-toggle-item");
561
1551
  row.setAttribute("role", "button");
562
1552
  row.tabIndex = 0;
563
- row.setAttribute("aria-pressed", "true");
564
- row.dataset.chartKey = item.key;
565
- const dot = row.querySelector(".chart-legend-dot");
566
- const toneColor = toneOf(item.tone, item.si + 1);
1553
+ row.classList.toggle("is-off", hidden.has(item.key));
1554
+ row.setAttribute("aria-pressed", String(!hidden.has(item.key)));
1555
+ row.dataset.icenChartKey = item.key;
1556
+ const dot = row.querySelector(".icen-chart-legend-dot");
1557
+ const toneColor = toneOf(item.tone, item.si);
567
1558
  if (dot && toneColor) dot.style.setProperty("--chart-tone", toneColor);
568
1559
  const toggle = () => {
569
1560
  const off = row.classList.toggle("is-off");
1561
+ if (off) hidden.add(item.key);
1562
+ else hidden.delete(item.key);
570
1563
  row.setAttribute("aria-pressed", String(!off));
571
- scope.querySelectorAll(`[data-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
1564
+ scope.querySelectorAll(`[data-icen-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
572
1565
  m.classList.toggle("is-off", off);
573
1566
  });
574
1567
  emitIcen(legend, "icen:chart-legend-toggle", { key: item.key, seriesIndex: item.si, hidden: off });
@@ -583,8 +1576,9 @@ function toggleLegend(items, scope) {
583
1576
  legend.appendChild(row);
584
1577
  }
585
1578
  for (const item of items) {
586
- scope.querySelectorAll(`[data-chart-series="${item.si}"]`).forEach((m) => {
587
- if (!m.hasAttribute("data-chart-key")) m.setAttribute("data-chart-key", item.key);
1579
+ scope.querySelectorAll(`[data-icen-chart-series="${item.si}"]`).forEach((m) => {
1580
+ if (!m.hasAttribute("data-icen-chart-key")) m.setAttribute("data-icen-chart-key", item.key);
1581
+ m.classList.toggle("is-off", hidden.has(item.key));
588
1582
  });
589
1583
  }
590
1584
  return legend;
@@ -611,19 +1605,19 @@ function renderVBar(el, opts) {
611
1605
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
612
1606
  }
613
1607
  const wrap = document.createElement("div");
614
- wrap.className = "chart-vbar";
1608
+ wrap.className = "icen-chart-vbar";
615
1609
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
616
1610
  for (let i = 0; i < n; i++) {
617
1611
  const track = document.createElement("div");
618
- track.className = "chart-vbar-track";
1612
+ track.className = "icen-chart-vbar-track";
619
1613
  if (seriesList.length > 1) {
620
- track.classList.add("chart-vbar-track--multi");
621
- if (opts.stacked) track.classList.add("chart-vbar-track--stacked");
1614
+ track.classList.add("icen-chart-vbar-track--multi");
1615
+ if (opts.stacked) track.classList.add("icen-chart-vbar-track--stacked");
622
1616
  }
623
1617
  seriesList.forEach((s, si) => {
624
1618
  const value = s.values[i] ?? 0;
625
1619
  const bar = document.createElement("div");
626
- bar.className = "chart-vbar-bar";
1620
+ bar.className = "icen-chart-vbar-bar";
627
1621
  const height = value > 0 ? Math.max(6, value / max * 100) : 0;
628
1622
  bar.style.height = `${height}%`;
629
1623
  const toneColor = toneOf(s.tone, si);
@@ -641,7 +1635,7 @@ function renderVBar(el, opts) {
641
1635
  wrap.appendChild(track);
642
1636
  }
643
1637
  body.append(wrap, labelsRow(labelsUsed));
644
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1638
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
645
1639
  });
646
1640
  attachChartInteraction(el, "vbar");
647
1641
  return el;
@@ -658,22 +1652,22 @@ function renderHBar(el, opts) {
658
1652
  const values = opts.values.slice(0, n);
659
1653
  const max = maxOf(values);
660
1654
  const wrap = document.createElement("div");
661
- wrap.className = "chart-hbar";
1655
+ wrap.className = "icen-chart-hbar";
662
1656
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
663
1657
  values.forEach((value, i) => {
664
1658
  const row = document.createElement("div");
665
- row.className = "chart-hbar-row";
1659
+ row.className = "icen-chart-hbar-row";
666
1660
  const label = document.createElement("span");
667
- label.className = "chart-hbar-label";
1661
+ label.className = "icen-chart-hbar-label";
668
1662
  label.textContent = labels[i] ?? "";
669
1663
  const track = document.createElement("div");
670
- track.className = "chart-hbar-track";
1664
+ track.className = "icen-chart-hbar-track";
671
1665
  const bar = document.createElement("div");
672
- bar.className = "chart-hbar-bar";
1666
+ bar.className = "icen-chart-hbar-bar";
673
1667
  bar.style.width = value > 0 ? `${Math.max(2, value / max * 100)}%` : "0%";
674
1668
  setMarkData(bar, { index: i, label: labels[i] ?? "", value });
675
1669
  const val = document.createElement("span");
676
- val.className = "chart-hbar-value";
1670
+ val.className = "icen-chart-hbar-value";
677
1671
  val.textContent = fmt(opts, value);
678
1672
  track.appendChild(bar);
679
1673
  row.append(label, track, val);
@@ -693,10 +1687,10 @@ function renderStack(el, opts) {
693
1687
  return;
694
1688
  }
695
1689
  const bar = document.createElement("div");
696
- bar.className = "chart-stack";
1690
+ bar.className = "icen-chart-stack";
697
1691
  for (const [segIndex, seg] of opts.segments.entries()) {
698
1692
  const s = document.createElement("div");
699
- s.className = "chart-stack-seg";
1693
+ s.className = "icen-chart-stack-seg";
700
1694
  s.style.width = `${seg.value / total * 100}%`;
701
1695
  if (seg.tone) s.style.setProperty("--chart-tone", toneVar(seg.tone));
702
1696
  s.setAttribute("title", `${seg.label}: ${fmt(opts, seg.value)}`);
@@ -704,7 +1698,7 @@ function renderStack(el, opts) {
704
1698
  bar.appendChild(s);
705
1699
  }
706
1700
  const legend = document.createElement("div");
707
- legend.className = "chart-legend";
1701
+ legend.className = "icen-chart-legend";
708
1702
  for (const seg of opts.segments) {
709
1703
  legend.appendChild(legendItem(seg.label, fmt(opts, seg.value), seg.tone));
710
1704
  }
@@ -724,15 +1718,15 @@ function renderDonut(el, opts) {
724
1718
  const radius = 42;
725
1719
  const circumference = 2 * Math.PI * radius;
726
1720
  const wrap = document.createElement("div");
727
- wrap.className = "chart-donut";
728
- const svg2 = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
729
- svg2.style.transform = "rotate(-90deg)";
730
- svg2.appendChild(svgEl("circle", {
1721
+ wrap.className = "icen-chart-donut";
1722
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.donut")) });
1723
+ svg.style.transform = "rotate(-90deg)";
1724
+ svg.appendChild(svgEl("circle", {
731
1725
  cx: "60",
732
1726
  cy: "60",
733
1727
  r: String(radius),
734
1728
  fill: "none",
735
- stroke: "var(--token-line-soft)",
1729
+ stroke: "var(--icen-token-line-soft)",
736
1730
  "stroke-width": "14"
737
1731
  }));
738
1732
  let offset = 0;
@@ -750,15 +1744,15 @@ function renderDonut(el, opts) {
750
1744
  "stroke-linecap": "butt"
751
1745
  });
752
1746
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
753
- svg2.appendChild(arc);
1747
+ svg.appendChild(arc);
754
1748
  offset += dash;
755
1749
  });
756
1750
  const legend = document.createElement("div");
757
- legend.className = "chart-legend";
1751
+ legend.className = "icen-chart-legend";
758
1752
  for (const seg of opts.segments) {
759
1753
  legend.appendChild(legendItem(seg.label, `${Math.round(seg.value / total * 100)}%`, seg.tone));
760
1754
  }
761
- wrap.append(svg2, legend);
1755
+ wrap.append(svg, legend);
762
1756
  body.appendChild(wrap);
763
1757
  });
764
1758
  attachChartInteraction(el, "donut");
@@ -776,23 +1770,23 @@ function renderLine(el, opts) {
776
1770
  return;
777
1771
  }
778
1772
  const labelsUsed = labels.slice(0, n);
779
- const width = 360;
1773
+ const width = fluidWidth(body);
780
1774
  const height = 150;
781
1775
  const pad = 14;
782
1776
  let max = 1;
783
1777
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
784
1778
  const wrap = document.createElement("div");
785
- wrap.className = "chart-line";
786
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
1779
+ wrap.className = "icen-chart-line";
1780
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
787
1781
  const defs = svgEl("defs", {});
788
1782
  for (let i = 0; i < 4; i++) {
789
1783
  const y = pad + i * (height - pad * 2) / 3;
790
- svg2.appendChild(svgEl("line", {
1784
+ svg.appendChild(svgEl("line", {
791
1785
  x1: String(pad),
792
1786
  x2: String(width - pad),
793
1787
  y1: String(y),
794
1788
  y2: String(y),
795
- stroke: "var(--token-line-soft)",
1789
+ stroke: "var(--icen-token-line-soft)",
796
1790
  "stroke-width": "1"
797
1791
  }));
798
1792
  }
@@ -822,7 +1816,7 @@ function renderLine(el, opts) {
822
1816
  if (seriesList.length > 1) {
823
1817
  setMarkData(areaPath, { seriesIndex: si, seriesName: s.name, label: s.name, value: values.reduce((a, b) => a + b, 0) });
824
1818
  }
825
- svg2.appendChild(areaPath);
1819
+ svg.appendChild(areaPath);
826
1820
  }
827
1821
  const linePath = svgEl("path", {
828
1822
  d: line,
@@ -833,16 +1827,16 @@ function renderLine(el, opts) {
833
1827
  "stroke-linejoin": "round"
834
1828
  });
835
1829
  const lineTitle = svgEl("title", {});
836
- lineTitle.textContent = s.name || "\u6570\u503C";
1830
+ lineTitle.textContent = s.name || t("charts.value");
837
1831
  linePath.appendChild(lineTitle);
838
1832
  setMarkData(linePath, { seriesIndex: si, seriesName: s.name, label: s.name, value: values[values.length - 1] ?? 0 });
839
- svg2.appendChild(linePath);
1833
+ svg.appendChild(linePath);
840
1834
  for (const p of points) {
841
1835
  const dot = svgEl("circle", {
842
1836
  cx: p.x.toFixed(1),
843
1837
  cy: p.y.toFixed(1),
844
1838
  r: "3",
845
- fill: "var(--token-card)",
1839
+ fill: "var(--icen-token-card)",
846
1840
  stroke: tone,
847
1841
  "stroke-width": "2"
848
1842
  });
@@ -856,23 +1850,24 @@ function renderLine(el, opts) {
856
1850
  label: p.label,
857
1851
  value: p.value
858
1852
  });
859
- svg2.appendChild(dot);
1853
+ svg.appendChild(dot);
860
1854
  const hit = svgEl("circle", {
861
1855
  cx: p.x.toFixed(1),
862
1856
  cy: p.y.toFixed(1),
863
1857
  r: "8",
864
1858
  fill: "transparent",
865
- "data-chart-hit": "1"
1859
+ "data-icen-chart-hit": "1"
866
1860
  });
867
1861
  copyMarkData(hit, dot);
868
- svg2.appendChild(hit);
1862
+ svg.appendChild(hit);
869
1863
  }
870
1864
  });
871
- if (defs.firstChild) svg2.insertBefore(defs, svg2.firstChild);
872
- wrap.append(svg2, labelsRow(sampleLabels(labelsUsed)));
1865
+ if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
1866
+ wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
873
1867
  body.appendChild(wrap);
874
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1868
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
875
1869
  });
1870
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
876
1871
  attachChartInteraction(el, "line");
877
1872
  return el;
878
1873
  }
@@ -904,30 +1899,30 @@ function renderRadar(el, opts) {
904
1899
  y: cy + r * Math.sin(angleOf(i))
905
1900
  });
906
1901
  const wrap = document.createElement("div");
907
- wrap.className = "chart-radar";
908
- const svg2 = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img" });
1902
+ wrap.className = "icen-chart-radar";
1903
+ const svg = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.radar")) });
909
1904
  for (let lv = 1; lv <= levels; lv++) {
910
1905
  const r = radius * lv / levels;
911
1906
  const pts = Array.from({ length: n }, (_, i) => {
912
1907
  const p = pointAt(i, r);
913
1908
  return `${p.x.toFixed(1)},${p.y.toFixed(1)}`;
914
1909
  }).join(" ");
915
- svg2.appendChild(svgEl("polygon", {
1910
+ svg.appendChild(svgEl("polygon", {
916
1911
  points: pts,
917
1912
  fill: "none",
918
- stroke: "var(--token-line-soft)",
1913
+ stroke: "var(--icen-token-line-soft)",
919
1914
  "stroke-width": "1",
920
1915
  "stroke-dasharray": lv === levels ? "0" : "3 2"
921
1916
  }));
922
1917
  }
923
1918
  for (let i = 0; i < n; i++) {
924
1919
  const edge = pointAt(i, radius);
925
- svg2.appendChild(svgEl("line", {
1920
+ svg.appendChild(svgEl("line", {
926
1921
  x1: String(cx),
927
1922
  y1: String(cy),
928
1923
  x2: edge.x.toFixed(1),
929
1924
  y2: edge.y.toFixed(1),
930
- stroke: "var(--token-line-soft)",
1925
+ stroke: "var(--icen-token-line-soft)",
931
1926
  "stroke-width": "1"
932
1927
  }));
933
1928
  const labelP = pointAt(i, radius + 14);
@@ -937,14 +1932,14 @@ function renderRadar(el, opts) {
937
1932
  "text-anchor": "middle",
938
1933
  "dominant-baseline": "middle",
939
1934
  "font-size": "9",
940
- fill: "var(--token-text-muted)"
1935
+ fill: "var(--icen-token-text-muted)"
941
1936
  });
942
1937
  txt.textContent = axes[i] ?? "";
943
- svg2.appendChild(txt);
1938
+ svg.appendChild(txt);
944
1939
  }
945
1940
  const legendItems = [];
946
1941
  opts.series.forEach((s, si) => {
947
- const tone = toneVar(s.tone);
1942
+ const tone = toneOf(s.tone, si) ?? toneVar(s.tone);
948
1943
  const pts = Array.from({ length: n }, (_, i) => {
949
1944
  const v = Math.max(0, Math.min(maxVal, s.values[i] ?? 0));
950
1945
  const p = pointAt(i, v / maxVal * radius);
@@ -962,7 +1957,7 @@ function renderRadar(el, opts) {
962
1957
  title.textContent = `${s.name}: ${s.values.map((v) => fmt(opts, v)).join(" / ")}`;
963
1958
  polyFill.appendChild(title);
964
1959
  setMarkData(polyFill, { seriesIndex: si, seriesName: s.name || void 0, label: s.name, value: s.values.reduce((a, b) => a + (b || 0), 0) });
965
- svg2.appendChild(polyFill);
1960
+ svg.appendChild(polyFill);
966
1961
  for (let i = 0; i < n; i++) {
967
1962
  const v = Math.max(0, Math.min(maxVal, s.values[i] ?? 0));
968
1963
  const p = pointAt(i, v / maxVal * radius);
@@ -970,18 +1965,19 @@ function renderRadar(el, opts) {
970
1965
  cx: p.x.toFixed(1),
971
1966
  cy: p.y.toFixed(1),
972
1967
  r: "2.5",
973
- fill: "var(--token-card)",
1968
+ fill: "var(--icen-token-card)",
974
1969
  stroke: tone,
975
1970
  "stroke-width": "1.5"
976
1971
  });
977
1972
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
978
- svg2.appendChild(dot);
1973
+ svg.appendChild(dot);
979
1974
  }
980
- legendItems.push({ key: s.name || `\u7CFB\u5217${si + 1}`, label: s.name || `\u7CFB\u5217${si + 1}`, tone: s.tone, si });
1975
+ legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 }), label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
981
1976
  });
982
- const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
983
- wrap.append(svg2, ...legend ? [legend] : []);
1977
+ wrap.appendChild(svg);
984
1978
  body.appendChild(wrap);
1979
+ const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
1980
+ if (legend) wrap.appendChild(legend);
985
1981
  });
986
1982
  attachChartInteraction(el, "radar");
987
1983
  return el;
@@ -1014,23 +2010,23 @@ function padFirstWeek(grid, firstDate, weekStart) {
1014
2010
  const pad = (first.getDay() + 7 - weekStart) % 7;
1015
2011
  for (let i = 0; i < pad; i++) {
1016
2012
  const blank = document.createElement("span");
1017
- blank.className = "chart-heatmap-cell is-blank";
2013
+ blank.className = "icen-chart-heatmap-cell is-blank";
1018
2014
  grid.appendChild(blank);
1019
2015
  }
1020
2016
  return pad;
1021
2017
  }
1022
2018
  function heatmapLegend(labels) {
1023
2019
  const legend = document.createElement("div");
1024
- legend.className = "chart-heatmap-legend";
2020
+ legend.className = "icen-chart-heatmap-legend";
1025
2021
  const less = document.createElement("span");
1026
- less.textContent = labels?.less ?? "\u5C11";
2022
+ less.textContent = labels?.less ?? t("charts.few");
1027
2023
  const more = document.createElement("span");
1028
- more.textContent = labels?.more ?? "\u591A";
2024
+ more.textContent = labels?.more ?? t("charts.many");
1029
2025
  legend.appendChild(less);
1030
2026
  for (let lv = 0; lv <= 4; lv++) {
1031
2027
  const cell = document.createElement("span");
1032
- cell.className = "chart-heatmap-cell";
1033
- cell.dataset.level = String(lv);
2028
+ cell.className = "icen-chart-heatmap-cell";
2029
+ cell.dataset.icenLevel = String(lv);
1034
2030
  legend.appendChild(cell);
1035
2031
  }
1036
2032
  legend.appendChild(more);
@@ -1057,16 +2053,17 @@ function renderHeatmap(el, opts) {
1057
2053
  if (entries.length > weeks * 7) entries = entries.slice(entries.length - weeks * 7);
1058
2054
  const max = maxOf(entries.map((e) => e.value));
1059
2055
  const wrap = document.createElement("div");
1060
- wrap.className = "chart-heatmap";
2056
+ wrap.className = "icen-chart-heatmap";
1061
2057
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1062
2058
  const grid = document.createElement("div");
1063
- grid.className = "chart-heatmap-grid";
2059
+ grid.className = "icen-chart-heatmap-grid";
1064
2060
  grid.setAttribute("role", "img");
2061
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
1065
2062
  padFirstWeek(grid, entries[0].date, opts.weekStart === 0 ? 0 : 1);
1066
2063
  for (const [i, entry] of entries.entries()) {
1067
2064
  const cell = document.createElement("span");
1068
- cell.className = "chart-heatmap-cell";
1069
- cell.dataset.level = String(levelOf(entry.value, max));
2065
+ cell.className = "icen-chart-heatmap-cell";
2066
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
1070
2067
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
1071
2068
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
1072
2069
  grid.appendChild(cell);
@@ -1101,16 +2098,16 @@ function renderSparkline(el, opts) {
1101
2098
  const area = `${line} L${last.x.toFixed(1)},${height - pad} L${first.x.toFixed(1)},${height - pad} Z`;
1102
2099
  const gradientId = `icen-chart-line-${++lineGradientSeq}`;
1103
2100
  const wrap = document.createElement("div");
1104
- wrap.className = "chart-sparkline";
1105
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
2101
+ wrap.className = "icen-chart-sparkline";
2102
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.sparkline")) });
1106
2103
  const defs = svgEl("defs", {});
1107
2104
  const gradient = svgEl("linearGradient", { id: gradientId, x1: "0", x2: "0", y1: "0", y2: "1" });
1108
2105
  gradient.appendChild(svgEl("stop", { offset: "0%", "stop-color": tone, "stop-opacity": "0.28" }));
1109
2106
  gradient.appendChild(svgEl("stop", { offset: "100%", "stop-color": tone, "stop-opacity": "0.02" }));
1110
2107
  defs.appendChild(gradient);
1111
- svg2.appendChild(defs);
1112
- svg2.appendChild(svgEl("path", { d: area, fill: `url(#${gradientId})` }));
1113
- svg2.appendChild(svgEl("path", {
2108
+ svg.appendChild(defs);
2109
+ svg.appendChild(svgEl("path", { d: area, fill: `url(#${gradientId})` }));
2110
+ svg.appendChild(svgEl("path", {
1114
2111
  d: line,
1115
2112
  fill: "none",
1116
2113
  stroke: tone,
@@ -1122,15 +2119,15 @@ function renderSparkline(el, opts) {
1122
2119
  cx: last.x.toFixed(1),
1123
2120
  cy: last.y.toFixed(1),
1124
2121
  r: "2.4",
1125
- fill: "var(--token-card)",
2122
+ fill: "var(--icen-token-card)",
1126
2123
  stroke: tone,
1127
2124
  "stroke-width": "1.6"
1128
2125
  });
1129
2126
  const title = svgEl("title", {});
1130
2127
  title.textContent = fmt(opts, last.value);
1131
2128
  dot.appendChild(title);
1132
- svg2.appendChild(dot);
1133
- wrap.appendChild(svg2);
2129
+ svg.appendChild(dot);
2130
+ wrap.appendChild(svg);
1134
2131
  body.appendChild(wrap);
1135
2132
  });
1136
2133
  attachChartInteraction(el, "sparkline");
@@ -1144,20 +2141,20 @@ function renderGauge(el, opts) {
1144
2141
  const radius = 42;
1145
2142
  const circumference = 2 * Math.PI * radius;
1146
2143
  const wrap = document.createElement("div");
1147
- wrap.className = "chart-gauge";
2144
+ wrap.className = "icen-chart-gauge";
1148
2145
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1149
- const svg2 = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
1150
- svg2.style.transform = "rotate(-90deg)";
1151
- svg2.appendChild(svgEl("circle", {
2146
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.label, t("charts.type.gauge")) });
2147
+ svg.style.transform = "rotate(-90deg)";
2148
+ svg.appendChild(svgEl("circle", {
1152
2149
  cx: "60",
1153
2150
  cy: "60",
1154
2151
  r: String(radius),
1155
2152
  fill: "none",
1156
- stroke: "var(--token-line-soft)",
2153
+ stroke: "var(--icen-token-line-soft)",
1157
2154
  "stroke-width": "10"
1158
2155
  }));
1159
2156
  const dash = ratio * circumference;
1160
- svg2.appendChild(svgEl("circle", {
2157
+ svg.appendChild(svgEl("circle", {
1161
2158
  cx: "60",
1162
2159
  cy: "60",
1163
2160
  r: String(radius),
@@ -1168,18 +2165,18 @@ function renderGauge(el, opts) {
1168
2165
  "stroke-linecap": "round"
1169
2166
  }));
1170
2167
  const center = document.createElement("div");
1171
- center.className = "chart-gauge-center";
2168
+ center.className = "icen-chart-gauge-center";
1172
2169
  const val = document.createElement("span");
1173
- val.className = "chart-gauge-value";
2170
+ val.className = "icen-chart-gauge-value";
1174
2171
  val.textContent = opts.formatValue ? opts.formatValue(opts.value) : `${Math.round(ratio * 100)}%`;
1175
2172
  center.appendChild(val);
1176
2173
  if (opts.label) {
1177
2174
  const lab = document.createElement("span");
1178
- lab.className = "chart-gauge-label";
2175
+ lab.className = "icen-chart-gauge-label";
1179
2176
  lab.textContent = opts.label;
1180
2177
  center.appendChild(lab);
1181
2178
  }
1182
- wrap.append(svg2, center);
2179
+ wrap.append(svg, center);
1183
2180
  el.appendChild(wrap);
1184
2181
  attachChartInteraction(el, "gauge");
1185
2182
  return el;
@@ -1197,19 +2194,20 @@ function renderCalendar(el, opts) {
1197
2194
  return;
1198
2195
  }
1199
2196
  const wrap = document.createElement("div");
1200
- wrap.className = "chart-calendar";
2197
+ wrap.className = "icen-chart-calendar";
1201
2198
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1202
2199
  const weekStart = opts.weekStart === 0 ? 0 : 1;
1203
- const weekdayDefaults = ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"];
2200
+ const weekdayDefaults = t("charts.calendarWeekdays");
1204
2201
  const weekdayLabels = opts.labels?.weekdays ?? weekdayDefaults.map((_, i) => weekdayLabelAt(weekdayDefaults, (weekStart + i) % 7));
1205
- const monthLabel = (m) => opts.labels?.months?.[m] ?? `${m + 1}\u6708`;
2202
+ const monthLabel = (m) => opts.labels?.months?.[m] ?? t("charts.monthLabel", { p0: m + 1 });
1206
2203
  const grid = document.createElement("div");
1207
- grid.className = "chart-heatmap-grid";
2204
+ grid.className = "icen-chart-heatmap-grid";
1208
2205
  grid.setAttribute("role", "img");
2206
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
1209
2207
  const months = document.createElement("div");
1210
- months.className = "chart-calendar-months";
2208
+ months.className = "icen-chart-calendar-months";
1211
2209
  const weekdayRow = document.createElement("div");
1212
- weekdayRow.className = "chart-calendar-weekdays";
2210
+ weekdayRow.className = "icen-chart-calendar-weekdays";
1213
2211
  weekdayLabels.forEach((w) => {
1214
2212
  const s = document.createElement("span");
1215
2213
  s.textContent = w;
@@ -1224,14 +2222,14 @@ function renderCalendar(el, opts) {
1224
2222
  if (d.getMonth() !== lastMonth) {
1225
2223
  lastMonth = d.getMonth();
1226
2224
  const label = document.createElement("span");
1227
- label.className = "chart-calendar-month";
2225
+ label.className = "icen-chart-calendar-month";
1228
2226
  label.textContent = monthLabel(d.getMonth());
1229
2227
  label.style.setProperty("--col", String(col));
1230
2228
  months.appendChild(label);
1231
2229
  }
1232
2230
  const cell = document.createElement("span");
1233
- cell.className = "chart-heatmap-cell";
1234
- cell.dataset.level = String(levelOf(entry.value, max));
2231
+ cell.className = "icen-chart-heatmap-cell";
2232
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
1235
2233
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
1236
2234
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
1237
2235
  grid.appendChild(cell);
@@ -1253,7 +2251,7 @@ function renderScatter(el, opts) {
1253
2251
  renderEmpty(body, opts.emptyLabel);
1254
2252
  return;
1255
2253
  }
1256
- const width = 360;
2254
+ const width = fluidWidth(body);
1257
2255
  const height = 220;
1258
2256
  const pad = 30;
1259
2257
  let xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, sMax = 0;
@@ -1268,19 +2266,19 @@ function renderScatter(el, opts) {
1268
2266
  if (yMax === yMin) yMax = yMin + 1;
1269
2267
  const rOf = (size) => size && sMax > 0 ? 3 + size / sMax * 7 : 4;
1270
2268
  const wrap = document.createElement("div");
1271
- wrap.className = "chart-scatter";
2269
+ wrap.className = "icen-chart-scatter";
1272
2270
  const tone = toneVar(opts.tone);
1273
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
2271
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.scatter")) });
1274
2272
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
1275
2273
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
1276
2274
  for (let i = 0; i <= 3; i++) {
1277
2275
  const y = pad + i * (height - pad * 2) / 3;
1278
- svg2.appendChild(svgEl("line", {
2276
+ svg.appendChild(svgEl("line", {
1279
2277
  x1: String(pad),
1280
2278
  x2: String(width - pad),
1281
2279
  y1: String(y),
1282
2280
  y2: String(y),
1283
- stroke: "var(--token-line-soft)",
2281
+ stroke: "var(--icen-token-line-soft)",
1284
2282
  "stroke-width": "1"
1285
2283
  }));
1286
2284
  const tv = yMin + (yMax - yMin) * (3 - i) / 3;
@@ -1289,19 +2287,19 @@ function renderScatter(el, opts) {
1289
2287
  y: String(y + 3),
1290
2288
  "text-anchor": "end",
1291
2289
  "font-size": "8",
1292
- fill: "var(--token-text-faint)"
2290
+ fill: "var(--icen-token-text-faint)"
1293
2291
  });
1294
2292
  txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1295
- svg2.appendChild(txt);
2293
+ svg.appendChild(txt);
1296
2294
  }
1297
2295
  for (let i = 0; i <= 4; i++) {
1298
2296
  const x = pad + i * (width - pad * 2) / 4;
1299
- svg2.appendChild(svgEl("line", {
2297
+ svg.appendChild(svgEl("line", {
1300
2298
  x1: String(x),
1301
2299
  x2: String(x),
1302
2300
  y1: String(pad),
1303
2301
  y2: String(height - pad),
1304
- stroke: "var(--token-line-soft)",
2302
+ stroke: "var(--icen-token-line-soft)",
1305
2303
  "stroke-width": "1",
1306
2304
  "stroke-dasharray": "2 3"
1307
2305
  }));
@@ -1311,20 +2309,20 @@ function renderScatter(el, opts) {
1311
2309
  y: String(height - pad + 12),
1312
2310
  "text-anchor": "middle",
1313
2311
  "font-size": "8",
1314
- fill: "var(--token-text-faint)"
2312
+ fill: "var(--icen-token-text-faint)"
1315
2313
  });
1316
2314
  txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1317
- svg2.appendChild(txt);
2315
+ svg.appendChild(txt);
1318
2316
  }
1319
2317
  if (opts.yLabel) {
1320
- const t = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--token-text-faint)" });
1321
- t.textContent = opts.yLabel;
1322
- svg2.appendChild(t);
2318
+ const t2 = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--icen-token-text-faint)" });
2319
+ t2.textContent = opts.yLabel;
2320
+ svg.appendChild(t2);
1323
2321
  }
1324
2322
  if (opts.xLabel) {
1325
- const t = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--token-text-faint)" });
1326
- t.textContent = opts.xLabel;
1327
- svg2.appendChild(t);
2323
+ const t2 = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--icen-token-text-faint)" });
2324
+ t2.textContent = opts.xLabel;
2325
+ svg.appendChild(t2);
1328
2326
  }
1329
2327
  pts.forEach((p, i) => {
1330
2328
  const c = svgEl("circle", {
@@ -1341,11 +2339,12 @@ function renderScatter(el, opts) {
1341
2339
  c.appendChild(title);
1342
2340
  setMarkData(c, { index: i, label: p.label ?? `#${i + 1}`, value: p.y });
1343
2341
  c.dataset.chartX = String(p.x);
1344
- svg2.appendChild(c);
2342
+ svg.appendChild(c);
1345
2343
  });
1346
- wrap.appendChild(svg2);
2344
+ wrap.appendChild(svg);
1347
2345
  body.appendChild(wrap);
1348
2346
  });
2347
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderScatter(el, opts));
1349
2348
  attachChartInteraction(el, "scatter");
1350
2349
  return el;
1351
2350
  }
@@ -1395,7 +2394,7 @@ function pivotData(spec) {
1395
2394
  const labels = [];
1396
2395
  const seenLabel = /* @__PURE__ */ new Set();
1397
2396
  const hasSeries = data.some((r) => r[seriesField] != null && r[seriesField] !== "");
1398
- const seriesNames = [];
2397
+ const seriesNames = hasSeries ? [] : [""];
1399
2398
  const seenSeries = /* @__PURE__ */ new Set();
1400
2399
  for (const r of data) {
1401
2400
  const l = str2(r[labelField]);
@@ -1484,8 +2483,8 @@ function normalizeChartSpec(raw) {
1484
2483
  const s = src;
1485
2484
  const spec = {};
1486
2485
  if (typeof s.type === "string") {
1487
- const t = s.type.trim().toLowerCase();
1488
- spec.type = CHART_TYPE_ALIASES[t] ?? t;
2486
+ const t2 = s.type.trim().toLowerCase();
2487
+ spec.type = CHART_TYPE_ALIASES[t2] ?? t2;
1489
2488
  }
1490
2489
  for (const k of ["title", "tone", "emptyLabel"]) {
1491
2490
  if (typeof s[k] === "string") spec[k] = s[k];
@@ -1507,7 +2506,7 @@ function normalizeChartSpec(raw) {
1507
2506
  if (Array.isArray(s.series)) {
1508
2507
  const series = s.series.filter((v) => !!v && typeof v === "object").map((v, i) => {
1509
2508
  const values = Array.isArray(v.values) ? v.values.map(toNum).filter((n) => n != null) : [];
1510
- const sv = { name: String(v.name ?? `\u7CFB\u5217${i + 1}`), values };
2509
+ const sv = { name: String(v.name ?? t("charts.seriesName", { p0: i + 1 })), values };
1511
2510
  const tone = v.tone;
1512
2511
  if (typeof tone === "string" || typeof tone === "number") sv.tone = tone;
1513
2512
  return sv;
@@ -1542,6 +2541,40 @@ function normalizeChartSpec(raw) {
1542
2541
  }
1543
2542
  spec.format = format;
1544
2543
  }
2544
+ if (typeof s.downsample === "boolean") spec.downsample = s.downsample;
2545
+ else {
2546
+ const n = toNum(s.downsample);
2547
+ if (n != null) spec.downsample = n;
2548
+ }
2549
+ if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2550
+ if (typeof s.loading === "boolean") spec.loading = s.loading;
2551
+ if (Array.isArray(s.marks)) {
2552
+ const marks = [];
2553
+ for (const raw2 of s.marks) {
2554
+ if (!raw2 || typeof raw2 !== "object" || Array.isArray(raw2)) continue;
2555
+ const m = raw2;
2556
+ if (m.type === "line") {
2557
+ if (m.axis !== "x" && m.axis !== "y") continue;
2558
+ if (typeof m.value !== "number" && typeof m.value !== "string") continue;
2559
+ const mark = { type: "line", axis: m.axis, value: m.value };
2560
+ if (typeof m.label === "string" && m.label !== "") mark.label = m.label;
2561
+ if (m.tone === "success" || m.tone === "warning" || m.tone === "error" || m.tone === "info") {
2562
+ mark.tone = m.tone;
2563
+ }
2564
+ marks.push(mark);
2565
+ } else if (m.type === "point") {
2566
+ if (typeof m.label !== "string" || m.label === "") continue;
2567
+ const mark = { type: "point", label: m.label };
2568
+ const si = toNum(m.seriesIndex);
2569
+ if (si != null && si >= 0) mark.seriesIndex = Math.floor(si);
2570
+ const v = toNum(m.value);
2571
+ if (v != null) mark.value = v;
2572
+ if (typeof m.text === "string") mark.text = m.text;
2573
+ marks.push(mark);
2574
+ }
2575
+ }
2576
+ if (marks.length > 0) spec.marks = marks;
2577
+ }
1545
2578
  const isDateRecords = spec.data?.length && spec.data[0] && "date" in spec.data[0];
1546
2579
  if (spec.data && spec.data.length > 0 && !isDateRecords && !spec.series && !spec.points && !spec.values && !spec.segments) {
1547
2580
  Object.assign(spec, pivotData(spec));
@@ -1581,6 +2614,391 @@ function inferChartType(spec) {
1581
2614
  if (typeof spec.max === "number" && spec.values && spec.values.length === 1) return "gauge";
1582
2615
  return "vbar";
1583
2616
  }
2617
+ var DOWNSAMPLE_DEFAULT_THRESHOLD = 1e3;
2618
+ var CHART_ZOOM_DRAG_MIN_PX = 5;
2619
+ var CHART_LINE_W = 360;
2620
+ var CHART_LINE_H = 150;
2621
+ var CHART_LINE_PAD = 14;
2622
+ function isDownsampleableType(type) {
2623
+ return type === "line" || type === "area" || type === "scatter";
2624
+ }
2625
+ function isZoomableType(type) {
2626
+ return type === "line" || type === "area" || type === "vbar";
2627
+ }
2628
+ function isStreamableType(type) {
2629
+ return type === "line" || type === "area" || type === "vbar";
2630
+ }
2631
+ function downsampleView(view, type) {
2632
+ const raw = view.downsample;
2633
+ if (raw == null || raw === false) return { view, note: null };
2634
+ const threshold = raw === true ? DOWNSAMPLE_DEFAULT_THRESHOLD : Math.floor(raw);
2635
+ if (!Number.isFinite(threshold)) return { view, note: null };
2636
+ if (type === "scatter") {
2637
+ const pts = view.points ?? [];
2638
+ if (pts.length === 0) return { view, note: null };
2639
+ const sampled2 = lttb(pts, threshold, (p) => p.x, (p) => p.y);
2640
+ if (sampled2.length === pts.length) return { view, note: null };
2641
+ return { view: { ...view, points: sampled2 }, note: t("charts.sampled", { p0: pts.length, p1: sampled2.length }) };
2642
+ }
2643
+ const labels = view.labels ?? [];
2644
+ if (labels.length === 0) return { view, note: null };
2645
+ const guide = view.series && view.series.length > 0 ? view.series[0]?.values ?? [] : view.values ?? [];
2646
+ const count = Math.min(labels.length, guide.length);
2647
+ if (count === 0) return { view, note: null };
2648
+ const indexed = guide.slice(0, count).map((v, i) => ({ i, v }));
2649
+ const sampled = lttb(indexed, threshold, (p) => p.i, (p) => p.v);
2650
+ if (sampled.length >= count) return { view, note: null };
2651
+ const idx = sampled.map((p) => p.i);
2652
+ return {
2653
+ view: {
2654
+ ...view,
2655
+ labels: idx.map((i) => labels[i] ?? ""),
2656
+ values: view.values ? idx.map((i) => view.values?.[i] ?? 0) : void 0,
2657
+ series: view.series?.map((s) => ({ ...s, values: idx.map((i) => s.values[i] ?? 0) }))
2658
+ },
2659
+ note: t("charts.sampled", { p0: count, p1: idx.length })
2660
+ };
2661
+ }
2662
+ function renderChartSkeleton(body) {
2663
+ const box = document.createElement("div");
2664
+ box.className = "icen-chart-skeleton";
2665
+ box.setAttribute("role", "status");
2666
+ box.setAttribute("aria-busy", "true");
2667
+ box.setAttribute("aria-label", t("charts.loading"));
2668
+ const widths = [100, 84, 92, 68, 76, 52];
2669
+ for (const w of widths) {
2670
+ const bar = document.createElement("div");
2671
+ bar.className = "icen-chart-skeleton-bar";
2672
+ bar.style.width = `${w}%`;
2673
+ box.appendChild(bar);
2674
+ }
2675
+ body.appendChild(box);
2676
+ }
2677
+ var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2678
+ function markToneVar(tone) {
2679
+ switch (tone) {
2680
+ case "success":
2681
+ return "var(--icen-token-success)";
2682
+ case "warning":
2683
+ return "var(--icen-token-warning)";
2684
+ case "error":
2685
+ return "var(--icen-token-error)";
2686
+ case "info":
2687
+ return "var(--icen-token-info)";
2688
+ default:
2689
+ return "var(--icen-token-text-faint)";
2690
+ }
2691
+ }
2692
+ function markWarnOnce(warned, mark, reason) {
2693
+ const key = JSON.stringify(mark);
2694
+ if (warned.has(key)) return;
2695
+ warned.add(key);
2696
+ console.warn(`[icen:chart] \u65E0\u6548\u6807\u8BB0\u5DF2\u8DF3\u8FC7\uFF08${reason}\uFF09`, mark);
2697
+ }
2698
+ function paintChartMarks(root, view, spec, formatValue, warned) {
2699
+ const marks = spec.marks;
2700
+ if (!marks || marks.length === 0) return;
2701
+ const type = spec.type;
2702
+ if (type === "line" || type === "area") paintSvgChartMarks(root, view, marks, formatValue, warned);
2703
+ else if (type === "vbar") paintVBarChartMarks(root, view, spec, marks, formatValue, warned);
2704
+ }
2705
+ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2706
+ const svg = root.querySelector(".icen-chart-line svg");
2707
+ if (!svg) return;
2708
+ const labels = view.labels ?? [];
2709
+ const n = labels.length;
2710
+ if (n === 0) return;
2711
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2712
+ let max = 1;
2713
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2714
+ const dims = svgDimsOf(svg);
2715
+ const W = dims.w;
2716
+ const H = dims.h;
2717
+ const PAD = CHART_LINE_PAD;
2718
+ const xAt = (i) => n <= 1 ? W / 2 : PAD + i / (n - 1) * (W - PAD * 2);
2719
+ const yAt = (v) => H - PAD - Math.max(0, v) / max * (H - PAD * 2);
2720
+ for (const mark of marks) {
2721
+ if (mark.type === "line") {
2722
+ const color = markToneVar(mark.tone);
2723
+ if (mark.axis === "y") {
2724
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2725
+ if (!Number.isFinite(v)) {
2726
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2727
+ continue;
2728
+ }
2729
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2730
+ svg.appendChild(svgEl("line", {
2731
+ class: "icen-chart-mark-line",
2732
+ x1: String(PAD),
2733
+ x2: String(W - PAD),
2734
+ y1: y.toFixed(1),
2735
+ y2: y.toFixed(1),
2736
+ stroke: color,
2737
+ "stroke-width": "1",
2738
+ "stroke-dasharray": "4 3"
2739
+ }));
2740
+ const label = svgEl("text", {
2741
+ class: "icen-chart-mark-label",
2742
+ x: String(W - PAD),
2743
+ y: String(clampNum(y - 4, 8, CHART_LINE_H - 4)),
2744
+ "text-anchor": "end",
2745
+ "font-size": "8",
2746
+ fill: color
2747
+ });
2748
+ label.textContent = mark.label ?? formatValue(v);
2749
+ svg.appendChild(label);
2750
+ } else {
2751
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2752
+ if (idx < 0 || idx >= n) {
2753
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2754
+ continue;
2755
+ }
2756
+ const x = xAt(idx);
2757
+ svg.appendChild(svgEl("line", {
2758
+ class: "icen-chart-mark-line",
2759
+ x1: x.toFixed(1),
2760
+ x2: x.toFixed(1),
2761
+ y1: String(PAD),
2762
+ y2: String(H - PAD),
2763
+ stroke: color,
2764
+ "stroke-width": "1",
2765
+ "stroke-dasharray": "4 3"
2766
+ }));
2767
+ const label = svgEl("text", {
2768
+ class: "icen-chart-mark-label",
2769
+ x: String(clampNum(x, 10, W - 10)),
2770
+ y: String(PAD + 8),
2771
+ "text-anchor": "middle",
2772
+ "font-size": "8",
2773
+ fill: color
2774
+ });
2775
+ label.textContent = mark.label ?? labels[idx] ?? "";
2776
+ svg.appendChild(label);
2777
+ }
2778
+ } else {
2779
+ const idx = labels.indexOf(mark.label);
2780
+ if (idx < 0 || idx >= n) {
2781
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2782
+ continue;
2783
+ }
2784
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2785
+ const s = seriesList[si];
2786
+ if (!s) {
2787
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2788
+ continue;
2789
+ }
2790
+ const v = mark.value ?? s.values[idx] ?? NaN;
2791
+ if (!Number.isFinite(v)) {
2792
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2793
+ continue;
2794
+ }
2795
+ const x = xAt(idx);
2796
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2797
+ const g = svgEl("g", { class: "icen-chart-mark-point" });
2798
+ g.appendChild(svgEl("circle", {
2799
+ cx: x.toFixed(1),
2800
+ cy: y.toFixed(1),
2801
+ r: "6",
2802
+ fill: "none",
2803
+ stroke: CHART_MARK_ACCENT,
2804
+ "stroke-width": "1.5"
2805
+ }));
2806
+ g.appendChild(svgEl("circle", { cx: x.toFixed(1), cy: y.toFixed(1), r: "2", fill: CHART_MARK_ACCENT }));
2807
+ const label = svgEl("text", {
2808
+ class: "icen-chart-mark-label",
2809
+ x: String(clampNum(x, 12, W - 12)),
2810
+ y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2811
+ "text-anchor": "middle",
2812
+ "font-size": "8",
2813
+ fill: CHART_MARK_ACCENT
2814
+ });
2815
+ label.textContent = mark.text ?? mark.label;
2816
+ g.appendChild(label);
2817
+ svg.appendChild(g);
2818
+ }
2819
+ }
2820
+ }
2821
+ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2822
+ const wrap = root.querySelector(".icen-chart-vbar");
2823
+ if (!wrap) return;
2824
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2825
+ const labels = view.labels ?? [];
2826
+ const n = Math.min(labels.length, ...seriesList.map((s) => s.values.length));
2827
+ if (n === 0 || seriesList.length === 0) return;
2828
+ const multi = seriesList.length > 1;
2829
+ let max = 1;
2830
+ if (spec.stacked && multi) {
2831
+ for (let i = 0; i < n; i++) {
2832
+ let sum2 = 0;
2833
+ for (const s of seriesList) sum2 += Math.max(0, s.values[i] ?? 0);
2834
+ if (sum2 > max) max = sum2;
2835
+ }
2836
+ } else {
2837
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2838
+ }
2839
+ const centerPct = (i) => (i + 0.5) / n * 100;
2840
+ for (const mark of marks) {
2841
+ if (mark.type === "line") {
2842
+ if (mark.axis === "y") {
2843
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2844
+ if (!Number.isFinite(v)) {
2845
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2846
+ continue;
2847
+ }
2848
+ const line = document.createElement("div");
2849
+ line.className = "icen-chart-mark-line icen-chart-mark-line--h";
2850
+ line.style.top = `${(clampNum(1 - Math.max(0, v) / max, 0.02, 0.98) * 100).toFixed(2)}%`;
2851
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2852
+ const lab = document.createElement("span");
2853
+ lab.className = "icen-chart-mark-label";
2854
+ lab.textContent = mark.label ?? formatValue(v);
2855
+ line.appendChild(lab);
2856
+ wrap.appendChild(line);
2857
+ } else {
2858
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2859
+ if (idx < 0 || idx >= n) {
2860
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2861
+ continue;
2862
+ }
2863
+ const line = document.createElement("div");
2864
+ line.className = "icen-chart-mark-line icen-chart-mark-line--v";
2865
+ line.style.left = `${centerPct(idx).toFixed(2)}%`;
2866
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2867
+ const lab = document.createElement("span");
2868
+ lab.className = "icen-chart-mark-label";
2869
+ lab.textContent = mark.label ?? labels[idx] ?? "";
2870
+ line.appendChild(lab);
2871
+ wrap.appendChild(line);
2872
+ }
2873
+ } else {
2874
+ const idx = labels.indexOf(mark.label);
2875
+ if (idx < 0 || idx >= n) {
2876
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2877
+ continue;
2878
+ }
2879
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2880
+ const s = seriesList[si];
2881
+ if (!s) {
2882
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2883
+ continue;
2884
+ }
2885
+ const v = mark.value ?? s.values[idx] ?? NaN;
2886
+ if (!Number.isFinite(v)) {
2887
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2888
+ continue;
2889
+ }
2890
+ const dot = document.createElement("div");
2891
+ dot.className = "icen-chart-mark-point";
2892
+ dot.style.left = `${centerPct(idx).toFixed(2)}%`;
2893
+ dot.style.bottom = `${(clampNum(Math.max(0, v) / max, 0, 1) * 100).toFixed(2)}%`;
2894
+ const lab = document.createElement("span");
2895
+ lab.className = "icen-chart-mark-label";
2896
+ lab.textContent = mark.text ?? mark.label;
2897
+ dot.appendChild(lab);
2898
+ wrap.appendChild(dot);
2899
+ }
2900
+ }
2901
+ }
2902
+ function chartAriaLabel(title, typeName) {
2903
+ return title ? `${typeName}\uFF1A${title}` : typeName;
2904
+ }
2905
+ function svgDimsOf(svg) {
2906
+ const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2907
+ const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
2908
+ const h2 = Number.isFinite(vb[3]) && (vb[3] ?? 0) > 0 ? vb[3] : CHART_LINE_H;
2909
+ return { w, h: h2 };
2910
+ }
2911
+ var fluidObservers = /* @__PURE__ */ new WeakMap();
2912
+ function fluidWidth(host) {
2913
+ const w = Math.round(host.getBoundingClientRect().width);
2914
+ return w > 0 ? Math.max(29, w) : 360;
2915
+ }
2916
+ function observeFluidWidth(el, rerender) {
2917
+ if (typeof ResizeObserver === "undefined") return;
2918
+ fluidObservers.get(el)?.disconnect();
2919
+ let last = Math.round(el.getBoundingClientRect().width);
2920
+ const ro = new ResizeObserver(() => {
2921
+ if (!el.isConnected) {
2922
+ ro.disconnect();
2923
+ fluidObservers.delete(el);
2924
+ return;
2925
+ }
2926
+ const w = Math.round(el.getBoundingClientRect().width);
2927
+ if (Math.abs(w - last) < 2) return;
2928
+ last = w;
2929
+ rerender();
2930
+ });
2931
+ ro.observe(el);
2932
+ fluidObservers.set(el, ro);
2933
+ }
2934
+ function releaseFluidWidth(el) {
2935
+ fluidObservers.get(el)?.disconnect();
2936
+ fluidObservers.delete(el);
2937
+ }
2938
+ function createChartToDataURL(root) {
2939
+ const cache = /* @__PURE__ */ new Map();
2940
+ return (opts) => {
2941
+ if (typeof document === "undefined") return void 0;
2942
+ const scale = clampNum(toNum(opts?.scale) ?? 2, 0.5, 4);
2943
+ const svgs = Array.from(root.querySelectorAll("svg"));
2944
+ if (svgs.length === 0) return void 0;
2945
+ const parts = [];
2946
+ for (const svg of svgs) {
2947
+ const { w, h: h2 } = svgDimsOf(svg);
2948
+ const clone = svg.cloneNode(true);
2949
+ clone.setAttribute("xmlns", SVG_NS);
2950
+ clone.setAttribute("width", String(w));
2951
+ clone.setAttribute("height", String(h2));
2952
+ let str2;
2953
+ try {
2954
+ str2 = new XMLSerializer().serializeToString(clone);
2955
+ } catch {
2956
+ return void 0;
2957
+ }
2958
+ parts.push({ src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(str2)}`, w, h: h2 });
2959
+ }
2960
+ const key = `${scale}|${parts.map((p) => p.src).join("")}`;
2961
+ const hit = cache.get(key);
2962
+ if (hit) return hit;
2963
+ const canvas = document.createElement("canvas");
2964
+ let ctx = null;
2965
+ try {
2966
+ ctx = canvas.getContext("2d");
2967
+ } catch {
2968
+ return void 0;
2969
+ }
2970
+ if (!ctx) return void 0;
2971
+ const context = ctx;
2972
+ const totalW = Math.max(...parts.map((p) => p.w));
2973
+ const totalH = parts.reduce((sum2, p) => sum2 + p.h, 0);
2974
+ canvas.width = Math.max(1, Math.round(totalW * scale));
2975
+ canvas.height = Math.max(1, Math.round(totalH * scale));
2976
+ let loaded = 0;
2977
+ let failed = false;
2978
+ let offsetY = 0;
2979
+ for (const part of parts) {
2980
+ const dy = offsetY;
2981
+ offsetY += part.h;
2982
+ const img = new Image();
2983
+ img.onload = () => {
2984
+ if (failed) return;
2985
+ context.drawImage(img, 0, dy * scale, part.w * scale, part.h * scale);
2986
+ loaded += 1;
2987
+ if (loaded === parts.length) {
2988
+ try {
2989
+ cache.set(key, canvas.toDataURL("image/png"));
2990
+ } catch {
2991
+ }
2992
+ }
2993
+ };
2994
+ img.onerror = () => {
2995
+ failed = true;
2996
+ };
2997
+ img.src = part.src;
2998
+ }
2999
+ return cache.get(key);
3000
+ };
3001
+ }
1584
3002
  function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1585
3003
  const read = (name) => mark.getAttribute(name) ?? void 0;
1586
3004
  const numOr = (v) => v == null ? void 0 : Number(v);
@@ -1588,11 +3006,11 @@ function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1588
3006
  type,
1589
3007
  phase,
1590
3008
  chart,
1591
- index: numOr(read("data-chart-index")),
1592
- seriesIndex: numOr(read("data-chart-series")),
1593
- seriesName: read("data-chart-series-name"),
1594
- label: read("data-chart-label"),
1595
- value: numOr(read("data-chart-value")),
3009
+ index: numOr(read("data-icen-chart-index")),
3010
+ seriesIndex: numOr(read("data-icen-chart-series")),
3011
+ seriesName: read("data-icen-chart-series-name"),
3012
+ label: read("data-icen-chart-label"),
3013
+ value: numOr(read("data-icen-chart-value")),
1596
3014
  target: mark,
1597
3015
  pointerX: pointer?.x,
1598
3016
  pointerY: pointer?.y
@@ -1603,7 +3021,7 @@ var tooltipEl = null;
1603
3021
  function chartTooltip() {
1604
3022
  if (!tooltipEl) {
1605
3023
  tooltipEl = document.createElement("div");
1606
- tooltipEl.className = "chart-tooltip";
3024
+ tooltipEl.className = "icen-chart-tooltip";
1607
3025
  tooltipEl.setAttribute("role", "tooltip");
1608
3026
  tooltipEl.hidden = true;
1609
3027
  document.body.appendChild(tooltipEl);
@@ -1612,14 +3030,14 @@ function chartTooltip() {
1612
3030
  }
1613
3031
  function applyTooltipSizing(host) {
1614
3032
  const tip = chartTooltip();
1615
- const raw = host?.closest(".chart, [data-chart-root]")?.getAttribute("data-panel-max") ?? null;
3033
+ const raw = host?.closest(".icen-chart, [data-icen-chart-root]")?.getAttribute("data-icen-panel-max") ?? null;
1616
3034
  const n = raw != null ? Number(raw) : NaN;
1617
3035
  tip.style.maxWidth = Number.isFinite(n) && n > 0 ? `${n}px` : "";
1618
3036
  }
1619
3037
  function tooltipText(mark) {
1620
- const label = mark.getAttribute("data-chart-label") ?? "";
1621
- const series = mark.getAttribute("data-chart-series-name");
1622
- const value = mark.getAttribute("data-chart-value");
3038
+ const label = mark.getAttribute("data-icen-chart-label") ?? "";
3039
+ const series = mark.getAttribute("data-icen-chart-series-name");
3040
+ const value = mark.getAttribute("data-icen-chart-value");
1623
3041
  const head = series ? label ? `${series} \xB7 ${label}` : series : label;
1624
3042
  return value != null ? `${head}\uFF1A${value}` : head;
1625
3043
  }
@@ -1651,8 +3069,8 @@ function bindChartEvents(root) {
1651
3069
  const typeNow = () => chartDelegateMeta.get(root)?.type() ?? "vbar";
1652
3070
  const tipEnabled = () => chartDelegateMeta.get(root)?.tooltip() ?? true;
1653
3071
  const markOf = (e) => {
1654
- const t = e.target;
1655
- return t instanceof Element ? t.closest("[data-chart-mark]") : null;
3072
+ const t2 = e.target;
3073
+ return t2 instanceof Element ? t2.closest("[data-icen-chart-mark]") : null;
1656
3074
  };
1657
3075
  let hoverMark = null;
1658
3076
  const enterMark = (mark, x, y) => {
@@ -1749,70 +3167,277 @@ function hasLegendOf(spec) {
1749
3167
  function renderChart(el, raw) {
1750
3168
  const noop = () => void 0;
1751
3169
  if (typeof document === "undefined") {
1752
- return { el, spec: {}, update: noop, on: () => noop, destroy: noop };
3170
+ return {
3171
+ el,
3172
+ spec: {},
3173
+ update: noop,
3174
+ append: noop,
3175
+ toDataURL: () => void 0,
3176
+ on: () => noop,
3177
+ destroy: noop
3178
+ };
1753
3179
  }
1754
3180
  const root = el;
1755
- let current = normalizeChartSpec(raw);
1756
- const typeOf = () => current.type ?? "vbar";
3181
+ let current2 = normalizeChartSpec(raw);
3182
+ const typeOf = () => current2.type ?? "vbar";
1757
3183
  const legendState = { hidden: null };
3184
+ let zoomWindow = null;
3185
+ const warnedMarks = /* @__PURE__ */ new Set();
3186
+ let warnedAppend = false;
3187
+ let zoomDragCleanup = null;
3188
+ const fullLength = () => {
3189
+ if (current2.type === "scatter") return current2.points?.length ?? 0;
3190
+ if (current2.series && current2.series.length > 0) {
3191
+ return Math.max(current2.labels?.length ?? 0, ...current2.series.map((s) => s.values.length));
3192
+ }
3193
+ return Math.max(current2.labels?.length ?? 0, current2.values?.length ?? 0);
3194
+ };
3195
+ const viewOf = () => {
3196
+ if (!zoomWindow) return current2;
3197
+ const { from, to } = zoomWindow;
3198
+ return {
3199
+ ...current2,
3200
+ labels: current2.labels?.slice(from, to + 1),
3201
+ values: current2.values?.slice(from, to + 1),
3202
+ series: current2.series?.map((s) => ({ ...s, values: s.values.slice(from, to + 1) })),
3203
+ points: current2.points?.slice(from, to + 1)
3204
+ };
3205
+ };
3206
+ const applyZoomSelection = (x0, x1) => {
3207
+ const len = fullLength();
3208
+ if (len < 2) return;
3209
+ const base = zoomWindow?.from ?? 0;
3210
+ const viewLen = zoomWindow ? zoomWindow.to - zoomWindow.from + 1 : len;
3211
+ const lo = Math.min(x0, x1);
3212
+ const hi = Math.max(x0, x1);
3213
+ let i0;
3214
+ let i1;
3215
+ const vbar = root.querySelector(".icen-chart-vbar");
3216
+ if (vbar) {
3217
+ const rect = vbar.getBoundingClientRect();
3218
+ const rel0 = rect.width > 0 ? Math.floor((lo - rect.left) / rect.width * viewLen) : 0;
3219
+ const rel1 = rect.width > 0 ? Math.max(rel0, Math.floor((hi - rect.left) / rect.width * viewLen)) : viewLen - 1;
3220
+ i0 = clampNum(rel0 + base, 0, len - 1);
3221
+ i1 = clampNum(rel1 + base, 0, len - 1);
3222
+ } else {
3223
+ const svg = root.querySelector(".icen-chart-line svg");
3224
+ if (!svg) return;
3225
+ const dims = svgDimsOf(svg);
3226
+ const p0 = svgClientPoint(svg, lo, 0, dims.w, dims.h);
3227
+ const p1 = svgClientPoint(svg, hi, 0, dims.w, dims.h);
3228
+ const rel0 = Math.round((p0.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
3229
+ const rel1 = Math.round((p1.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
3230
+ i0 = clampNum(rel0 + base, 0, len - 1);
3231
+ i1 = clampNum(rel1 + base, 0, len - 1);
3232
+ }
3233
+ if (i0 > i1) [i0, i1] = [i1, i0];
3234
+ if (i0 <= 0 && i1 >= len - 1) zoomWindow = null;
3235
+ else zoomWindow = { from: i0, to: Math.max(i1, i0) };
3236
+ render();
3237
+ emitIcen(root, "icen:chart-zoom", { chart: String(current2.type ?? ""), from: i0, to: Math.max(i1, i0) });
3238
+ };
3239
+ const bindZoomGesture = () => {
3240
+ if (current2.zoom !== "x" && current2.zoom !== "brush") return;
3241
+ const t2 = typeOf();
3242
+ if (!isZoomableType(t2) || fullLength() < 2) return;
3243
+ const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
3244
+ if (!plot) return;
3245
+ const on = (type, fn) => {
3246
+ plot.addEventListener(type, fn);
3247
+ };
3248
+ let drag = null;
3249
+ const onMove = (e) => {
3250
+ if (!drag) return;
3251
+ drag.x1 = e.clientX;
3252
+ drag.y1 = e.clientY;
3253
+ if (!drag.active && Math.hypot(drag.x1 - drag.x0, drag.y1 - drag.y0) >= CHART_ZOOM_DRAG_MIN_PX) {
3254
+ drag.active = true;
3255
+ const rect = document.createElement("div");
3256
+ rect.className = "icen-chart-zoom-rect";
3257
+ document.body.appendChild(rect);
3258
+ drag.rect = rect;
3259
+ }
3260
+ if (drag.active && drag.rect) {
3261
+ drag.rect.style.left = `${Math.round(Math.min(drag.x0, drag.x1))}px`;
3262
+ drag.rect.style.width = `${Math.round(Math.abs(drag.x1 - drag.x0))}px`;
3263
+ if (current2.zoom === "brush") {
3264
+ drag.rect.style.top = `${Math.round(Math.min(drag.y0, drag.y1))}px`;
3265
+ drag.rect.style.height = `${Math.round(Math.abs(drag.y1 - drag.y0))}px`;
3266
+ } else {
3267
+ const pr = plot.getBoundingClientRect();
3268
+ drag.rect.style.top = `${Math.round(pr.top)}px`;
3269
+ drag.rect.style.height = `${Math.round(pr.height)}px`;
3270
+ }
3271
+ }
3272
+ };
3273
+ const onUp = () => {
3274
+ window.removeEventListener("pointermove", onMove);
3275
+ window.removeEventListener("pointerup", onUp);
3276
+ window.removeEventListener("pointercancel", onUp);
3277
+ zoomDragCleanup = null;
3278
+ if (!drag) return;
3279
+ const d = drag;
3280
+ drag = null;
3281
+ d.rect?.remove();
3282
+ if (!d.active) return;
3283
+ applyZoomSelection(d.x0, d.x1);
3284
+ };
3285
+ const onDown = (e) => {
3286
+ if (e.button !== 0) return;
3287
+ drag = { x0: e.clientX, y0: e.clientY, x1: e.clientX, y1: e.clientY, active: false, rect: null };
3288
+ window.addEventListener("pointermove", onMove);
3289
+ window.addEventListener("pointerup", onUp);
3290
+ window.addEventListener("pointercancel", onUp);
3291
+ zoomDragCleanup = onUp;
3292
+ };
3293
+ on("pointerdown", onDown);
3294
+ on("dblclick", () => {
3295
+ if (!zoomWindow) return;
3296
+ zoomWindow = null;
3297
+ render();
3298
+ });
3299
+ };
1758
3300
  const render = () => {
1759
- if (!current.type) current = { ...current, type: inferChartType(current) };
1760
- const spec = current;
3301
+ if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
3302
+ const spec = current2;
3303
+ const type = spec.type;
1761
3304
  const formatValue = chartFormatValue(spec.format);
1762
3305
  if (spec.legend !== void 0) legendState.hidden = spec.legend === false;
3306
+ const loading = spec.loading === true;
3307
+ root.classList.toggle("is-loading", loading);
3308
+ let view = viewOf();
3309
+ let note = null;
3310
+ if (!loading && isDownsampleableType(type)) {
3311
+ const r = downsampleView(view, type);
3312
+ view = r.view;
3313
+ note = r.note;
3314
+ }
3315
+ const zoomReset = zoomWindow && (spec.zoom === "x" || spec.zoom === "brush") ? () => {
3316
+ zoomWindow = null;
3317
+ render();
3318
+ } : null;
1763
3319
  withChrome(root, spec, hasLegendOf(spec), (body) => {
1764
- switch (spec.type) {
3320
+ if (loading) {
3321
+ renderChartSkeleton(body);
3322
+ return;
3323
+ }
3324
+ switch (type) {
1765
3325
  case "line":
1766
- 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 });
3326
+ 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 });
1767
3327
  break;
1768
3328
  case "area":
1769
- 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 });
3329
+ 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 });
1770
3330
  break;
1771
3331
  case "vbar":
1772
- 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 });
3332
+ 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 });
1773
3333
  break;
1774
3334
  case "hbar":
1775
- renderHBar(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3335
+ renderHBar(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1776
3336
  break;
1777
3337
  case "stack":
1778
- renderStack(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3338
+ renderStack(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1779
3339
  break;
1780
3340
  case "donut":
1781
- renderDonut(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3341
+ renderDonut(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1782
3342
  break;
1783
3343
  case "radar": {
1784
- 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 }] : [];
1785
- renderRadar(body, { axes: spec.axes ?? spec.labels ?? [], series, max: spec.max, levels: spec.levels, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3344
+ 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 }] : [];
3345
+ renderRadar(body, { axes: view.axes ?? view.labels ?? [], series, max: view.max, levels: view.levels, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1786
3346
  break;
1787
3347
  }
1788
3348
  case "heatmap":
1789
- 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 });
3349
+ 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 });
1790
3350
  break;
1791
3351
  case "calendar":
1792
- 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 });
3352
+ 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 });
1793
3353
  break;
1794
3354
  case "sparkline":
1795
- renderSparkline(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3355
+ renderSparkline(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1796
3356
  break;
1797
3357
  case "gauge":
1798
- renderGauge(body, { value: spec.values?.[0] ?? 0, max: spec.max, tone: spec.tone, label: spec.labels?.[0], formatValue });
3358
+ renderGauge(body, { value: view.values?.[0] ?? 0, max: view.max, tone: view.tone, label: view.labels?.[0], formatValue });
1799
3359
  break;
1800
3360
  case "scatter":
1801
- renderScatter(body, { points: spec.points ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3361
+ renderScatter(body, { points: view.points ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1802
3362
  break;
1803
3363
  default:
1804
- renderEmpty(body, spec.emptyLabel);
3364
+ renderEmpty(body, view.emptyLabel);
1805
3365
  }
1806
- });
3366
+ }, legendState, { note, onZoomReset: zoomReset });
3367
+ if (!loading) {
3368
+ const graphic = root.querySelector('[role="img"]');
3369
+ if (graphic && !graphic.getAttribute("aria-label")) {
3370
+ graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3371
+ }
3372
+ }
3373
+ if (loading) return;
3374
+ paintChartMarks(root, view, spec, formatValue, warnedMarks);
3375
+ bindZoomGesture();
1807
3376
  };
1808
- chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current.tooltip !== false });
3377
+ chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current2.tooltip !== false });
1809
3378
  const unbindEvents = bindChartEvents(root);
1810
3379
  render();
3380
+ observeFluidWidth(root, render);
1811
3381
  return {
1812
3382
  el: root,
1813
- spec: current,
3383
+ /** 归一 + 推断后的当前规格(getter:update/append 换引用后永远读到最新) */
3384
+ get spec() {
3385
+ return current2;
3386
+ },
1814
3387
  update(next) {
1815
- current = normalizeChartSpec(next);
3388
+ const prev = current2;
3389
+ current2 = normalizeChartSpec(next);
3390
+ if (zoomWindow) {
3391
+ const sameLabels = JSON.stringify(prev.labels ?? null) === JSON.stringify(current2.labels ?? null);
3392
+ const t2 = current2.type ?? inferChartType(current2);
3393
+ const zoomable = isZoomableType(t2) && (current2.zoom === "x" || current2.zoom === "brush");
3394
+ if (!sameLabels || !zoomable) zoomWindow = null;
3395
+ else {
3396
+ const len = fullLength();
3397
+ if (len < 2) zoomWindow = null;
3398
+ else {
3399
+ const from = clampNum(zoomWindow.from, 0, len - 1);
3400
+ const to = clampNum(zoomWindow.to, 0, len - 1);
3401
+ zoomWindow = from <= to ? { from, to } : null;
3402
+ }
3403
+ }
3404
+ }
3405
+ render();
3406
+ },
3407
+ append(label, values, opts) {
3408
+ const t2 = current2.type ?? inferChartType(current2);
3409
+ if (!isStreamableType(t2)) {
3410
+ if (!warnedAppend) {
3411
+ warnedAppend = true;
3412
+ console.warn(`[icen:chart] append \u4EC5\u652F\u6301 line/area/vbar\uFF08\u5F53\u524D ${String(current2.type ?? t2)}\uFF09\uFF0C\u5DF2\u5FFD\u7565`);
3413
+ }
3414
+ return;
3415
+ }
3416
+ const labels = current2.labels ?? (current2.labels = []);
3417
+ labels.push(String(label ?? ""));
3418
+ const vals = Array.isArray(values) ? values : [];
3419
+ if (current2.series && current2.series.length > 0) {
3420
+ for (const [i, s] of current2.series.entries()) s.values.push(toNum(vals[i]) ?? 0);
3421
+ } else {
3422
+ const v = current2.values ?? (current2.values = []);
3423
+ v.push(toNum(vals[0]) ?? 0);
3424
+ }
3425
+ const maxPoints = opts?.maxPoints != null ? Math.max(1, Math.floor(toNum(opts.maxPoints) ?? 0)) : 0;
3426
+ let dropped = 0;
3427
+ if (maxPoints > 0) {
3428
+ while (labels.length > maxPoints) {
3429
+ labels.shift();
3430
+ if (current2.series) for (const s of current2.series) s.values.shift();
3431
+ else current2.values?.shift();
3432
+ dropped += 1;
3433
+ }
3434
+ }
3435
+ if (zoomWindow) {
3436
+ const len = Math.max(1, labels.length);
3437
+ const size = zoomWindow.to - zoomWindow.from + 1;
3438
+ const to = clampNum(zoomWindow.to - dropped + 1, 0, len - 1);
3439
+ zoomWindow = { from: Math.max(0, to - size + 1), to };
3440
+ }
1816
3441
  render();
1817
3442
  },
1818
3443
  on(name, listener) {
@@ -1822,13 +3447,29 @@ function renderChart(el, raw) {
1822
3447
  root.addEventListener(`icen:chart-${name}`, handler);
1823
3448
  return () => root.removeEventListener(`icen:chart-${name}`, handler);
1824
3449
  },
3450
+ toDataURL: createChartToDataURL(root),
1825
3451
  destroy() {
3452
+ releaseFluidWidth(root);
3453
+ hiddenLegendKeys.delete(root);
3454
+ zoomDragCleanup?.();
1826
3455
  root.textContent = "";
3456
+ root.classList.remove("is-loading");
1827
3457
  unbindEvents();
1828
3458
  chartTooltip().hidden = true;
1829
3459
  }
1830
3460
  };
1831
3461
  }
3462
+ function svgClientPoint(svg, clientX, clientY, viewBoxWidth, viewBoxHeight) {
3463
+ const rect = svg.getBoundingClientRect();
3464
+ const scale = Math.min(rect.width / viewBoxWidth, rect.height / viewBoxHeight);
3465
+ if (!Number.isFinite(scale) || scale <= 0) {
3466
+ return { x: viewBoxWidth / 2, y: viewBoxHeight / 2 };
3467
+ }
3468
+ return {
3469
+ x: (clientX - rect.left - (rect.width - viewBoxWidth * scale) / 2) / scale,
3470
+ y: (clientY - rect.top - (rect.height - viewBoxHeight * scale) / 2) / scale
3471
+ };
3472
+ }
1832
3473
  var GRAPH_W = 360;
1833
3474
  var GRAPH_H = 260;
1834
3475
  var GRAPH_PAD = 28;
@@ -1877,23 +3518,23 @@ function buildHead(headClass) {
1877
3518
  const head = h("button", headClass);
1878
3519
  head.type = "button";
1879
3520
  head.setAttribute("aria-expanded", "false");
1880
- const iconEl = h("span", "ai-item-icon");
3521
+ const iconEl = h("span", "icen-ai-item-icon");
1881
3522
  iconEl.setAttribute("aria-hidden", "true");
1882
- const main = h("span", "ai-item-main");
1883
- const titleEl = h("span", "ai-item-title");
1884
- const subEl = h("span", "ai-item-sub");
1885
- const statusEl = h("span", "ai-item-status");
3523
+ const main = h("span", "icen-ai-item-main");
3524
+ const titleEl = h("span", "icen-ai-item-title");
3525
+ const subEl = h("span", "icen-ai-item-sub");
3526
+ const statusEl = h("span", "icen-ai-item-status");
1886
3527
  statusEl.setAttribute("role", "img");
1887
- const metaEl = h("span", "ai-item-meta");
3528
+ const metaEl = h("span", "icen-ai-item-meta");
1888
3529
  main.append(titleEl, subEl);
1889
3530
  head.append(iconEl, main, statusEl, metaEl);
1890
3531
  return { head, iconEl, titleEl, subEl, statusEl, metaEl };
1891
3532
  }
1892
3533
  function buildIo(label) {
1893
- const root = h("div", "ai-tool-io");
1894
- root.append(h("div", "ai-tool-io-label", label));
1895
- const pre = h("pre", "ai-tool-io-content");
1896
- const media = h("div", "ai-tool-io-media");
3534
+ const root = h("div", "icen-ai-tool-io");
3535
+ root.append(h("div", "icen-ai-tool-io-label", label));
3536
+ const pre = h("pre", "icen-ai-tool-io-content");
3537
+ const media = h("div", "icen-ai-tool-io-media");
1897
3538
  media.hidden = true;
1898
3539
  root.append(pre, media);
1899
3540
  return { root, pre, media };
@@ -1902,9 +3543,9 @@ function chartSpecOf(value) {
1902
3543
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1903
3544
  const v = value;
1904
3545
  if (v.type === "chart" && v.spec && typeof v.spec === "object") return v.spec;
1905
- const t = typeof v.type === "string" ? v.type : void 0;
3546
+ const t2 = typeof v.type === "string" ? v.type : void 0;
1906
3547
  const looksChart = Array.isArray(v.series) || Array.isArray(v.segments) || Array.isArray(v.points) || Array.isArray(v.dates) || Array.isArray(v.labels) && Array.isArray(v.values);
1907
- if (looksChart && (t === void 0 || typeof t === "string")) return v;
3548
+ if (looksChart && (t2 === void 0 || typeof t2 === "string")) return v;
1908
3549
  return null;
1909
3550
  }
1910
3551
  function setIo(io, value, allowChart = true) {
@@ -1914,7 +3555,7 @@ function setIo(io, value, allowChart = true) {
1914
3555
  io.pre.hidden = true;
1915
3556
  io.media.replaceChildren();
1916
3557
  const holder = document.createElement("div");
1917
- holder.className = "ai-tool-io-chart";
3558
+ holder.className = "icen-ai-tool-io-chart";
1918
3559
  io.media.appendChild(holder);
1919
3560
  renderChart(holder, chartSpec);
1920
3561
  io.media.hidden = false;
@@ -1950,29 +3591,29 @@ function defaultExpanded(m) {
1950
3591
  return false;
1951
3592
  }
1952
3593
  function buildApproval() {
1953
- const root = h("div", "ai-tool-approval");
1954
- const reason = h("div", "ai-tool-approval-reason");
3594
+ const root = h("div", "icen-ai-tool-approval");
3595
+ const reason = h("div", "icen-ai-tool-approval-reason");
1955
3596
  reason.hidden = true;
1956
- const allow = h("button", "btn btn-sm btn-primary", "\u5141\u8BB8");
3597
+ const allow = h("button", "icen-btn icen-btn-sm icen-btn-primary", t("aiTool.allow"));
1957
3598
  allow.type = "button";
1958
- allow.setAttribute("data-ai-approve", "");
1959
- const deny = h("button", "btn btn-sm", "\u62D2\u7EDD");
3599
+ allow.setAttribute("data-icen-ai-approve", "");
3600
+ const deny = h("button", "icen-btn icen-btn-sm", t("aiTool.reject"));
1960
3601
  deny.type = "button";
1961
- deny.setAttribute("data-ai-reject", "");
3602
+ deny.setAttribute("data-icen-ai-reject", "");
1962
3603
  root.append(reason, allow, deny);
1963
3604
  return { root, reason };
1964
3605
  }
1965
3606
  function applyTint(item, model) {
1966
3607
  const tint = getAiKind(model.kind).tint;
1967
- if (tint) item.style.setProperty("--ai-item-tint", `var(--token-${tint})`);
3608
+ if (tint) item.style.setProperty("--ai-item-tint", `var(--icen-token-${tint})`);
1968
3609
  else item.style.removeProperty("--ai-item-tint");
1969
3610
  }
1970
3611
  function applyKindVisual(parts, model) {
1971
3612
  const kind = getAiKind(model.kind);
1972
3613
  parts.titleEl.textContent = kind.label || model.name;
1973
3614
  parts.iconEl.replaceChildren();
1974
- const svg2 = svgIcon(kind.icon);
1975
- if (svg2) parts.iconEl.append(svg2);
3615
+ const svg = svgIcon(kind.icon);
3616
+ if (svg) parts.iconEl.append(svg);
1976
3617
  const sub = summarizeInput(model);
1977
3618
  parts.subEl.textContent = sub;
1978
3619
  parts.subEl.hidden = !sub;
@@ -1987,15 +3628,15 @@ function renderAiToolCall(el, model) {
1987
3628
  return { el, update: () => void 0 };
1988
3629
  }
1989
3630
  const item = el;
1990
- let current = model;
1991
- item.className = `ai-tool ai-tool--${model.kind}`;
1992
- item.dataset.aiId = model.id;
1993
- item.dataset.aiKind = model.kind;
1994
- const parts = buildHead("ai-tool-head");
1995
- const body = h("div", "ai-tool-body");
3631
+ let current2 = model;
3632
+ item.className = `icen-ai-tool icen-ai-tool--${model.kind}`;
3633
+ item.dataset.icenAiId = model.id;
3634
+ item.dataset.icenAiKind = model.kind;
3635
+ const parts = buildHead("icen-ai-tool-head");
3636
+ const body = h("div", "icen-ai-tool-body");
1996
3637
  body.hidden = true;
1997
- const inputIo = buildIo("\u8F93\u5165");
1998
- const outputIo = buildIo("\u8F93\u51FA");
3638
+ const inputIo = buildIo(t("common.input"));
3639
+ const outputIo = buildIo(t("common.output"));
1999
3640
  const approval = buildApproval();
2000
3641
  body.append(inputIo.root, outputIo.root, approval.root);
2001
3642
  item.append(parts.head, body);
@@ -2019,12 +3660,12 @@ function renderAiToolCall(el, model) {
2019
3660
  approval.reason.hidden = !reason;
2020
3661
  if (!item.dataset.aiUserToggled && defaultExpanded(m)) setOpen(true);
2021
3662
  };
2022
- apply(current);
3663
+ apply(current2);
2023
3664
  return {
2024
3665
  el: item,
2025
3666
  update(patch) {
2026
- current = { ...current, ...patch };
2027
- apply(current);
3667
+ current2 = { ...current2, ...patch };
3668
+ apply(current2);
2028
3669
  }
2029
3670
  };
2030
3671
  }
@@ -2033,15 +3674,15 @@ function renderAiSubagent(el, model) {
2033
3674
  return { el, update: () => void 0 };
2034
3675
  }
2035
3676
  const item = el;
2036
- let current = model;
2037
- item.className = "ai-subagent";
2038
- item.dataset.aiId = model.id;
2039
- item.dataset.aiKind = model.kind;
2040
- const parts = buildHead("ai-subagent-head");
2041
- const body = h("div", "ai-subagent-body");
3677
+ let current2 = model;
3678
+ item.className = "icen-ai-subagent";
3679
+ item.dataset.icenAiId = model.id;
3680
+ item.dataset.icenAiKind = model.kind;
3681
+ const parts = buildHead("icen-ai-subagent-head");
3682
+ const body = h("div", "icen-ai-subagent-body");
2042
3683
  body.hidden = true;
2043
- const stream = h("div", "ai-subagent-stream");
2044
- const result = h("div", "ai-subagent-result");
3684
+ const stream = h("div", "icen-ai-subagent-stream");
3685
+ const result = h("div", "icen-ai-subagent-result");
2045
3686
  result.hidden = true;
2046
3687
  body.append(stream, result);
2047
3688
  item.append(parts.head, body);
@@ -2081,7 +3722,7 @@ function renderAiSubagent(el, model) {
2081
3722
  applyTint(item, m);
2082
3723
  applyKindVisual(parts, m);
2083
3724
  const steps = m.activities?.length ?? 0;
2084
- const meta = [m.durationMs != null ? formatDuration(m.durationMs) : "", steps > 0 ? `${steps} \u6B65` : ""].filter(Boolean).join(" \xB7 ");
3725
+ const meta = [m.durationMs != null ? formatDuration(m.durationMs) : "", steps > 0 ? t("common.steps", { p0: steps }) : ""].filter(Boolean).join(" \xB7 ");
2085
3726
  applyStatusMeta(parts, m.status, meta);
2086
3727
  renderActivities(m.activities);
2087
3728
  const receipt = compactValue(m.output);
@@ -2089,12 +3730,12 @@ function renderAiSubagent(el, model) {
2089
3730
  result.hidden = !receipt;
2090
3731
  if (!item.dataset.aiUserToggled && defaultExpanded(m)) setOpen(true);
2091
3732
  };
2092
- apply(current);
3733
+ apply(current2);
2093
3734
  return {
2094
3735
  el: item,
2095
3736
  update(patch) {
2096
- current = { ...current, ...patch };
2097
- apply(current);
3737
+ current2 = { ...current2, ...patch };
3738
+ apply(current2);
2098
3739
  }
2099
3740
  };
2100
3741
  }
@@ -2103,8 +3744,8 @@ function setupItem(item, kind) {
2103
3744
  const flag = kind === "tool" ? "__icenAiToolInit" : "__icenAiSubagentInit";
2104
3745
  if (marked[flag]) return () => void 0;
2105
3746
  marked[flag] = true;
2106
- const headClass = kind === "tool" ? ".ai-tool-head" : ".ai-subagent-head";
2107
- const bodyClass = kind === "tool" ? ".ai-tool-body" : ".ai-subagent-body";
3747
+ const headClass = kind === "tool" ? ".icen-ai-tool-head" : ".icen-ai-subagent-head";
3748
+ const bodyClass = kind === "tool" ? ".icen-ai-tool-body" : ".icen-ai-subagent-body";
2108
3749
  const head = item.querySelector(`:scope > ${headClass}`);
2109
3750
  const body = item.querySelector(`:scope > ${bodyClass}`);
2110
3751
  const setOpen = (open, fire = true) => {
@@ -2117,25 +3758,25 @@ function setupItem(item, kind) {
2117
3758
  const onCardClick = (ev) => {
2118
3759
  const target = ev.target;
2119
3760
  if (!(target instanceof Element)) return;
2120
- const ownerOf = (node) => node.closest(".ai-tool, .ai-subagent");
2121
- const approveBtn = target.closest("[data-ai-approve]");
3761
+ const ownerOf = (node) => node.closest(".icen-ai-tool, .icen-ai-subagent");
3762
+ const approveBtn = target.closest("[data-icen-ai-approve]");
2122
3763
  if (approveBtn && ownerOf(approveBtn) === item) {
2123
- emitIcen(item, "icen:ai-approve", { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" });
3764
+ emitIcen(item, "icen:ai-approve", { id: item.dataset.icenAiId ?? "", kind: item.dataset.icenAiKind ?? "" });
2124
3765
  return;
2125
3766
  }
2126
- const rejectBtn = target.closest("[data-ai-reject]");
3767
+ const rejectBtn = target.closest("[data-icen-ai-reject]");
2127
3768
  if (rejectBtn && ownerOf(rejectBtn) === item) {
2128
- emitIcen(item, "icen:ai-reject", { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" });
3769
+ emitIcen(item, "icen:ai-reject", { id: item.dataset.icenAiId ?? "", kind: item.dataset.icenAiKind ?? "" });
2129
3770
  return;
2130
3771
  }
2131
- const headEl = target.closest(".ai-tool-head, .ai-subagent-head");
3772
+ const headEl = target.closest(".icen-ai-tool-head, .icen-ai-subagent-head");
2132
3773
  if (!headEl || ownerOf(headEl) !== item || !head) return;
2133
3774
  item.dataset.aiUserToggled = "1";
2134
3775
  setOpen(head.getAttribute("aria-expanded") !== "true");
2135
3776
  };
2136
3777
  item.addEventListener("click", onCardClick);
2137
3778
  if (body?.hidden) {
2138
- const kindName = item.dataset.aiKind ?? "";
3779
+ const kindName = item.dataset.icenAiKind ?? "";
2139
3780
  const isErr = item.classList.contains("is-error");
2140
3781
  const isApproval = item.classList.contains("is-approval");
2141
3782
  if (isErr || isApproval || kindName === "chart") {
@@ -2157,14 +3798,14 @@ function initItems(root, selector, kind) {
2157
3798
  return items.map((item) => setupItem(item, kind));
2158
3799
  }
2159
3800
  function initAiTool(root) {
2160
- const cleanups = initItems(root, ".ai-tool", "tool");
3801
+ const cleanups = initItems(root, ".icen-ai-tool", "tool");
2161
3802
  return () => {
2162
3803
  for (const fn of cleanups) fn();
2163
3804
  cleanups.length = 0;
2164
3805
  };
2165
3806
  }
2166
3807
  function initAiSubagent(root) {
2167
- const cleanups = initItems(root, ".ai-subagent", "subagent");
3808
+ const cleanups = initItems(root, ".icen-ai-subagent", "subagent");
2168
3809
  return () => {
2169
3810
  for (const fn of cleanups) fn();
2170
3811
  cleanups.length = 0;