@icen.ai/ui 0.10.0 → 0.11.1
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.
- package/AGENTS.md +79 -309
- package/LICENSE +21 -0
- package/README.md +43 -54
- package/dist/base.css +68 -22
- package/dist/behaviors/accordion.mjs +1 -1
- package/dist/behaviors/ai-branch.mjs +14 -0
- package/dist/behaviors/ai-chat.d.mts +2 -2
- package/dist/behaviors/ai-chat.mjs +66 -10
- package/dist/behaviors/ai-composer.d.mts +5 -5
- package/dist/behaviors/ai-composer.mjs +34 -10
- package/dist/behaviors/ai-core.mjs +14 -0
- package/dist/behaviors/ai-diff.mjs +14 -0
- package/dist/behaviors/ai-feedback.mjs +14 -0
- package/dist/behaviors/ai-panel.d.mts +2 -2
- package/dist/behaviors/ai-panel.mjs +14 -0
- package/dist/behaviors/ai-provider.d.mts +1 -1
- package/dist/behaviors/ai-provider.mjs +14 -0
- package/dist/behaviors/ai-threads.mjs +14 -0
- package/dist/behaviors/ai-tool.d.mts +1 -1
- package/dist/behaviors/ai-tool.mjs +299 -24
- package/dist/behaviors/ai-tools.mjs +1179 -28
- package/dist/behaviors/autocomplete.d.mts +1 -1
- package/dist/behaviors/autocomplete.mjs +14 -0
- package/dist/behaviors/back-top.mjs +14 -0
- package/dist/behaviors/carousel.mjs +21 -1
- package/dist/behaviors/cascader.mjs +27 -0
- package/dist/behaviors/charts.d.mts +12 -1
- package/dist/behaviors/charts.mjs +298 -20
- package/dist/behaviors/code-block.mjs +22 -1
- package/dist/behaviors/command-palette.mjs +3 -3
- package/dist/behaviors/context-menu.d.mts +2 -2
- package/dist/behaviors/context-menu.mjs +14 -0
- package/dist/behaviors/controls.d.mts +8 -8
- package/dist/behaviors/controls.mjs +50 -6
- package/dist/behaviors/copy.mjs +14 -0
- package/dist/behaviors/datatable.d.mts +3 -3
- package/dist/behaviors/datatable.mjs +89 -11
- package/dist/behaviors/date-picker.mjs +14 -0
- package/dist/behaviors/events.d.mts +10 -10
- package/dist/behaviors/events.mjs +11 -1
- package/dist/behaviors/form-validate.d.mts +10 -1
- package/dist/behaviors/form-validate.mjs +279 -4611
- package/dist/behaviors/i18n.d.mts +14 -0
- package/dist/behaviors/i18n.mjs +28 -0
- package/dist/behaviors/input.mjs +16 -0
- package/dist/behaviors/kb-access.d.mts +2 -2
- package/dist/behaviors/kb-access.mjs +21 -2
- package/dist/behaviors/kb-acl.d.mts +2 -2
- package/dist/behaviors/kb-acl.mjs +14 -0
- package/dist/behaviors/kb-answer.d.mts +2 -2
- package/dist/behaviors/kb-answer.mjs +298 -23
- package/dist/behaviors/kb-audit.d.mts +2 -2
- package/dist/behaviors/kb-audit.mjs +14 -0
- package/dist/behaviors/kb-canvas.d.mts +3 -3
- package/dist/behaviors/kb-canvas.mjs +14 -0
- package/dist/behaviors/kb-chain.d.mts +2 -2
- package/dist/behaviors/kb-chain.mjs +14 -0
- package/dist/behaviors/kb-checkpoint.d.mts +2 -2
- package/dist/behaviors/kb-checkpoint.mjs +14 -0
- package/dist/behaviors/kb-chunks.d.mts +2 -2
- package/dist/behaviors/kb-chunks.mjs +14 -0
- package/dist/behaviors/kb-citation.d.mts +2 -2
- package/dist/behaviors/kb-citation.mjs +33 -6
- package/dist/behaviors/kb-clarify.d.mts +2 -2
- package/dist/behaviors/kb-clarify.mjs +14 -0
- package/dist/behaviors/kb-conflict.d.mts +2 -2
- package/dist/behaviors/kb-conflict.mjs +14 -0
- package/dist/behaviors/kb-connector.d.mts +2 -2
- package/dist/behaviors/kb-connector.mjs +14 -0
- package/dist/behaviors/kb-core.d.mts +1 -1
- package/dist/behaviors/kb-core.mjs +14 -0
- package/dist/behaviors/kb-eval.d.mts +2 -2
- package/dist/behaviors/kb-eval.mjs +21 -2
- package/dist/behaviors/kb-explain.d.mts +2 -2
- package/dist/behaviors/kb-explain.mjs +26 -2
- package/dist/behaviors/kb-filter.d.mts +2 -2
- package/dist/behaviors/kb-filter.mjs +21 -2
- package/dist/behaviors/kb-gap.d.mts +2 -2
- package/dist/behaviors/kb-gap.mjs +14 -0
- package/dist/behaviors/kb-hittest.d.mts +2 -2
- package/dist/behaviors/kb-hittest.mjs +15 -1
- package/dist/behaviors/kb-metadata.mjs +19 -0
- package/dist/behaviors/kb-passage.d.mts +2 -2
- package/dist/behaviors/kb-passage.mjs +14 -0
- package/dist/behaviors/kb-pipeline.d.mts +2 -2
- package/dist/behaviors/kb-pipeline.mjs +14 -0
- package/dist/behaviors/kb-qa.mjs +14 -0
- package/dist/behaviors/kb-rerank.d.mts +2 -2
- package/dist/behaviors/kb-rerank.mjs +14 -0
- package/dist/behaviors/kb-retrieval.d.mts +2 -2
- package/dist/behaviors/kb-retrieval.mjs +31 -4
- package/dist/behaviors/kb-review.d.mts +2 -2
- package/dist/behaviors/kb-review.mjs +21 -2
- package/dist/behaviors/kb-sandbox.d.mts +2 -2
- package/dist/behaviors/kb-sandbox.mjs +20 -1
- package/dist/behaviors/kb-segment.d.mts +2 -2
- package/dist/behaviors/kb-segment.mjs +15 -1
- package/dist/behaviors/kb-select.mjs +21 -2
- package/dist/behaviors/kb-sources.d.mts +2 -2
- package/dist/behaviors/kb-sources.mjs +14 -0
- package/dist/behaviors/kb-sql.d.mts +2 -2
- package/dist/behaviors/kb-sql.mjs +14 -0
- package/dist/behaviors/kb-trace.d.mts +2 -2
- package/dist/behaviors/kb-trace.mjs +22 -3
- package/dist/behaviors/kb-visibility.d.mts +2 -2
- package/dist/behaviors/kb-visibility.mjs +14 -0
- package/dist/behaviors/kb-who-can.d.mts +2 -2
- package/dist/behaviors/kb-who-can.mjs +21 -2
- package/dist/behaviors/mentions.d.mts +1 -1
- package/dist/behaviors/mentions.mjs +14 -0
- package/dist/behaviors/modal.d.mts +1 -1
- package/dist/behaviors/modal.mjs +14 -0
- package/dist/behaviors/motion.d.mts +16 -0
- package/dist/behaviors/motion.mjs +39 -0
- package/dist/behaviors/notification.d.mts +2 -2
- package/dist/behaviors/notification.mjs +27 -3
- package/dist/behaviors/panel.mjs +14 -0
- package/dist/behaviors/scroll-area.d.mts +17 -0
- package/dist/behaviors/scroll-area.mjs +59 -0
- package/dist/behaviors/select.mjs +21 -2
- package/dist/behaviors/slider.mjs +3 -3
- package/dist/behaviors/split-pane.mjs +2 -0
- package/dist/behaviors/suggestions.mjs +14 -0
- package/dist/behaviors/tabs.mjs +10 -0
- package/dist/behaviors/tag-input.mjs +14 -0
- package/dist/behaviors/theme-switcher.d.mts +2 -2
- package/dist/behaviors/theme-switcher.mjs +30 -2
- package/dist/behaviors/theme.mjs +16 -2
- package/dist/behaviors/toast.d.mts +2 -2
- package/dist/behaviors/toast.mjs +14 -0
- package/dist/behaviors/tree-select.mjs +27 -0
- package/dist/behaviors/tree.mjs +4 -4
- package/dist/behaviors/upload.mjs +14 -0
- package/dist/behaviors/url-safety.d.mts +8 -0
- package/dist/behaviors/url-safety.mjs +11 -0
- package/dist/components/accordion.d.mts +2 -0
- package/dist/components/ai-branch.d.mts +2 -0
- package/dist/components/ai-chat.css +40 -33
- package/dist/components/ai-chat.d.mts +2 -0
- package/dist/components/ai-composer.d.mts +2 -0
- package/dist/components/ai-context.d.mts +2 -0
- package/dist/components/ai-context.mjs +1 -0
- package/dist/components/ai-diff.css +6 -6
- package/dist/components/ai-diff.d.mts +2 -0
- package/dist/components/ai-feedback.d.mts +2 -0
- package/dist/components/ai-files.d.mts +2 -0
- package/dist/components/ai-message.d.mts +2 -0
- package/dist/components/ai-panel.css +12 -10
- package/dist/components/ai-reasoning.d.mts +2 -0
- package/dist/components/ai-subagent.d.mts +2 -0
- package/dist/components/ai-subagent.mjs +1 -0
- package/dist/components/ai-threads.d.mts +2 -0
- package/dist/components/ai-todo.d.mts +2 -0
- package/dist/components/ai-todo.mjs +1 -0
- package/dist/components/ai-tool-call.d.mts +2 -0
- package/dist/components/ai-tool-call.mjs +1 -0
- package/dist/components/ai-tool.css +16 -16
- package/dist/components/ai-usage.d.mts +2 -0
- package/dist/components/alert.d.mts +2 -0
- package/dist/components/autocomplete.css +12 -12
- package/dist/components/autocomplete.d.mts +2 -0
- package/dist/components/avatar.d.mts +2 -0
- package/dist/components/back-top.css +47 -16
- package/dist/components/back-top.d.mts +2 -0
- package/dist/components/badge.css +1 -1
- package/dist/components/badge.d.mts +2 -0
- package/dist/components/breadcrumb.css +26 -8
- package/dist/components/breadcrumb.d.mts +2 -0
- package/dist/components/btn.css +67 -62
- package/dist/components/btn.d.mts +2 -0
- package/dist/components/card.css +22 -22
- package/dist/components/card.d.mts +2 -0
- package/dist/components/carousel.d.mts +2 -0
- package/dist/components/cascader.css +56 -35
- package/dist/components/cascader.d.mts +2 -0
- package/dist/components/chart-area.css +46 -0
- package/dist/components/chart-area.d.mts +2 -0
- package/dist/components/chart-bar.css +66 -19
- package/dist/components/chart-bar.d.mts +2 -0
- package/dist/components/chart-calendar.d.mts +2 -0
- package/dist/components/chart-gauge.css +23 -3
- package/dist/components/chart-gauge.d.mts +2 -0
- package/dist/components/chart-graph.css +15 -3
- package/dist/components/chart-graph.d.mts +2 -0
- package/dist/components/chart-heatmap.css +117 -95
- package/dist/components/chart-heatmap.d.mts +2 -0
- package/dist/components/chart-line.css +54 -0
- package/dist/components/chart-line.d.mts +2 -0
- package/dist/components/chart-map.d.mts +2 -0
- package/dist/components/chart-pie.css +29 -0
- package/dist/components/chart-pie.d.mts +2 -0
- package/dist/components/chart-radar.css +50 -1
- package/dist/components/chart-radar.d.mts +2 -0
- package/dist/components/chart-scatter.css +39 -2
- package/dist/components/chart-scatter.d.mts +2 -0
- package/dist/components/chart-sparkline.css +20 -0
- package/dist/components/chart-sparkline.d.mts +2 -0
- package/dist/components/chart-stack.css +16 -5
- package/dist/components/chart-stack.d.mts +2 -0
- package/dist/components/charts.css +109 -35
- package/dist/components/charts.d.mts +2 -0
- package/dist/components/code-block.css +10 -8
- package/dist/components/code-block.d.mts +2 -0
- package/dist/components/command-palette.css +45 -38
- package/dist/components/command-palette.d.mts +2 -0
- package/dist/components/content.css +62 -57
- package/dist/components/context-menu.d.mts +2 -0
- package/dist/components/copy.css +10 -10
- package/dist/components/copy.d.mts +2 -0
- package/dist/components/datatable.css +72 -59
- package/dist/components/datatable.d.mts +2 -0
- package/dist/components/date-picker.css +26 -26
- package/dist/components/date-picker.d.mts +2 -0
- package/dist/components/desc.d.mts +2 -0
- package/dist/components/dropdown.d.mts +2 -0
- package/dist/components/empty.css +16 -16
- package/dist/components/empty.d.mts +2 -0
- package/dist/components/feedback.css +31 -29
- package/dist/components/form-validate.css +20 -6
- package/dist/components/form-validate.d.mts +2 -0
- package/dist/components/form.css +17 -14
- package/dist/components/form.d.mts +2 -0
- package/dist/components/icon.css +21 -10
- package/dist/components/icon.d.mts +2 -0
- package/dist/components/input.css +22 -22
- package/dist/components/input.d.mts +2 -0
- package/dist/components/kb-access.d.mts +2 -0
- package/dist/components/kb-acl.d.mts +2 -0
- package/dist/components/kb-agent.css +134 -55
- package/dist/components/kb-answer.d.mts +2 -0
- package/dist/components/kb-audit.d.mts +2 -0
- package/dist/components/kb-canvas.d.mts +2 -0
- package/dist/components/kb-chain.d.mts +2 -0
- package/dist/components/kb-checkpoint.d.mts +2 -0
- package/dist/components/kb-chunks.d.mts +2 -0
- package/dist/components/kb-citation.d.mts +2 -0
- package/dist/components/kb-clarify.d.mts +2 -0
- package/dist/components/kb-conflict.d.mts +2 -0
- package/dist/components/kb-connector.d.mts +2 -0
- package/dist/components/kb-data.css +192 -80
- package/dist/components/kb-eval.d.mts +2 -0
- package/dist/components/kb-explain.d.mts +2 -0
- package/dist/components/kb-filter.d.mts +2 -0
- package/dist/components/kb-gap.d.mts +2 -0
- package/dist/components/kb-ground.css +165 -73
- package/dist/components/kb-hittest.d.mts +2 -0
- package/dist/components/kb-ingest.css +308 -113
- package/dist/components/kb-metadata.d.mts +2 -0
- package/dist/components/kb-ops.css +189 -75
- package/dist/components/kb-passage.d.mts +2 -0
- package/dist/components/kb-perm.css +158 -87
- package/dist/components/kb-pipeline.d.mts +2 -0
- package/dist/components/kb-qa.d.mts +2 -0
- package/dist/components/kb-rerank.d.mts +2 -0
- package/dist/components/kb-retrieval.d.mts +2 -0
- package/dist/components/kb-review.d.mts +2 -0
- package/dist/components/kb-sandbox.d.mts +2 -0
- package/dist/components/kb-search.css +353 -116
- package/dist/components/kb-segment.d.mts +2 -0
- package/dist/components/kb-sources.d.mts +2 -0
- package/dist/components/kb-sql.d.mts +2 -0
- package/dist/components/kb-trace.d.mts +2 -0
- package/dist/components/kb-visibility.d.mts +2 -0
- package/dist/components/kb-who-can.d.mts +2 -0
- package/dist/components/kb.css +60 -36
- package/dist/components/kb.d.mts +2 -0
- package/dist/components/kbd.d.mts +2 -0
- package/dist/components/layout.css +10 -10
- package/dist/components/layout.d.mts +2 -0
- package/dist/components/list.d.mts +2 -0
- package/dist/components/material-chinese.css +10 -0
- package/dist/components/material-soviet.css +10 -0
- package/dist/components/material.css +61 -18
- package/dist/components/media-card.d.mts +2 -0
- package/dist/components/media.css +22 -27
- package/dist/components/mentions.css +18 -17
- package/dist/components/mentions.d.mts +2 -0
- package/dist/components/menu.css +32 -28
- package/dist/components/modal.css +30 -27
- package/dist/components/modal.d.mts +2 -0
- package/dist/components/nav.css +48 -44
- package/dist/components/nav.d.mts +2 -0
- package/dist/components/notification.css +31 -25
- package/dist/components/notification.d.mts +2 -0
- package/dist/components/pagination.css +15 -13
- package/dist/components/pagination.d.mts +2 -0
- package/dist/components/panel.css +19 -20
- package/dist/components/panel.d.mts +2 -0
- package/dist/components/pill.css +8 -7
- package/dist/components/pill.d.mts +2 -0
- package/dist/components/popover.css +32 -23
- package/dist/components/popover.d.mts +2 -0
- package/dist/components/progress.d.mts +2 -0
- package/dist/components/rating.d.mts +2 -0
- package/dist/components/result.d.mts +2 -0
- package/dist/components/scroll-area.css +84 -112
- package/dist/components/scroll-area.d.mts +2 -0
- package/dist/components/scroll-area.mjs +1 -0
- package/dist/components/segmented.css +47 -29
- package/dist/components/segmented.d.mts +2 -0
- package/dist/components/select.css +80 -41
- package/dist/components/select.d.mts +2 -0
- package/dist/components/sidebar.css +42 -38
- package/dist/components/sidebar.d.mts +2 -0
- package/dist/components/skeleton.d.mts +2 -0
- package/dist/components/slider.css +26 -22
- package/dist/components/slider.d.mts +2 -0
- package/dist/components/spinner.d.mts +2 -0
- package/dist/components/split-pane.css +16 -7
- package/dist/components/split-pane.d.mts +2 -0
- package/dist/components/stat.css +17 -16
- package/dist/components/stat.d.mts +2 -0
- package/dist/components/steps.css +26 -26
- package/dist/components/steps.d.mts +2 -0
- package/dist/components/switch.css +78 -39
- package/dist/components/switch.d.mts +2 -0
- package/dist/components/table.css +54 -32
- package/dist/components/table.d.mts +2 -0
- package/dist/components/tabs.css +53 -32
- package/dist/components/tabs.d.mts +2 -0
- package/dist/components/tag-input.css +12 -8
- package/dist/components/tag-input.d.mts +2 -0
- package/dist/components/tag.css +20 -12
- package/dist/components/tag.d.mts +2 -0
- package/dist/components/theme-switcher.css +7 -7
- package/dist/components/theme-switcher.d.mts +2 -0
- package/dist/components/timeline.d.mts +2 -0
- package/dist/components/toast.css +34 -30
- package/dist/components/toast.d.mts +2 -0
- package/dist/components/toolbar.css +19 -18
- package/dist/components/toolbar.d.mts +2 -0
- package/dist/components/tooltip.css +9 -8
- package/dist/components/tooltip.d.mts +2 -0
- package/dist/components/tree-select.css +63 -40
- package/dist/components/tree-select.d.mts +2 -0
- package/dist/components/tree.d.mts +2 -0
- package/dist/components/upload.css +9 -11
- package/dist/components/upload.d.mts +2 -0
- package/dist/index.d.mts +85 -84
- package/dist/index.mjs +14644 -13935
- package/dist/react.d.mts +18 -18
- package/dist/react.mjs +377 -36
- package/dist/registry.json +797 -64
- package/dist/tokens/colors.css +6 -0
- package/dist/tokens/design.css +137 -31
- package/dist/tokens/dtcg.json +9592 -2008
- package/dist/tokens/figma.variables.json +7451 -2141
- package/dist/tokens/motion.css +51 -0
- package/dist/tokens/pixel.css +10 -0
- package/dist/tokens/scrollbars.css +40 -0
- package/dist/tokens/tokens-studio.json +8390 -1142
- package/dist/tokens/typography.css +33 -0
- package/dist/tokens.css +402 -82
- package/dist/ui.css +4196 -2163
- package/dist/vue.d.mts +17 -17
- package/dist/vue.mjs +371 -34
- package/docs/spec/charts-scale-a11y.md +115 -0
- package/docs/spec/design-philosophy.md +5 -5
- package/docs/spec/design-primitives.md +10 -10
- package/docs/spec/motion-typography.md +105 -0
- package/docs/spec/scrollbars.md +46 -0
- package/package.json +17 -3
|
@@ -21,6 +21,7 @@ var ICEN_LOCALE_ZH_CN = {
|
|
|
21
21
|
"aiChat.roleTool": "\u5DE5",
|
|
22
22
|
"aiChat.roleUser": "\u6211",
|
|
23
23
|
"aiChat.thinking": "\u601D\u8003 {p0}",
|
|
24
|
+
"aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
|
|
24
25
|
/* ── aiComposer ── */
|
|
25
26
|
"aiComposer.attachAgent": "\u4EE3\u7406",
|
|
26
27
|
"aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
|
|
@@ -203,6 +204,19 @@ var ICEN_LOCALE_ZH_CN = {
|
|
|
203
204
|
"charts.noData": "\u6682\u65E0\u6570\u636E",
|
|
204
205
|
"charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
|
|
205
206
|
"charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
|
|
207
|
+
"charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
|
|
208
|
+
"charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
|
|
209
|
+
"charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
|
|
210
|
+
"charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
|
|
211
|
+
"charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
|
|
212
|
+
"charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
|
|
213
|
+
"charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
|
|
214
|
+
"charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
|
|
215
|
+
"charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
|
|
216
|
+
"charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
|
|
217
|
+
"charts.a11y.trendDown": "\u4E0B\u964D",
|
|
218
|
+
"charts.a11y.trendFlat": "\u6301\u5E73",
|
|
219
|
+
"charts.a11y.trendUp": "\u4E0A\u5347",
|
|
206
220
|
"charts.type.area": "\u9762\u79EF\u56FE",
|
|
207
221
|
"charts.type.donut": "\u73AF\u5F62\u56FE",
|
|
208
222
|
"charts.type.gauge": "\u4EEA\u8868\u76D8",
|
|
@@ -1241,6 +1255,15 @@ function svgIcon(svg) {
|
|
|
1241
1255
|
return parseSvg(svg);
|
|
1242
1256
|
}
|
|
1243
1257
|
|
|
1258
|
+
// src/behaviors/url-safety.ts
|
|
1259
|
+
function safeUrl(uri) {
|
|
1260
|
+
const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
|
|
1261
|
+
if (!s) return void 0;
|
|
1262
|
+
if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
|
|
1263
|
+
if (/^data:\s*text\/html/.test(s)) return void 0;
|
|
1264
|
+
return uri;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1244
1267
|
// src/behaviors/ai-chat.ts
|
|
1245
1268
|
var ICON_COPY = iconHTML("copy");
|
|
1246
1269
|
var ICON_RETRY = iconHTML("refresh");
|
|
@@ -1250,10 +1273,9 @@ var ROLE_AVATAR = {
|
|
|
1250
1273
|
system: t("aiChat.roleSystem"),
|
|
1251
1274
|
tool: t("aiChat.roleTool")
|
|
1252
1275
|
};
|
|
1253
|
-
function
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1256
|
-
return uri;
|
|
1276
|
+
function safeContentUrl(part) {
|
|
1277
|
+
const src = aiContentUrl(part);
|
|
1278
|
+
return src ? safeUrl(src) : void 0;
|
|
1257
1279
|
}
|
|
1258
1280
|
function renderAiContentPart(part) {
|
|
1259
1281
|
if (part.type === "text") {
|
|
@@ -1263,7 +1285,7 @@ function renderAiContentPart(part) {
|
|
|
1263
1285
|
return span;
|
|
1264
1286
|
}
|
|
1265
1287
|
if (part.type === "image") {
|
|
1266
|
-
const src =
|
|
1288
|
+
const src = safeContentUrl(part);
|
|
1267
1289
|
if (!src) return void 0;
|
|
1268
1290
|
const img = document.createElement("img");
|
|
1269
1291
|
img.className = "icen-ai-msg-media icen-ai-msg-media--image";
|
|
@@ -1273,7 +1295,7 @@ function renderAiContentPart(part) {
|
|
|
1273
1295
|
return img;
|
|
1274
1296
|
}
|
|
1275
1297
|
if (part.type === "audio") {
|
|
1276
|
-
const src =
|
|
1298
|
+
const src = safeContentUrl(part);
|
|
1277
1299
|
if (!src) return void 0;
|
|
1278
1300
|
const audio = document.createElement("audio");
|
|
1279
1301
|
audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
|
|
@@ -1282,7 +1304,7 @@ function renderAiContentPart(part) {
|
|
|
1282
1304
|
return audio;
|
|
1283
1305
|
}
|
|
1284
1306
|
if (part.type === "video") {
|
|
1285
|
-
const src =
|
|
1307
|
+
const src = safeContentUrl(part);
|
|
1286
1308
|
if (!src) return void 0;
|
|
1287
1309
|
const video = document.createElement("video");
|
|
1288
1310
|
video.className = "icen-ai-msg-media icen-ai-msg-media--video";
|
|
@@ -1294,7 +1316,7 @@ function renderAiContentPart(part) {
|
|
|
1294
1316
|
if (part.type === "file") {
|
|
1295
1317
|
const chip = h("span", "icen-ai-msg-file");
|
|
1296
1318
|
chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
|
|
1297
|
-
const href2 = part.url ?
|
|
1319
|
+
const href2 = part.url ? safeUrl(part.url) : void 0;
|
|
1298
1320
|
if (href2 && /^(https?:|data:)/i.test(href2)) {
|
|
1299
1321
|
const a2 = document.createElement("a");
|
|
1300
1322
|
a2.className = "icen-ai-msg-file-link";
|
|
@@ -1307,7 +1329,7 @@ function renderAiContentPart(part) {
|
|
|
1307
1329
|
}
|
|
1308
1330
|
const a = document.createElement("a");
|
|
1309
1331
|
a.className = "icen-ai-msg-link";
|
|
1310
|
-
const href =
|
|
1332
|
+
const href = safeUrl(part.uri);
|
|
1311
1333
|
if (href) a.href = href;
|
|
1312
1334
|
a.textContent = part.name ?? part.uri;
|
|
1313
1335
|
a.title = part.uri;
|
|
@@ -1534,7 +1556,8 @@ function withChrome(el, opts, hasLegend, paint, state, extras) {
|
|
|
1534
1556
|
emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
|
|
1535
1557
|
});
|
|
1536
1558
|
syncEye();
|
|
1537
|
-
head.append(title, eye);
|
|
1559
|
+
if (hasLegend) head.append(title, eye);
|
|
1560
|
+
else head.append(title);
|
|
1538
1561
|
el.append(head, body);
|
|
1539
1562
|
paint(body);
|
|
1540
1563
|
}
|
|
@@ -1635,7 +1658,7 @@ function renderVBar(el, opts) {
|
|
|
1635
1658
|
wrap.appendChild(track);
|
|
1636
1659
|
}
|
|
1637
1660
|
body.append(wrap, labelsRow(labelsUsed));
|
|
1638
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name
|
|
1661
|
+
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
|
|
1639
1662
|
});
|
|
1640
1663
|
attachChartInteraction(el, "vbar");
|
|
1641
1664
|
return el;
|
|
@@ -1730,8 +1753,10 @@ function renderDonut(el, opts) {
|
|
|
1730
1753
|
"stroke-width": "14"
|
|
1731
1754
|
}));
|
|
1732
1755
|
let offset = 0;
|
|
1756
|
+
const gap = opts.segments.length > 1 ? 2.5 : 0;
|
|
1733
1757
|
opts.segments.forEach((seg, segIndex) => {
|
|
1734
|
-
const
|
|
1758
|
+
const arcLength = Math.max(0, seg.value / total * circumference);
|
|
1759
|
+
const dash = arcLength - Math.min(gap, arcLength * 0.1);
|
|
1735
1760
|
const arc = svgEl("circle", {
|
|
1736
1761
|
cx: "60",
|
|
1737
1762
|
cy: "60",
|
|
@@ -1745,7 +1770,7 @@ function renderDonut(el, opts) {
|
|
|
1745
1770
|
});
|
|
1746
1771
|
setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
|
|
1747
1772
|
svg.appendChild(arc);
|
|
1748
|
-
offset +=
|
|
1773
|
+
offset += arcLength;
|
|
1749
1774
|
});
|
|
1750
1775
|
const legend = document.createElement("div");
|
|
1751
1776
|
legend.className = "icen-chart-legend";
|
|
@@ -1780,8 +1805,9 @@ function renderLine(el, opts) {
|
|
|
1780
1805
|
const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
|
|
1781
1806
|
const defs = svgEl("defs", {});
|
|
1782
1807
|
for (let i = 0; i < 4; i++) {
|
|
1783
|
-
const y = pad + i * (height - pad * 2) / 3;
|
|
1808
|
+
const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
|
|
1784
1809
|
svg.appendChild(svgEl("line", {
|
|
1810
|
+
class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
|
|
1785
1811
|
x1: String(pad),
|
|
1786
1812
|
x2: String(width - pad),
|
|
1787
1813
|
y1: String(y),
|
|
@@ -1865,7 +1891,7 @@ function renderLine(el, opts) {
|
|
|
1865
1891
|
if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
|
|
1866
1892
|
wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
|
|
1867
1893
|
body.appendChild(wrap);
|
|
1868
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name
|
|
1894
|
+
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
|
|
1869
1895
|
});
|
|
1870
1896
|
if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
|
|
1871
1897
|
attachChartInteraction(el, "line");
|
|
@@ -1972,7 +1998,7 @@ function renderRadar(el, opts) {
|
|
|
1972
1998
|
setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
|
|
1973
1999
|
svg.appendChild(dot);
|
|
1974
2000
|
}
|
|
1975
|
-
legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 })
|
|
2001
|
+
legendItems.push({ key: `${si}:${s.name || t("charts.seriesName", { p0: si + 1 })}`, label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
|
|
1976
2002
|
});
|
|
1977
2003
|
wrap.appendChild(svg);
|
|
1978
2004
|
body.appendChild(wrap);
|
|
@@ -1994,6 +2020,11 @@ function niceCeil(v) {
|
|
|
1994
2020
|
else nice = 10;
|
|
1995
2021
|
return nice * base;
|
|
1996
2022
|
}
|
|
2023
|
+
function tickPrecision(min, max, steps) {
|
|
2024
|
+
const span = Math.abs(max - min);
|
|
2025
|
+
if (!Number.isFinite(span) || span <= 0) return 0;
|
|
2026
|
+
return Math.max(0, Math.ceil(-Math.log10(span / steps)));
|
|
2027
|
+
}
|
|
1997
2028
|
function isoDate(d) {
|
|
1998
2029
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
1999
2030
|
const day = String(d.getDate()).padStart(2, "0");
|
|
@@ -2089,7 +2120,8 @@ function renderSparkline(el, opts) {
|
|
|
2089
2120
|
const tone = toneVar(opts.tone);
|
|
2090
2121
|
const points = values.map((value, i) => ({
|
|
2091
2122
|
x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
|
|
2092
|
-
|
|
2123
|
+
/* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
|
|
2124
|
+
y: height - pad - Math.max(0, value) / max * (height - pad * 2),
|
|
2093
2125
|
value
|
|
2094
2126
|
}));
|
|
2095
2127
|
const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
|
|
@@ -2214,6 +2246,7 @@ function renderCalendar(el, opts) {
|
|
|
2214
2246
|
weekdayRow.appendChild(s);
|
|
2215
2247
|
});
|
|
2216
2248
|
const max = maxOf(entries.map((e) => e.value));
|
|
2249
|
+
entries.sort((a, b) => a.date.localeCompare(b.date));
|
|
2217
2250
|
const pad = padFirstWeek(grid, entries[0].date, weekStart);
|
|
2218
2251
|
let lastMonth = -1;
|
|
2219
2252
|
entries.forEach((entry, i) => {
|
|
@@ -2272,8 +2305,9 @@ function renderScatter(el, opts) {
|
|
|
2272
2305
|
const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
|
|
2273
2306
|
const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
|
|
2274
2307
|
for (let i = 0; i <= 3; i++) {
|
|
2275
|
-
const y = pad + i * (height - pad * 2) / 3;
|
|
2308
|
+
const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
|
|
2276
2309
|
svg.appendChild(svgEl("line", {
|
|
2310
|
+
class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
|
|
2277
2311
|
x1: String(pad),
|
|
2278
2312
|
x2: String(width - pad),
|
|
2279
2313
|
y1: String(y),
|
|
@@ -2289,12 +2323,13 @@ function renderScatter(el, opts) {
|
|
|
2289
2323
|
"font-size": "8",
|
|
2290
2324
|
fill: "var(--icen-token-text-faint)"
|
|
2291
2325
|
});
|
|
2292
|
-
txt.textContent = fmt(opts,
|
|
2326
|
+
txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
|
|
2293
2327
|
svg.appendChild(txt);
|
|
2294
2328
|
}
|
|
2295
2329
|
for (let i = 0; i <= 4; i++) {
|
|
2296
|
-
const x = pad + i * (width - pad * 2) / 4;
|
|
2330
|
+
const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
|
|
2297
2331
|
svg.appendChild(svgEl("line", {
|
|
2332
|
+
class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
|
|
2298
2333
|
x1: String(x),
|
|
2299
2334
|
x2: String(x),
|
|
2300
2335
|
y1: String(pad),
|
|
@@ -2311,7 +2346,7 @@ function renderScatter(el, opts) {
|
|
|
2311
2346
|
"font-size": "8",
|
|
2312
2347
|
fill: "var(--icen-token-text-faint)"
|
|
2313
2348
|
});
|
|
2314
|
-
txt.textContent = fmt(opts,
|
|
2349
|
+
txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
|
|
2315
2350
|
svg.appendChild(txt);
|
|
2316
2351
|
}
|
|
2317
2352
|
if (opts.yLabel) {
|
|
@@ -2548,6 +2583,14 @@ function normalizeChartSpec(raw) {
|
|
|
2548
2583
|
}
|
|
2549
2584
|
if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
|
|
2550
2585
|
if (typeof s.loading === "boolean") spec.loading = s.loading;
|
|
2586
|
+
if (s.a11y && typeof s.a11y === "object") {
|
|
2587
|
+
const a = s.a11y;
|
|
2588
|
+
const a11y = {};
|
|
2589
|
+
if (typeof a.summary === "boolean") a11y.summary = a.summary;
|
|
2590
|
+
if (typeof a.table === "boolean") a11y.table = a.table;
|
|
2591
|
+
if (typeof a.keyboard === "boolean") a11y.keyboard = a.keyboard;
|
|
2592
|
+
if (Object.keys(a11y).length > 0) spec.a11y = a11y;
|
|
2593
|
+
}
|
|
2551
2594
|
if (Array.isArray(s.marks)) {
|
|
2552
2595
|
const marks = [];
|
|
2553
2596
|
for (const raw2 of s.marks) {
|
|
@@ -2675,6 +2718,7 @@ function renderChartSkeleton(body) {
|
|
|
2675
2718
|
body.appendChild(box);
|
|
2676
2719
|
}
|
|
2677
2720
|
var CHART_MARK_ACCENT = "var(--icen-token-accent)";
|
|
2721
|
+
var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
|
|
2678
2722
|
function markToneVar(tone) {
|
|
2679
2723
|
switch (tone) {
|
|
2680
2724
|
case "success":
|
|
@@ -2810,7 +2854,7 @@ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
|
|
|
2810
2854
|
y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
|
|
2811
2855
|
"text-anchor": "middle",
|
|
2812
2856
|
"font-size": "8",
|
|
2813
|
-
fill:
|
|
2857
|
+
fill: CHART_MARK_ACCENT_TEXT
|
|
2814
2858
|
});
|
|
2815
2859
|
label.textContent = mark.text ?? mark.label;
|
|
2816
2860
|
g.appendChild(label);
|
|
@@ -2902,6 +2946,81 @@ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
|
|
|
2902
2946
|
function chartAriaLabel(title, typeName) {
|
|
2903
2947
|
return title ? `${typeName}\uFF1A${title}` : typeName;
|
|
2904
2948
|
}
|
|
2949
|
+
function summarizeChart(view, type, fmt2) {
|
|
2950
|
+
const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
2951
|
+
const parts = [];
|
|
2952
|
+
if (series.length > 1) parts.push(t("charts.a11y.seriesCount", { p0: series.length }));
|
|
2953
|
+
if (type === "scatter") {
|
|
2954
|
+
const pts = view.points ?? [];
|
|
2955
|
+
if (pts.length > 0) {
|
|
2956
|
+
const xs = pts.map((p) => p.x);
|
|
2957
|
+
const ys = pts.map((p) => p.y);
|
|
2958
|
+
parts.push(t("charts.a11y.scatterRange", { p0: fmt2(Math.min(...xs)), p1: fmt2(Math.max(...xs)), p2: fmt2(Math.min(...ys)), p3: fmt2(Math.max(...ys)) }));
|
|
2959
|
+
}
|
|
2960
|
+
return parts.join("\uFF1B");
|
|
2961
|
+
}
|
|
2962
|
+
const labels = view.labels ?? [];
|
|
2963
|
+
if (labels.length > 1) parts.push(t("charts.a11y.range", { p0: labels[0], p1: labels[labels.length - 1] }));
|
|
2964
|
+
let min = Infinity;
|
|
2965
|
+
let max = -Infinity;
|
|
2966
|
+
let minAt = "";
|
|
2967
|
+
let maxAt = "";
|
|
2968
|
+
for (const s of series) {
|
|
2969
|
+
s.values.forEach((v, i) => {
|
|
2970
|
+
if (v < min) {
|
|
2971
|
+
min = v;
|
|
2972
|
+
minAt = labels[i] ?? String(i + 1);
|
|
2973
|
+
}
|
|
2974
|
+
if (v > max) {
|
|
2975
|
+
max = v;
|
|
2976
|
+
maxAt = labels[i] ?? String(i + 1);
|
|
2977
|
+
}
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2980
|
+
if (Number.isFinite(min) && Number.isFinite(max)) {
|
|
2981
|
+
parts.push(t("charts.a11y.min", { p0: fmt2(min), p1: minAt }));
|
|
2982
|
+
parts.push(t("charts.a11y.max", { p0: fmt2(max), p1: maxAt }));
|
|
2983
|
+
}
|
|
2984
|
+
const first = series[0]?.values ?? [];
|
|
2985
|
+
if (first.length > 1) {
|
|
2986
|
+
const d = first[first.length - 1] - first[0];
|
|
2987
|
+
const key = Math.abs(d) < 1e-9 ? "charts.a11y.trendFlat" : d > 0 ? "charts.a11y.trendUp" : "charts.a11y.trendDown";
|
|
2988
|
+
parts.push(t("charts.a11y.trend", { p0: t(key) }));
|
|
2989
|
+
}
|
|
2990
|
+
return parts.join("\uFF1B");
|
|
2991
|
+
}
|
|
2992
|
+
function buildChartTable(view, spec, type, fmt2) {
|
|
2993
|
+
const table = document.createElement("table");
|
|
2994
|
+
table.className = "icen-chart-table";
|
|
2995
|
+
const caption = document.createElement("caption");
|
|
2996
|
+
caption.textContent = t("charts.a11y.tableCaption", { p0: spec.title ?? String(type) });
|
|
2997
|
+
table.appendChild(caption);
|
|
2998
|
+
const addRow = (target, cells, head) => {
|
|
2999
|
+
const tr = document.createElement("tr");
|
|
3000
|
+
for (const c of cells) {
|
|
3001
|
+
const cell = document.createElement(head ? "th" : "td");
|
|
3002
|
+
if (head) cell.scope = target.tagName === "THEAD" ? "col" : "row";
|
|
3003
|
+
cell.textContent = c;
|
|
3004
|
+
tr.appendChild(cell);
|
|
3005
|
+
}
|
|
3006
|
+
target.appendChild(tr);
|
|
3007
|
+
};
|
|
3008
|
+
const thead = table.createTHead();
|
|
3009
|
+
const tbody = table.createTBody();
|
|
3010
|
+
if (type === "scatter") {
|
|
3011
|
+
addRow(thead, ["x", "y"], true);
|
|
3012
|
+
for (const p of view.points ?? []) addRow(tbody, [fmt2(p.x), fmt2(p.y)], false);
|
|
3013
|
+
return table;
|
|
3014
|
+
}
|
|
3015
|
+
const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
3016
|
+
const labels = view.labels ?? [];
|
|
3017
|
+
addRow(thead, ["", ...series.map((s, i) => s.name || String(i + 1))], true);
|
|
3018
|
+
const n = Math.max(labels.length, ...series.map((s) => s.values.length));
|
|
3019
|
+
for (let i = 0; i < n; i++) {
|
|
3020
|
+
addRow(tbody, [labels[i] ?? String(i + 1), ...series.map((s) => fmt2(s.values[i] ?? 0))], false);
|
|
3021
|
+
}
|
|
3022
|
+
return table;
|
|
3023
|
+
}
|
|
2905
3024
|
function svgDimsOf(svg) {
|
|
2906
3025
|
const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
|
|
2907
3026
|
const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
|
|
@@ -3242,6 +3361,7 @@ function renderChart(el, raw) {
|
|
|
3242
3361
|
if (!isZoomableType(t2) || fullLength() < 2) return;
|
|
3243
3362
|
const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
|
|
3244
3363
|
if (!plot) return;
|
|
3364
|
+
plot.style.touchAction = current2.zoom === "x" ? "pan-y" : "none";
|
|
3245
3365
|
const on = (type, fn) => {
|
|
3246
3366
|
plot.addEventListener(type, fn);
|
|
3247
3367
|
};
|
|
@@ -3297,6 +3417,149 @@ function renderChart(el, raw) {
|
|
|
3297
3417
|
render();
|
|
3298
3418
|
});
|
|
3299
3419
|
};
|
|
3420
|
+
const KB_TYPES = /* @__PURE__ */ new Set(["line", "area", "vbar", "hbar", "scatter"]);
|
|
3421
|
+
const kbCursor = { si: 0, i: 0, active: false };
|
|
3422
|
+
let liveRegion = null;
|
|
3423
|
+
let a11ySeq = 0;
|
|
3424
|
+
const a11yOf = () => ({
|
|
3425
|
+
summary: current2.a11y?.summary !== false,
|
|
3426
|
+
table: current2.a11y?.table === true,
|
|
3427
|
+
keyboard: current2.a11y?.keyboard !== false
|
|
3428
|
+
});
|
|
3429
|
+
const seriesViewOf = (view) => view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
3430
|
+
const kbPointCount = (view) => typeOf() === "scatter" ? view.points?.length ?? 0 : Math.max(0, ...seriesViewOf(view).map((s) => s.values.length), view.labels?.length ?? 0);
|
|
3431
|
+
const kbCursorEl = () => {
|
|
3432
|
+
const t2 = typeOf();
|
|
3433
|
+
const view = viewOf();
|
|
3434
|
+
const series = seriesViewOf(view);
|
|
3435
|
+
const n = kbPointCount(view);
|
|
3436
|
+
if (n < 1) return null;
|
|
3437
|
+
const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
|
|
3438
|
+
const i = clampNum(kbCursor.i, 0, n - 1);
|
|
3439
|
+
if (t2 === "line" || t2 === "area") {
|
|
3440
|
+
const svg = root.querySelector(".icen-chart-line svg");
|
|
3441
|
+
if (!svg) return null;
|
|
3442
|
+
const dots = svg.querySelectorAll("circle");
|
|
3443
|
+
let base = 0;
|
|
3444
|
+
for (let k = 0; k < si; k++) base += Math.min(series[k].values.length, n);
|
|
3445
|
+
return dots.item(base + i) ?? null;
|
|
3446
|
+
}
|
|
3447
|
+
if (t2 === "scatter") return root.querySelector(".icen-chart-scatter svg")?.querySelectorAll("circle").item(i) ?? null;
|
|
3448
|
+
if (t2 === "vbar") return root.querySelectorAll(".icen-chart-vbar-bar").item(series.length > 1 ? i * series.length + si : i) ?? null;
|
|
3449
|
+
if (t2 === "hbar") return root.querySelectorAll(".icen-chart-hbar-bar").item(i) ?? null;
|
|
3450
|
+
return null;
|
|
3451
|
+
};
|
|
3452
|
+
const announceKb = (text) => {
|
|
3453
|
+
if (!liveRegion || !liveRegion.isConnected) {
|
|
3454
|
+
liveRegion = document.createElement("div");
|
|
3455
|
+
liveRegion.className = "icen-chart-live";
|
|
3456
|
+
liveRegion.setAttribute("aria-live", "polite");
|
|
3457
|
+
root.appendChild(liveRegion);
|
|
3458
|
+
}
|
|
3459
|
+
liveRegion.textContent = "";
|
|
3460
|
+
liveRegion.textContent = text;
|
|
3461
|
+
};
|
|
3462
|
+
const applyKbCursor = () => {
|
|
3463
|
+
for (const el2 of root.querySelectorAll(".icen-chart-kb-focus")) el2.classList.remove("icen-chart-kb-focus");
|
|
3464
|
+
if (!kbCursor.active) return;
|
|
3465
|
+
kbCursorEl()?.classList.add("icen-chart-kb-focus");
|
|
3466
|
+
};
|
|
3467
|
+
const announceCursor = () => {
|
|
3468
|
+
const view = viewOf();
|
|
3469
|
+
const series = seriesViewOf(view);
|
|
3470
|
+
const n = kbPointCount(view);
|
|
3471
|
+
if (n < 1) return;
|
|
3472
|
+
const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
|
|
3473
|
+
const i = clampNum(kbCursor.i, 0, Math.max(0, n - 1));
|
|
3474
|
+
const fmt2 = chartFormatValue(current2.format);
|
|
3475
|
+
if (typeOf() === "scatter") {
|
|
3476
|
+
const p = view.points?.[i];
|
|
3477
|
+
if (!p) return;
|
|
3478
|
+
announceKb(t("charts.a11y.point", { p0: `x ${fmt2(p.x)}`, p1: `y ${fmt2(p.y)}`, p2: i + 1, p3: n }));
|
|
3479
|
+
return;
|
|
3480
|
+
}
|
|
3481
|
+
const label = view.labels?.[i] ?? String(i + 1);
|
|
3482
|
+
const value = series[si]?.values[i] ?? 0;
|
|
3483
|
+
if (series.length > 1) announceKb(t("charts.a11y.pointSeries", { p0: series[si].name || String(si + 1), p1: label, p2: fmt2(value), p3: i + 1, p4: n }));
|
|
3484
|
+
else announceKb(t("charts.a11y.point", { p0: label, p1: fmt2(value), p2: i + 1, p3: n }));
|
|
3485
|
+
};
|
|
3486
|
+
const onKbKeydown = (e) => {
|
|
3487
|
+
const conf = a11yOf();
|
|
3488
|
+
if (!conf.keyboard || !KB_TYPES.has(typeOf())) return;
|
|
3489
|
+
const g = root.querySelector("[data-icen-chart-kb]");
|
|
3490
|
+
if (!g || e.target !== g) return;
|
|
3491
|
+
if (e.key === "Escape") {
|
|
3492
|
+
if (zoomWindow) {
|
|
3493
|
+
zoomWindow = null;
|
|
3494
|
+
kbCursor.active = false;
|
|
3495
|
+
render();
|
|
3496
|
+
}
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
const view = viewOf();
|
|
3500
|
+
const series = seriesViewOf(view);
|
|
3501
|
+
const n = kbPointCount(view);
|
|
3502
|
+
if (n < 1) return;
|
|
3503
|
+
const siMax = Math.max(0, series.length - 1);
|
|
3504
|
+
let moved = true;
|
|
3505
|
+
switch (e.key) {
|
|
3506
|
+
case "ArrowRight":
|
|
3507
|
+
kbCursor.i = clampNum(kbCursor.i + 1, 0, n - 1);
|
|
3508
|
+
break;
|
|
3509
|
+
case "ArrowLeft":
|
|
3510
|
+
kbCursor.i = clampNum(kbCursor.i - 1, 0, n - 1);
|
|
3511
|
+
break;
|
|
3512
|
+
case "ArrowDown":
|
|
3513
|
+
kbCursor.si = clampNum(kbCursor.si + 1, 0, siMax);
|
|
3514
|
+
break;
|
|
3515
|
+
case "ArrowUp":
|
|
3516
|
+
kbCursor.si = clampNum(kbCursor.si - 1, 0, siMax);
|
|
3517
|
+
break;
|
|
3518
|
+
case "Home":
|
|
3519
|
+
kbCursor.i = 0;
|
|
3520
|
+
break;
|
|
3521
|
+
case "End":
|
|
3522
|
+
kbCursor.i = n - 1;
|
|
3523
|
+
break;
|
|
3524
|
+
default:
|
|
3525
|
+
moved = false;
|
|
3526
|
+
}
|
|
3527
|
+
if (!moved) return;
|
|
3528
|
+
e.preventDefault();
|
|
3529
|
+
kbCursor.active = true;
|
|
3530
|
+
applyKbCursor();
|
|
3531
|
+
announceCursor();
|
|
3532
|
+
};
|
|
3533
|
+
root.addEventListener("keydown", onKbKeydown);
|
|
3534
|
+
const applyChartA11yPlus = (view, spec, type, formatValue) => {
|
|
3535
|
+
const conf = a11yOf();
|
|
3536
|
+
const graphic = root.querySelector('[role="img"]');
|
|
3537
|
+
if (!graphic) return;
|
|
3538
|
+
const body = root.querySelector(".icen-chart-body") ?? graphic.parentElement ?? root;
|
|
3539
|
+
const summaryParts = [];
|
|
3540
|
+
if (conf.summary) summaryParts.push(summarizeChart(view, type, formatValue));
|
|
3541
|
+
if (conf.keyboard && KB_TYPES.has(type)) summaryParts.push(t("charts.a11y.keyboardHint"));
|
|
3542
|
+
const summaryText = summaryParts.filter(Boolean).join("\uFF1B");
|
|
3543
|
+
if (summaryText) {
|
|
3544
|
+
const p = document.createElement("p");
|
|
3545
|
+
p.className = "icen-chart-summary";
|
|
3546
|
+
p.id = `icen-chart-a11y-${++a11ySeq}`;
|
|
3547
|
+
p.textContent = summaryText;
|
|
3548
|
+
body.appendChild(p);
|
|
3549
|
+
graphic.setAttribute("aria-describedby", p.id);
|
|
3550
|
+
} else {
|
|
3551
|
+
graphic.removeAttribute("aria-describedby");
|
|
3552
|
+
}
|
|
3553
|
+
if (conf.keyboard && KB_TYPES.has(type)) {
|
|
3554
|
+
graphic.setAttribute("tabindex", "0");
|
|
3555
|
+
graphic.setAttribute("data-icen-chart-kb", "");
|
|
3556
|
+
} else {
|
|
3557
|
+
graphic.removeAttribute("tabindex");
|
|
3558
|
+
graphic.removeAttribute("data-icen-chart-kb");
|
|
3559
|
+
}
|
|
3560
|
+
if (conf.table) body.appendChild(buildChartTable(view, spec, type, formatValue));
|
|
3561
|
+
applyKbCursor();
|
|
3562
|
+
};
|
|
3300
3563
|
const render = () => {
|
|
3301
3564
|
if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
|
|
3302
3565
|
const spec = current2;
|
|
@@ -3368,9 +3631,16 @@ function renderChart(el, raw) {
|
|
|
3368
3631
|
const graphic = root.querySelector('[role="img"]');
|
|
3369
3632
|
if (graphic && !graphic.getAttribute("aria-label")) {
|
|
3370
3633
|
graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
|
|
3634
|
+
} else if (!graphic) {
|
|
3635
|
+
const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
|
|
3636
|
+
if (dom) {
|
|
3637
|
+
dom.setAttribute("role", "img");
|
|
3638
|
+
dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
|
|
3639
|
+
}
|
|
3371
3640
|
}
|
|
3372
3641
|
}
|
|
3373
3642
|
if (loading) return;
|
|
3643
|
+
applyChartA11yPlus(view, spec, type, formatValue);
|
|
3374
3644
|
paintChartMarks(root, view, spec, formatValue, warnedMarks);
|
|
3375
3645
|
bindZoomGesture();
|
|
3376
3646
|
};
|
|
@@ -3452,6 +3722,7 @@ function renderChart(el, raw) {
|
|
|
3452
3722
|
releaseFluidWidth(root);
|
|
3453
3723
|
hiddenLegendKeys.delete(root);
|
|
3454
3724
|
zoomDragCleanup?.();
|
|
3725
|
+
root.removeEventListener("keydown", onKbKeydown);
|
|
3455
3726
|
root.textContent = "";
|
|
3456
3727
|
root.classList.remove("is-loading");
|
|
3457
3728
|
unbindEvents();
|
|
@@ -3605,8 +3876,12 @@ function buildApproval() {
|
|
|
3605
3876
|
}
|
|
3606
3877
|
function applyTint(item, model) {
|
|
3607
3878
|
const tint = getAiKind(model.kind).tint;
|
|
3608
|
-
if (tint)
|
|
3609
|
-
|
|
3879
|
+
if (tint) {
|
|
3880
|
+
const slot = tint === "muted" ? "text-muted" : tint;
|
|
3881
|
+
item.style.setProperty("--ai-item-tint", `var(--icen-token-${slot})`);
|
|
3882
|
+
} else {
|
|
3883
|
+
item.style.removeProperty("--ai-item-tint");
|
|
3884
|
+
}
|
|
3610
3885
|
}
|
|
3611
3886
|
function applyKindVisual(parts, model) {
|
|
3612
3887
|
const kind = getAiKind(model.kind);
|