@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
package/dist/vue.mjs
CHANGED
|
@@ -168,6 +168,7 @@ var ICEN_LOCALE_ZH_CN = {
|
|
|
168
168
|
"aiChat.roleTool": "\u5DE5",
|
|
169
169
|
"aiChat.roleUser": "\u6211",
|
|
170
170
|
"aiChat.thinking": "\u601D\u8003 {p0}",
|
|
171
|
+
"aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
|
|
171
172
|
/* ── aiComposer ── */
|
|
172
173
|
"aiComposer.attachAgent": "\u4EE3\u7406",
|
|
173
174
|
"aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
|
|
@@ -350,6 +351,19 @@ var ICEN_LOCALE_ZH_CN = {
|
|
|
350
351
|
"charts.noData": "\u6682\u65E0\u6570\u636E",
|
|
351
352
|
"charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
|
|
352
353
|
"charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
|
|
354
|
+
"charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
|
|
355
|
+
"charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
|
|
356
|
+
"charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
|
|
357
|
+
"charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
|
|
358
|
+
"charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
|
|
359
|
+
"charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
|
|
360
|
+
"charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
|
|
361
|
+
"charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
|
|
362
|
+
"charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
|
|
363
|
+
"charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
|
|
364
|
+
"charts.a11y.trendDown": "\u4E0B\u964D",
|
|
365
|
+
"charts.a11y.trendFlat": "\u6301\u5E73",
|
|
366
|
+
"charts.a11y.trendUp": "\u4E0A\u5347",
|
|
353
367
|
"charts.type.area": "\u9762\u79EF\u56FE",
|
|
354
368
|
"charts.type.donut": "\u73AF\u5F62\u56FE",
|
|
355
369
|
"charts.type.gauge": "\u4EEA\u8868\u76D8",
|
|
@@ -1215,7 +1229,8 @@ function withChrome(el, opts, hasLegend, paint, state, extras) {
|
|
|
1215
1229
|
emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
|
|
1216
1230
|
});
|
|
1217
1231
|
syncEye();
|
|
1218
|
-
head.append(title, eye);
|
|
1232
|
+
if (hasLegend) head.append(title, eye);
|
|
1233
|
+
else head.append(title);
|
|
1219
1234
|
el.append(head, body);
|
|
1220
1235
|
paint(body);
|
|
1221
1236
|
}
|
|
@@ -1316,7 +1331,7 @@ function renderVBar(el, opts) {
|
|
|
1316
1331
|
wrap.appendChild(track);
|
|
1317
1332
|
}
|
|
1318
1333
|
body.append(wrap, labelsRow(labelsUsed));
|
|
1319
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name
|
|
1334
|
+
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));
|
|
1320
1335
|
});
|
|
1321
1336
|
attachChartInteraction(el, "vbar");
|
|
1322
1337
|
return el;
|
|
@@ -1411,8 +1426,10 @@ function renderDonut(el, opts) {
|
|
|
1411
1426
|
"stroke-width": "14"
|
|
1412
1427
|
}));
|
|
1413
1428
|
let offset = 0;
|
|
1429
|
+
const gap = opts.segments.length > 1 ? 2.5 : 0;
|
|
1414
1430
|
opts.segments.forEach((seg, segIndex) => {
|
|
1415
|
-
const
|
|
1431
|
+
const arcLength = Math.max(0, seg.value / total * circumference);
|
|
1432
|
+
const dash = arcLength - Math.min(gap, arcLength * 0.1);
|
|
1416
1433
|
const arc = svgEl("circle", {
|
|
1417
1434
|
cx: "60",
|
|
1418
1435
|
cy: "60",
|
|
@@ -1426,7 +1443,7 @@ function renderDonut(el, opts) {
|
|
|
1426
1443
|
});
|
|
1427
1444
|
setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
|
|
1428
1445
|
svg.appendChild(arc);
|
|
1429
|
-
offset +=
|
|
1446
|
+
offset += arcLength;
|
|
1430
1447
|
});
|
|
1431
1448
|
const legend = document.createElement("div");
|
|
1432
1449
|
legend.className = "icen-chart-legend";
|
|
@@ -1461,8 +1478,9 @@ function renderLine(el, opts) {
|
|
|
1461
1478
|
const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
|
|
1462
1479
|
const defs = svgEl("defs", {});
|
|
1463
1480
|
for (let i = 0; i < 4; i++) {
|
|
1464
|
-
const y = pad + i * (height - pad * 2) / 3;
|
|
1481
|
+
const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
|
|
1465
1482
|
svg.appendChild(svgEl("line", {
|
|
1483
|
+
class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
|
|
1466
1484
|
x1: String(pad),
|
|
1467
1485
|
x2: String(width - pad),
|
|
1468
1486
|
y1: String(y),
|
|
@@ -1546,7 +1564,7 @@ function renderLine(el, opts) {
|
|
|
1546
1564
|
if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
|
|
1547
1565
|
wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
|
|
1548
1566
|
body.appendChild(wrap);
|
|
1549
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name
|
|
1567
|
+
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));
|
|
1550
1568
|
});
|
|
1551
1569
|
if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
|
|
1552
1570
|
attachChartInteraction(el, "line");
|
|
@@ -1653,7 +1671,7 @@ function renderRadar(el, opts) {
|
|
|
1653
1671
|
setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
|
|
1654
1672
|
svg.appendChild(dot);
|
|
1655
1673
|
}
|
|
1656
|
-
legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 })
|
|
1674
|
+
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 });
|
|
1657
1675
|
});
|
|
1658
1676
|
wrap.appendChild(svg);
|
|
1659
1677
|
body.appendChild(wrap);
|
|
@@ -1675,6 +1693,11 @@ function niceCeil(v) {
|
|
|
1675
1693
|
else nice = 10;
|
|
1676
1694
|
return nice * base;
|
|
1677
1695
|
}
|
|
1696
|
+
function tickPrecision(min, max, steps) {
|
|
1697
|
+
const span = Math.abs(max - min);
|
|
1698
|
+
if (!Number.isFinite(span) || span <= 0) return 0;
|
|
1699
|
+
return Math.max(0, Math.ceil(-Math.log10(span / steps)));
|
|
1700
|
+
}
|
|
1678
1701
|
function isoDate(d) {
|
|
1679
1702
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
1680
1703
|
const day = String(d.getDate()).padStart(2, "0");
|
|
@@ -1770,7 +1793,8 @@ function renderSparkline(el, opts) {
|
|
|
1770
1793
|
const tone = toneVar(opts.tone);
|
|
1771
1794
|
const points = values.map((value, i) => ({
|
|
1772
1795
|
x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
|
|
1773
|
-
|
|
1796
|
+
/* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
|
|
1797
|
+
y: height - pad - Math.max(0, value) / max * (height - pad * 2),
|
|
1774
1798
|
value
|
|
1775
1799
|
}));
|
|
1776
1800
|
const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
|
|
@@ -1895,6 +1919,7 @@ function renderCalendar(el, opts) {
|
|
|
1895
1919
|
weekdayRow.appendChild(s);
|
|
1896
1920
|
});
|
|
1897
1921
|
const max = maxOf(entries.map((e) => e.value));
|
|
1922
|
+
entries.sort((a, b) => a.date.localeCompare(b.date));
|
|
1898
1923
|
const pad = padFirstWeek(grid, entries[0].date, weekStart);
|
|
1899
1924
|
let lastMonth = -1;
|
|
1900
1925
|
entries.forEach((entry, i) => {
|
|
@@ -1953,8 +1978,9 @@ function renderScatter(el, opts) {
|
|
|
1953
1978
|
const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
|
|
1954
1979
|
const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
|
|
1955
1980
|
for (let i = 0; i <= 3; i++) {
|
|
1956
|
-
const y = pad + i * (height - pad * 2) / 3;
|
|
1981
|
+
const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
|
|
1957
1982
|
svg.appendChild(svgEl("line", {
|
|
1983
|
+
class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
|
|
1958
1984
|
x1: String(pad),
|
|
1959
1985
|
x2: String(width - pad),
|
|
1960
1986
|
y1: String(y),
|
|
@@ -1970,12 +1996,13 @@ function renderScatter(el, opts) {
|
|
|
1970
1996
|
"font-size": "8",
|
|
1971
1997
|
fill: "var(--icen-token-text-faint)"
|
|
1972
1998
|
});
|
|
1973
|
-
txt.textContent = fmt(opts,
|
|
1999
|
+
txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
|
|
1974
2000
|
svg.appendChild(txt);
|
|
1975
2001
|
}
|
|
1976
2002
|
for (let i = 0; i <= 4; i++) {
|
|
1977
|
-
const x = pad + i * (width - pad * 2) / 4;
|
|
2003
|
+
const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
|
|
1978
2004
|
svg.appendChild(svgEl("line", {
|
|
2005
|
+
class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
|
|
1979
2006
|
x1: String(x),
|
|
1980
2007
|
x2: String(x),
|
|
1981
2008
|
y1: String(pad),
|
|
@@ -1992,7 +2019,7 @@ function renderScatter(el, opts) {
|
|
|
1992
2019
|
"font-size": "8",
|
|
1993
2020
|
fill: "var(--icen-token-text-faint)"
|
|
1994
2021
|
});
|
|
1995
|
-
txt.textContent = fmt(opts,
|
|
2022
|
+
txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
|
|
1996
2023
|
svg.appendChild(txt);
|
|
1997
2024
|
}
|
|
1998
2025
|
if (opts.yLabel) {
|
|
@@ -2229,6 +2256,14 @@ function normalizeChartSpec(raw) {
|
|
|
2229
2256
|
}
|
|
2230
2257
|
if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
|
|
2231
2258
|
if (typeof s.loading === "boolean") spec.loading = s.loading;
|
|
2259
|
+
if (s.a11y && typeof s.a11y === "object") {
|
|
2260
|
+
const a = s.a11y;
|
|
2261
|
+
const a11y = {};
|
|
2262
|
+
if (typeof a.summary === "boolean") a11y.summary = a.summary;
|
|
2263
|
+
if (typeof a.table === "boolean") a11y.table = a.table;
|
|
2264
|
+
if (typeof a.keyboard === "boolean") a11y.keyboard = a.keyboard;
|
|
2265
|
+
if (Object.keys(a11y).length > 0) spec.a11y = a11y;
|
|
2266
|
+
}
|
|
2232
2267
|
if (Array.isArray(s.marks)) {
|
|
2233
2268
|
const marks = [];
|
|
2234
2269
|
for (const raw2 of s.marks) {
|
|
@@ -2356,6 +2391,7 @@ function renderChartSkeleton(body) {
|
|
|
2356
2391
|
body.appendChild(box);
|
|
2357
2392
|
}
|
|
2358
2393
|
var CHART_MARK_ACCENT = "var(--icen-token-accent)";
|
|
2394
|
+
var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
|
|
2359
2395
|
function markToneVar(tone) {
|
|
2360
2396
|
switch (tone) {
|
|
2361
2397
|
case "success":
|
|
@@ -2491,7 +2527,7 @@ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
|
|
|
2491
2527
|
y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
|
|
2492
2528
|
"text-anchor": "middle",
|
|
2493
2529
|
"font-size": "8",
|
|
2494
|
-
fill:
|
|
2530
|
+
fill: CHART_MARK_ACCENT_TEXT
|
|
2495
2531
|
});
|
|
2496
2532
|
label.textContent = mark.text ?? mark.label;
|
|
2497
2533
|
g.appendChild(label);
|
|
@@ -2583,6 +2619,81 @@ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
|
|
|
2583
2619
|
function chartAriaLabel(title, typeName) {
|
|
2584
2620
|
return title ? `${typeName}\uFF1A${title}` : typeName;
|
|
2585
2621
|
}
|
|
2622
|
+
function summarizeChart(view, type, fmt2) {
|
|
2623
|
+
const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
2624
|
+
const parts = [];
|
|
2625
|
+
if (series.length > 1) parts.push(t("charts.a11y.seriesCount", { p0: series.length }));
|
|
2626
|
+
if (type === "scatter") {
|
|
2627
|
+
const pts = view.points ?? [];
|
|
2628
|
+
if (pts.length > 0) {
|
|
2629
|
+
const xs = pts.map((p) => p.x);
|
|
2630
|
+
const ys = pts.map((p) => p.y);
|
|
2631
|
+
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)) }));
|
|
2632
|
+
}
|
|
2633
|
+
return parts.join("\uFF1B");
|
|
2634
|
+
}
|
|
2635
|
+
const labels = view.labels ?? [];
|
|
2636
|
+
if (labels.length > 1) parts.push(t("charts.a11y.range", { p0: labels[0], p1: labels[labels.length - 1] }));
|
|
2637
|
+
let min = Infinity;
|
|
2638
|
+
let max = -Infinity;
|
|
2639
|
+
let minAt = "";
|
|
2640
|
+
let maxAt = "";
|
|
2641
|
+
for (const s of series) {
|
|
2642
|
+
s.values.forEach((v, i) => {
|
|
2643
|
+
if (v < min) {
|
|
2644
|
+
min = v;
|
|
2645
|
+
minAt = labels[i] ?? String(i + 1);
|
|
2646
|
+
}
|
|
2647
|
+
if (v > max) {
|
|
2648
|
+
max = v;
|
|
2649
|
+
maxAt = labels[i] ?? String(i + 1);
|
|
2650
|
+
}
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
if (Number.isFinite(min) && Number.isFinite(max)) {
|
|
2654
|
+
parts.push(t("charts.a11y.min", { p0: fmt2(min), p1: minAt }));
|
|
2655
|
+
parts.push(t("charts.a11y.max", { p0: fmt2(max), p1: maxAt }));
|
|
2656
|
+
}
|
|
2657
|
+
const first = series[0]?.values ?? [];
|
|
2658
|
+
if (first.length > 1) {
|
|
2659
|
+
const d = first[first.length - 1] - first[0];
|
|
2660
|
+
const key = Math.abs(d) < 1e-9 ? "charts.a11y.trendFlat" : d > 0 ? "charts.a11y.trendUp" : "charts.a11y.trendDown";
|
|
2661
|
+
parts.push(t("charts.a11y.trend", { p0: t(key) }));
|
|
2662
|
+
}
|
|
2663
|
+
return parts.join("\uFF1B");
|
|
2664
|
+
}
|
|
2665
|
+
function buildChartTable(view, spec, type, fmt2) {
|
|
2666
|
+
const table = document.createElement("table");
|
|
2667
|
+
table.className = "icen-chart-table";
|
|
2668
|
+
const caption = document.createElement("caption");
|
|
2669
|
+
caption.textContent = t("charts.a11y.tableCaption", { p0: spec.title ?? String(type) });
|
|
2670
|
+
table.appendChild(caption);
|
|
2671
|
+
const addRow = (target, cells, head) => {
|
|
2672
|
+
const tr = document.createElement("tr");
|
|
2673
|
+
for (const c of cells) {
|
|
2674
|
+
const cell = document.createElement(head ? "th" : "td");
|
|
2675
|
+
if (head) cell.scope = target.tagName === "THEAD" ? "col" : "row";
|
|
2676
|
+
cell.textContent = c;
|
|
2677
|
+
tr.appendChild(cell);
|
|
2678
|
+
}
|
|
2679
|
+
target.appendChild(tr);
|
|
2680
|
+
};
|
|
2681
|
+
const thead = table.createTHead();
|
|
2682
|
+
const tbody = table.createTBody();
|
|
2683
|
+
if (type === "scatter") {
|
|
2684
|
+
addRow(thead, ["x", "y"], true);
|
|
2685
|
+
for (const p of view.points ?? []) addRow(tbody, [fmt2(p.x), fmt2(p.y)], false);
|
|
2686
|
+
return table;
|
|
2687
|
+
}
|
|
2688
|
+
const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
2689
|
+
const labels = view.labels ?? [];
|
|
2690
|
+
addRow(thead, ["", ...series.map((s, i) => s.name || String(i + 1))], true);
|
|
2691
|
+
const n = Math.max(labels.length, ...series.map((s) => s.values.length));
|
|
2692
|
+
for (let i = 0; i < n; i++) {
|
|
2693
|
+
addRow(tbody, [labels[i] ?? String(i + 1), ...series.map((s) => fmt2(s.values[i] ?? 0))], false);
|
|
2694
|
+
}
|
|
2695
|
+
return table;
|
|
2696
|
+
}
|
|
2586
2697
|
function svgDimsOf(svg) {
|
|
2587
2698
|
const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
|
|
2588
2699
|
const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
|
|
@@ -2923,6 +3034,7 @@ function renderChart(el, raw) {
|
|
|
2923
3034
|
if (!isZoomableType(t2) || fullLength() < 2) return;
|
|
2924
3035
|
const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
|
|
2925
3036
|
if (!plot) return;
|
|
3037
|
+
plot.style.touchAction = current2.zoom === "x" ? "pan-y" : "none";
|
|
2926
3038
|
const on = (type, fn) => {
|
|
2927
3039
|
plot.addEventListener(type, fn);
|
|
2928
3040
|
};
|
|
@@ -2978,6 +3090,149 @@ function renderChart(el, raw) {
|
|
|
2978
3090
|
render();
|
|
2979
3091
|
});
|
|
2980
3092
|
};
|
|
3093
|
+
const KB_TYPES = /* @__PURE__ */ new Set(["line", "area", "vbar", "hbar", "scatter"]);
|
|
3094
|
+
const kbCursor = { si: 0, i: 0, active: false };
|
|
3095
|
+
let liveRegion = null;
|
|
3096
|
+
let a11ySeq = 0;
|
|
3097
|
+
const a11yOf = () => ({
|
|
3098
|
+
summary: current2.a11y?.summary !== false,
|
|
3099
|
+
table: current2.a11y?.table === true,
|
|
3100
|
+
keyboard: current2.a11y?.keyboard !== false
|
|
3101
|
+
});
|
|
3102
|
+
const seriesViewOf = (view) => view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
3103
|
+
const kbPointCount = (view) => typeOf() === "scatter" ? view.points?.length ?? 0 : Math.max(0, ...seriesViewOf(view).map((s) => s.values.length), view.labels?.length ?? 0);
|
|
3104
|
+
const kbCursorEl = () => {
|
|
3105
|
+
const t2 = typeOf();
|
|
3106
|
+
const view = viewOf();
|
|
3107
|
+
const series = seriesViewOf(view);
|
|
3108
|
+
const n = kbPointCount(view);
|
|
3109
|
+
if (n < 1) return null;
|
|
3110
|
+
const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
|
|
3111
|
+
const i = clampNum(kbCursor.i, 0, n - 1);
|
|
3112
|
+
if (t2 === "line" || t2 === "area") {
|
|
3113
|
+
const svg = root.querySelector(".icen-chart-line svg");
|
|
3114
|
+
if (!svg) return null;
|
|
3115
|
+
const dots = svg.querySelectorAll("circle");
|
|
3116
|
+
let base = 0;
|
|
3117
|
+
for (let k = 0; k < si; k++) base += Math.min(series[k].values.length, n);
|
|
3118
|
+
return dots.item(base + i) ?? null;
|
|
3119
|
+
}
|
|
3120
|
+
if (t2 === "scatter") return root.querySelector(".icen-chart-scatter svg")?.querySelectorAll("circle").item(i) ?? null;
|
|
3121
|
+
if (t2 === "vbar") return root.querySelectorAll(".icen-chart-vbar-bar").item(series.length > 1 ? i * series.length + si : i) ?? null;
|
|
3122
|
+
if (t2 === "hbar") return root.querySelectorAll(".icen-chart-hbar-bar").item(i) ?? null;
|
|
3123
|
+
return null;
|
|
3124
|
+
};
|
|
3125
|
+
const announceKb = (text) => {
|
|
3126
|
+
if (!liveRegion || !liveRegion.isConnected) {
|
|
3127
|
+
liveRegion = document.createElement("div");
|
|
3128
|
+
liveRegion.className = "icen-chart-live";
|
|
3129
|
+
liveRegion.setAttribute("aria-live", "polite");
|
|
3130
|
+
root.appendChild(liveRegion);
|
|
3131
|
+
}
|
|
3132
|
+
liveRegion.textContent = "";
|
|
3133
|
+
liveRegion.textContent = text;
|
|
3134
|
+
};
|
|
3135
|
+
const applyKbCursor = () => {
|
|
3136
|
+
for (const el2 of root.querySelectorAll(".icen-chart-kb-focus")) el2.classList.remove("icen-chart-kb-focus");
|
|
3137
|
+
if (!kbCursor.active) return;
|
|
3138
|
+
kbCursorEl()?.classList.add("icen-chart-kb-focus");
|
|
3139
|
+
};
|
|
3140
|
+
const announceCursor = () => {
|
|
3141
|
+
const view = viewOf();
|
|
3142
|
+
const series = seriesViewOf(view);
|
|
3143
|
+
const n = kbPointCount(view);
|
|
3144
|
+
if (n < 1) return;
|
|
3145
|
+
const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
|
|
3146
|
+
const i = clampNum(kbCursor.i, 0, Math.max(0, n - 1));
|
|
3147
|
+
const fmt2 = chartFormatValue(current2.format);
|
|
3148
|
+
if (typeOf() === "scatter") {
|
|
3149
|
+
const p = view.points?.[i];
|
|
3150
|
+
if (!p) return;
|
|
3151
|
+
announceKb(t("charts.a11y.point", { p0: `x ${fmt2(p.x)}`, p1: `y ${fmt2(p.y)}`, p2: i + 1, p3: n }));
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3154
|
+
const label = view.labels?.[i] ?? String(i + 1);
|
|
3155
|
+
const value = series[si]?.values[i] ?? 0;
|
|
3156
|
+
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 }));
|
|
3157
|
+
else announceKb(t("charts.a11y.point", { p0: label, p1: fmt2(value), p2: i + 1, p3: n }));
|
|
3158
|
+
};
|
|
3159
|
+
const onKbKeydown = (e) => {
|
|
3160
|
+
const conf = a11yOf();
|
|
3161
|
+
if (!conf.keyboard || !KB_TYPES.has(typeOf())) return;
|
|
3162
|
+
const g = root.querySelector("[data-icen-chart-kb]");
|
|
3163
|
+
if (!g || e.target !== g) return;
|
|
3164
|
+
if (e.key === "Escape") {
|
|
3165
|
+
if (zoomWindow) {
|
|
3166
|
+
zoomWindow = null;
|
|
3167
|
+
kbCursor.active = false;
|
|
3168
|
+
render();
|
|
3169
|
+
}
|
|
3170
|
+
return;
|
|
3171
|
+
}
|
|
3172
|
+
const view = viewOf();
|
|
3173
|
+
const series = seriesViewOf(view);
|
|
3174
|
+
const n = kbPointCount(view);
|
|
3175
|
+
if (n < 1) return;
|
|
3176
|
+
const siMax = Math.max(0, series.length - 1);
|
|
3177
|
+
let moved = true;
|
|
3178
|
+
switch (e.key) {
|
|
3179
|
+
case "ArrowRight":
|
|
3180
|
+
kbCursor.i = clampNum(kbCursor.i + 1, 0, n - 1);
|
|
3181
|
+
break;
|
|
3182
|
+
case "ArrowLeft":
|
|
3183
|
+
kbCursor.i = clampNum(kbCursor.i - 1, 0, n - 1);
|
|
3184
|
+
break;
|
|
3185
|
+
case "ArrowDown":
|
|
3186
|
+
kbCursor.si = clampNum(kbCursor.si + 1, 0, siMax);
|
|
3187
|
+
break;
|
|
3188
|
+
case "ArrowUp":
|
|
3189
|
+
kbCursor.si = clampNum(kbCursor.si - 1, 0, siMax);
|
|
3190
|
+
break;
|
|
3191
|
+
case "Home":
|
|
3192
|
+
kbCursor.i = 0;
|
|
3193
|
+
break;
|
|
3194
|
+
case "End":
|
|
3195
|
+
kbCursor.i = n - 1;
|
|
3196
|
+
break;
|
|
3197
|
+
default:
|
|
3198
|
+
moved = false;
|
|
3199
|
+
}
|
|
3200
|
+
if (!moved) return;
|
|
3201
|
+
e.preventDefault();
|
|
3202
|
+
kbCursor.active = true;
|
|
3203
|
+
applyKbCursor();
|
|
3204
|
+
announceCursor();
|
|
3205
|
+
};
|
|
3206
|
+
root.addEventListener("keydown", onKbKeydown);
|
|
3207
|
+
const applyChartA11yPlus = (view, spec, type, formatValue) => {
|
|
3208
|
+
const conf = a11yOf();
|
|
3209
|
+
const graphic = root.querySelector('[role="img"]');
|
|
3210
|
+
if (!graphic) return;
|
|
3211
|
+
const body = root.querySelector(".icen-chart-body") ?? graphic.parentElement ?? root;
|
|
3212
|
+
const summaryParts = [];
|
|
3213
|
+
if (conf.summary) summaryParts.push(summarizeChart(view, type, formatValue));
|
|
3214
|
+
if (conf.keyboard && KB_TYPES.has(type)) summaryParts.push(t("charts.a11y.keyboardHint"));
|
|
3215
|
+
const summaryText = summaryParts.filter(Boolean).join("\uFF1B");
|
|
3216
|
+
if (summaryText) {
|
|
3217
|
+
const p = document.createElement("p");
|
|
3218
|
+
p.className = "icen-chart-summary";
|
|
3219
|
+
p.id = `icen-chart-a11y-${++a11ySeq}`;
|
|
3220
|
+
p.textContent = summaryText;
|
|
3221
|
+
body.appendChild(p);
|
|
3222
|
+
graphic.setAttribute("aria-describedby", p.id);
|
|
3223
|
+
} else {
|
|
3224
|
+
graphic.removeAttribute("aria-describedby");
|
|
3225
|
+
}
|
|
3226
|
+
if (conf.keyboard && KB_TYPES.has(type)) {
|
|
3227
|
+
graphic.setAttribute("tabindex", "0");
|
|
3228
|
+
graphic.setAttribute("data-icen-chart-kb", "");
|
|
3229
|
+
} else {
|
|
3230
|
+
graphic.removeAttribute("tabindex");
|
|
3231
|
+
graphic.removeAttribute("data-icen-chart-kb");
|
|
3232
|
+
}
|
|
3233
|
+
if (conf.table) body.appendChild(buildChartTable(view, spec, type, formatValue));
|
|
3234
|
+
applyKbCursor();
|
|
3235
|
+
};
|
|
2981
3236
|
const render = () => {
|
|
2982
3237
|
if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
|
|
2983
3238
|
const spec = current2;
|
|
@@ -3049,9 +3304,16 @@ function renderChart(el, raw) {
|
|
|
3049
3304
|
const graphic = root.querySelector('[role="img"]');
|
|
3050
3305
|
if (graphic && !graphic.getAttribute("aria-label")) {
|
|
3051
3306
|
graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
|
|
3307
|
+
} else if (!graphic) {
|
|
3308
|
+
const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
|
|
3309
|
+
if (dom) {
|
|
3310
|
+
dom.setAttribute("role", "img");
|
|
3311
|
+
dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
|
|
3312
|
+
}
|
|
3052
3313
|
}
|
|
3053
3314
|
}
|
|
3054
3315
|
if (loading) return;
|
|
3316
|
+
applyChartA11yPlus(view, spec, type, formatValue);
|
|
3055
3317
|
paintChartMarks(root, view, spec, formatValue, warnedMarks);
|
|
3056
3318
|
bindZoomGesture();
|
|
3057
3319
|
};
|
|
@@ -3133,6 +3395,7 @@ function renderChart(el, raw) {
|
|
|
3133
3395
|
releaseFluidWidth(root);
|
|
3134
3396
|
hiddenLegendKeys.delete(root);
|
|
3135
3397
|
zoomDragCleanup?.();
|
|
3398
|
+
root.removeEventListener("keydown", onKbKeydown);
|
|
3136
3399
|
root.textContent = "";
|
|
3137
3400
|
root.classList.remove("is-loading");
|
|
3138
3401
|
unbindEvents();
|
|
@@ -3761,7 +4024,13 @@ function onKeyDown2(e) {
|
|
|
3761
4024
|
|
|
3762
4025
|
// src/behaviors/datatable.ts
|
|
3763
4026
|
function defaultCompare(a, b) {
|
|
3764
|
-
if (typeof a === "number" && typeof b === "number")
|
|
4027
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
4028
|
+
if (Number.isNaN(a) || Number.isNaN(b)) {
|
|
4029
|
+
if (Number.isNaN(a) && Number.isNaN(b)) return 0;
|
|
4030
|
+
return Number.isNaN(a) ? 1 : -1;
|
|
4031
|
+
}
|
|
4032
|
+
return a - b;
|
|
4033
|
+
}
|
|
3765
4034
|
return String(a ?? "").localeCompare(String(b ?? ""), "zh-CN", { numeric: true });
|
|
3766
4035
|
}
|
|
3767
4036
|
function toNum2(v) {
|
|
@@ -4050,11 +4319,13 @@ function createTable(el, opts) {
|
|
|
4050
4319
|
const body = document.createElement("div");
|
|
4051
4320
|
body.className = "icen-dt-body";
|
|
4052
4321
|
body.setAttribute("role", "rowgroup");
|
|
4053
|
-
const summaryEl = document.createElement("div");
|
|
4054
|
-
summaryEl
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4322
|
+
const summaryEl = opts.summaryRow ? document.createElement("div") : null;
|
|
4323
|
+
if (summaryEl) {
|
|
4324
|
+
summaryEl.className = "icen-dt-row icen-dt-row--summary";
|
|
4325
|
+
summaryEl.setAttribute("role", "row");
|
|
4326
|
+
summaryEl.hidden = true;
|
|
4327
|
+
}
|
|
4328
|
+
canvas.append(head, body, ...summaryEl ? [summaryEl] : []);
|
|
4058
4329
|
scroll.appendChild(canvas);
|
|
4059
4330
|
root.appendChild(scroll);
|
|
4060
4331
|
const foot = document.createElement("div");
|
|
@@ -4868,6 +5139,7 @@ function createTable(el, opts) {
|
|
|
4868
5139
|
return wrap;
|
|
4869
5140
|
}
|
|
4870
5141
|
function renderSummary() {
|
|
5142
|
+
if (!summaryEl) return;
|
|
4871
5143
|
summaryEl.textContent = "";
|
|
4872
5144
|
summaryEl.hidden = true;
|
|
4873
5145
|
const cfg = opts.summaryRow;
|
|
@@ -5064,9 +5336,9 @@ function createTable(el, opts) {
|
|
|
5064
5336
|
}
|
|
5065
5337
|
}
|
|
5066
5338
|
let currentTotal = 0;
|
|
5067
|
-
function visibleRange(total) {
|
|
5339
|
+
function visibleRange(total, avail) {
|
|
5068
5340
|
if (!virtual) {
|
|
5069
|
-
if (opts.remote || opts.pagination === false) return [0, total];
|
|
5341
|
+
if (opts.remote || opts.pagination === false) return [0, Math.min(total, avail)];
|
|
5070
5342
|
const start2 = (page - 1) * pageSize;
|
|
5071
5343
|
return [start2, Math.min(total, start2 + pageSize)];
|
|
5072
5344
|
}
|
|
@@ -5081,6 +5353,10 @@ function createTable(el, opts) {
|
|
|
5081
5353
|
const rows = pipeline();
|
|
5082
5354
|
const entries = groupFn ? flatEntries() : null;
|
|
5083
5355
|
const total = entries ? entries.length : opts.remote ? opts.totalCount ?? data.length : rows.length;
|
|
5356
|
+
if (!opts.remote && opts.pagination !== false) {
|
|
5357
|
+
const pages = Math.max(1, Math.ceil(total / pageSize));
|
|
5358
|
+
if (page > pages) page = pages;
|
|
5359
|
+
}
|
|
5084
5360
|
navTotal = entries ? entries.length : rows.length;
|
|
5085
5361
|
currentTotal = total;
|
|
5086
5362
|
const keepTop = virtual ? scroll.scrollTop : 0;
|
|
@@ -5109,7 +5385,7 @@ function createTable(el, opts) {
|
|
|
5109
5385
|
renderSummary();
|
|
5110
5386
|
return;
|
|
5111
5387
|
}
|
|
5112
|
-
const [start, end] = visibleRange(total);
|
|
5388
|
+
const [start, end] = visibleRange(total, rows.length);
|
|
5113
5389
|
const frag = document.createDocumentFragment();
|
|
5114
5390
|
const offsets = frozenOffsets();
|
|
5115
5391
|
if (virtual && start > 0) {
|
|
@@ -5172,11 +5448,21 @@ function createTable(el, opts) {
|
|
|
5172
5448
|
const pages = Math.ceil(total / pageSize);
|
|
5173
5449
|
const pager = document.createElement("nav");
|
|
5174
5450
|
pager.className = "icen-dt-pager";
|
|
5175
|
-
|
|
5451
|
+
{
|
|
5452
|
+
const base = t("datatable.paginationAria");
|
|
5453
|
+
const used = /* @__PURE__ */ new Set();
|
|
5454
|
+
for (const el2 of document.querySelectorAll(".icen-dt-pager[aria-label]")) {
|
|
5455
|
+
if (!root.contains(el2)) used.add(el2.getAttribute("aria-label") ?? "");
|
|
5456
|
+
}
|
|
5457
|
+
let label = base, n = 2;
|
|
5458
|
+
while (used.has(label)) label = `${base} ${n++}`;
|
|
5459
|
+
pager.setAttribute("aria-label", label);
|
|
5460
|
+
}
|
|
5176
5461
|
const sizeSel = document.createElement("select");
|
|
5177
5462
|
sizeSel.className = "icen-dt-page-size";
|
|
5178
5463
|
sizeSel.setAttribute("aria-label", t("datatable.pageSizeAria"));
|
|
5179
|
-
|
|
5464
|
+
const sizeOptions = pageSizes.includes(pageSize) ? pageSizes : [...pageSizes, pageSize].sort((a, b) => a - b);
|
|
5465
|
+
for (const s of sizeOptions) {
|
|
5180
5466
|
const o = document.createElement("option");
|
|
5181
5467
|
o.value = String(s);
|
|
5182
5468
|
o.textContent = t("pagination.pageSize", { p0: s });
|
|
@@ -5268,6 +5554,7 @@ function createTable(el, opts) {
|
|
|
5268
5554
|
if (destroyed) return;
|
|
5269
5555
|
renderHead();
|
|
5270
5556
|
renderBody();
|
|
5557
|
+
syncFrozenWidths();
|
|
5271
5558
|
}
|
|
5272
5559
|
rekey();
|
|
5273
5560
|
renderAll();
|
|
@@ -5288,12 +5575,52 @@ function createTable(el, opts) {
|
|
|
5288
5575
|
opts.onPageChange?.(page, pageSize);
|
|
5289
5576
|
renderAll();
|
|
5290
5577
|
}
|
|
5578
|
+
function hasFluidFrozen() {
|
|
5579
|
+
return cols().some((c) => frozenSide(c) != null && !/^(\d+(?:\.\d+)?)px/.test(colWidths.get(c.key) ?? c.width ?? ""));
|
|
5580
|
+
}
|
|
5581
|
+
function syncFrozenWidths() {
|
|
5582
|
+
if (!hasFluidFrozen()) return;
|
|
5583
|
+
const visible = cols();
|
|
5584
|
+
const headCells = Array.from(headRow.children);
|
|
5585
|
+
const lead = headCells.length - visible.length;
|
|
5586
|
+
const left = /* @__PURE__ */ new Map();
|
|
5587
|
+
const right = /* @__PURE__ */ new Map();
|
|
5588
|
+
let acc = headCells.slice(0, lead).reduce((s, c) => s + c.offsetWidth, 0);
|
|
5589
|
+
for (let i = 0; i < visible.length; i++) {
|
|
5590
|
+
const c = visible[i];
|
|
5591
|
+
if (frozenSide(c) === "left") left.set(c.key, acc);
|
|
5592
|
+
acc += headCells[lead + i]?.offsetWidth ?? 0;
|
|
5593
|
+
}
|
|
5594
|
+
let accR = 0;
|
|
5595
|
+
for (let i = visible.length - 1; i >= 0; i--) {
|
|
5596
|
+
const c = visible[i];
|
|
5597
|
+
if (frozenSide(c) === "right") right.set(c.key, accR);
|
|
5598
|
+
accR += headCells[lead + i]?.offsetWidth ?? 0;
|
|
5599
|
+
}
|
|
5600
|
+
const rows = [headRow, ...summaryEl ? [summaryEl] : [], ...Array.from(body.querySelectorAll(".icen-dt-row"))];
|
|
5601
|
+
for (const row of rows) {
|
|
5602
|
+
const cells = Array.from(row.children);
|
|
5603
|
+
if (cells.length !== headCells.length) continue;
|
|
5604
|
+
cells.forEach((cell, i) => {
|
|
5605
|
+
const col = i >= lead ? visible[i - lead] : void 0;
|
|
5606
|
+
if (!col) return;
|
|
5607
|
+
const l = left.get(col.key);
|
|
5608
|
+
if (l != null && cell.classList.contains("icen-dt-cell--frozen")) cell.style.left = `${l}px`;
|
|
5609
|
+
const r = right.get(col.key);
|
|
5610
|
+
if (r != null && cell.classList.contains("icen-dt-cell--frozen-right")) cell.style.right = `${r}px`;
|
|
5611
|
+
});
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5291
5614
|
return {
|
|
5292
5615
|
setPage,
|
|
5293
5616
|
setPageSize,
|
|
5294
5617
|
setData(next) {
|
|
5295
5618
|
if (editing) cancelEdit(true);
|
|
5296
5619
|
data = next;
|
|
5620
|
+
if (typeof opts.rowKey !== "function" && typeof opts.rowKey !== "string" && selected.size > 0) {
|
|
5621
|
+
selected.clear();
|
|
5622
|
+
emitSelection();
|
|
5623
|
+
}
|
|
5297
5624
|
rekey();
|
|
5298
5625
|
invalidate();
|
|
5299
5626
|
page = 1;
|
|
@@ -5536,6 +5863,15 @@ function svgIcon(svg) {
|
|
|
5536
5863
|
return parseSvg(svg);
|
|
5537
5864
|
}
|
|
5538
5865
|
|
|
5866
|
+
// src/behaviors/url-safety.ts
|
|
5867
|
+
function safeUrl(uri) {
|
|
5868
|
+
const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
|
|
5869
|
+
if (!s) return void 0;
|
|
5870
|
+
if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
|
|
5871
|
+
if (/^data:\s*text\/html/.test(s)) return void 0;
|
|
5872
|
+
return uri;
|
|
5873
|
+
}
|
|
5874
|
+
|
|
5539
5875
|
// src/behaviors/ai-chat.ts
|
|
5540
5876
|
var ICON_COPY = iconHTML("copy");
|
|
5541
5877
|
var ICON_RETRY = iconHTML("refresh");
|
|
@@ -5563,6 +5899,8 @@ function createAiStream(el) {
|
|
|
5563
5899
|
el.setAttribute("aria-busy", "true");
|
|
5564
5900
|
if (reasoning) {
|
|
5565
5901
|
reasoning.classList.add("is-streaming");
|
|
5902
|
+
const timeEl = reasoning.querySelector(".icen-ai-reasoning-time");
|
|
5903
|
+
if (timeEl) timeEl.textContent = t("aiChat.thinkingNow");
|
|
5566
5904
|
setReasoningOpen(reasoning, true);
|
|
5567
5905
|
const head = reasoning.querySelector(".icen-ai-reasoning-head");
|
|
5568
5906
|
if (head && head.dataset.icenReasoningStart == null) head.dataset.icenReasoningStart = String(startedAt);
|
|
@@ -5650,10 +5988,9 @@ var ROLE_AVATAR = {
|
|
|
5650
5988
|
system: t("aiChat.roleSystem"),
|
|
5651
5989
|
tool: t("aiChat.roleTool")
|
|
5652
5990
|
};
|
|
5653
|
-
function
|
|
5654
|
-
const
|
|
5655
|
-
|
|
5656
|
-
return uri;
|
|
5991
|
+
function safeContentUrl(part) {
|
|
5992
|
+
const src = aiContentUrl(part);
|
|
5993
|
+
return src ? safeUrl(src) : void 0;
|
|
5657
5994
|
}
|
|
5658
5995
|
function renderAiContentPart(part) {
|
|
5659
5996
|
if (part.type === "text") {
|
|
@@ -5663,7 +6000,7 @@ function renderAiContentPart(part) {
|
|
|
5663
6000
|
return span;
|
|
5664
6001
|
}
|
|
5665
6002
|
if (part.type === "image") {
|
|
5666
|
-
const src =
|
|
6003
|
+
const src = safeContentUrl(part);
|
|
5667
6004
|
if (!src) return void 0;
|
|
5668
6005
|
const img = document.createElement("img");
|
|
5669
6006
|
img.className = "icen-ai-msg-media icen-ai-msg-media--image";
|
|
@@ -5673,7 +6010,7 @@ function renderAiContentPart(part) {
|
|
|
5673
6010
|
return img;
|
|
5674
6011
|
}
|
|
5675
6012
|
if (part.type === "audio") {
|
|
5676
|
-
const src =
|
|
6013
|
+
const src = safeContentUrl(part);
|
|
5677
6014
|
if (!src) return void 0;
|
|
5678
6015
|
const audio = document.createElement("audio");
|
|
5679
6016
|
audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
|
|
@@ -5682,7 +6019,7 @@ function renderAiContentPart(part) {
|
|
|
5682
6019
|
return audio;
|
|
5683
6020
|
}
|
|
5684
6021
|
if (part.type === "video") {
|
|
5685
|
-
const src =
|
|
6022
|
+
const src = safeContentUrl(part);
|
|
5686
6023
|
if (!src) return void 0;
|
|
5687
6024
|
const video = document.createElement("video");
|
|
5688
6025
|
video.className = "icen-ai-msg-media icen-ai-msg-media--video";
|
|
@@ -5694,7 +6031,7 @@ function renderAiContentPart(part) {
|
|
|
5694
6031
|
if (part.type === "file") {
|
|
5695
6032
|
const chip = h("span", "icen-ai-msg-file");
|
|
5696
6033
|
chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
|
|
5697
|
-
const href2 = part.url ?
|
|
6034
|
+
const href2 = part.url ? safeUrl(part.url) : void 0;
|
|
5698
6035
|
if (href2 && /^(https?:|data:)/i.test(href2)) {
|
|
5699
6036
|
const a2 = document.createElement("a");
|
|
5700
6037
|
a2.className = "icen-ai-msg-file-link";
|
|
@@ -5707,7 +6044,7 @@ function renderAiContentPart(part) {
|
|
|
5707
6044
|
}
|
|
5708
6045
|
const a = document.createElement("a");
|
|
5709
6046
|
a.className = "icen-ai-msg-link";
|
|
5710
|
-
const href =
|
|
6047
|
+
const href = safeUrl(part.uri);
|
|
5711
6048
|
if (href) a.href = href;
|
|
5712
6049
|
a.textContent = part.name ?? part.uri;
|
|
5713
6050
|
a.title = part.uri;
|
|
@@ -5769,7 +6106,7 @@ function renderAiMessage(scrollEl, model) {
|
|
|
5769
6106
|
errEl.textContent = message;
|
|
5770
6107
|
},
|
|
5771
6108
|
stream() {
|
|
5772
|
-
const span = h("span", "ai-msg-stream-text");
|
|
6109
|
+
const span = h("span", "icen-ai-msg-text ai-msg-stream-text");
|
|
5773
6110
|
body.appendChild(span);
|
|
5774
6111
|
return createAiStream(span);
|
|
5775
6112
|
}
|