@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/react.mjs
CHANGED
|
@@ -166,6 +166,7 @@ var ICEN_LOCALE_ZH_CN = {
|
|
|
166
166
|
"aiChat.roleTool": "\u5DE5",
|
|
167
167
|
"aiChat.roleUser": "\u6211",
|
|
168
168
|
"aiChat.thinking": "\u601D\u8003 {p0}",
|
|
169
|
+
"aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
|
|
169
170
|
/* ── aiComposer ── */
|
|
170
171
|
"aiComposer.attachAgent": "\u4EE3\u7406",
|
|
171
172
|
"aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
|
|
@@ -348,6 +349,19 @@ var ICEN_LOCALE_ZH_CN = {
|
|
|
348
349
|
"charts.noData": "\u6682\u65E0\u6570\u636E",
|
|
349
350
|
"charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
|
|
350
351
|
"charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
|
|
352
|
+
"charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
|
|
353
|
+
"charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
|
|
354
|
+
"charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
|
|
355
|
+
"charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
|
|
356
|
+
"charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
|
|
357
|
+
"charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
|
|
358
|
+
"charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
|
|
359
|
+
"charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
|
|
360
|
+
"charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
|
|
361
|
+
"charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
|
|
362
|
+
"charts.a11y.trendDown": "\u4E0B\u964D",
|
|
363
|
+
"charts.a11y.trendFlat": "\u6301\u5E73",
|
|
364
|
+
"charts.a11y.trendUp": "\u4E0A\u5347",
|
|
351
365
|
"charts.type.area": "\u9762\u79EF\u56FE",
|
|
352
366
|
"charts.type.donut": "\u73AF\u5F62\u56FE",
|
|
353
367
|
"charts.type.gauge": "\u4EEA\u8868\u76D8",
|
|
@@ -1213,7 +1227,8 @@ function withChrome(el, opts, hasLegend, paint, state, extras) {
|
|
|
1213
1227
|
emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
|
|
1214
1228
|
});
|
|
1215
1229
|
syncEye();
|
|
1216
|
-
head.append(title, eye);
|
|
1230
|
+
if (hasLegend) head.append(title, eye);
|
|
1231
|
+
else head.append(title);
|
|
1217
1232
|
el.append(head, body);
|
|
1218
1233
|
paint(body);
|
|
1219
1234
|
}
|
|
@@ -1314,7 +1329,7 @@ function renderVBar(el, opts) {
|
|
|
1314
1329
|
wrap.appendChild(track);
|
|
1315
1330
|
}
|
|
1316
1331
|
body.append(wrap, labelsRow(labelsUsed));
|
|
1317
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name
|
|
1332
|
+
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));
|
|
1318
1333
|
});
|
|
1319
1334
|
attachChartInteraction(el, "vbar");
|
|
1320
1335
|
return el;
|
|
@@ -1409,8 +1424,10 @@ function renderDonut(el, opts) {
|
|
|
1409
1424
|
"stroke-width": "14"
|
|
1410
1425
|
}));
|
|
1411
1426
|
let offset = 0;
|
|
1427
|
+
const gap = opts.segments.length > 1 ? 2.5 : 0;
|
|
1412
1428
|
opts.segments.forEach((seg, segIndex) => {
|
|
1413
|
-
const
|
|
1429
|
+
const arcLength = Math.max(0, seg.value / total * circumference);
|
|
1430
|
+
const dash = arcLength - Math.min(gap, arcLength * 0.1);
|
|
1414
1431
|
const arc = svgEl("circle", {
|
|
1415
1432
|
cx: "60",
|
|
1416
1433
|
cy: "60",
|
|
@@ -1424,7 +1441,7 @@ function renderDonut(el, opts) {
|
|
|
1424
1441
|
});
|
|
1425
1442
|
setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
|
|
1426
1443
|
svg.appendChild(arc);
|
|
1427
|
-
offset +=
|
|
1444
|
+
offset += arcLength;
|
|
1428
1445
|
});
|
|
1429
1446
|
const legend = document.createElement("div");
|
|
1430
1447
|
legend.className = "icen-chart-legend";
|
|
@@ -1459,8 +1476,9 @@ function renderLine(el, opts) {
|
|
|
1459
1476
|
const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
|
|
1460
1477
|
const defs = svgEl("defs", {});
|
|
1461
1478
|
for (let i = 0; i < 4; i++) {
|
|
1462
|
-
const y = pad + i * (height - pad * 2) / 3;
|
|
1479
|
+
const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
|
|
1463
1480
|
svg.appendChild(svgEl("line", {
|
|
1481
|
+
class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
|
|
1464
1482
|
x1: String(pad),
|
|
1465
1483
|
x2: String(width - pad),
|
|
1466
1484
|
y1: String(y),
|
|
@@ -1544,7 +1562,7 @@ function renderLine(el, opts) {
|
|
|
1544
1562
|
if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
|
|
1545
1563
|
wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
|
|
1546
1564
|
body.appendChild(wrap);
|
|
1547
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name
|
|
1565
|
+
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));
|
|
1548
1566
|
});
|
|
1549
1567
|
if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
|
|
1550
1568
|
attachChartInteraction(el, "line");
|
|
@@ -1651,7 +1669,7 @@ function renderRadar(el, opts) {
|
|
|
1651
1669
|
setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
|
|
1652
1670
|
svg.appendChild(dot);
|
|
1653
1671
|
}
|
|
1654
|
-
legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 })
|
|
1672
|
+
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 });
|
|
1655
1673
|
});
|
|
1656
1674
|
wrap.appendChild(svg);
|
|
1657
1675
|
body.appendChild(wrap);
|
|
@@ -1673,6 +1691,11 @@ function niceCeil(v) {
|
|
|
1673
1691
|
else nice = 10;
|
|
1674
1692
|
return nice * base;
|
|
1675
1693
|
}
|
|
1694
|
+
function tickPrecision(min, max, steps) {
|
|
1695
|
+
const span = Math.abs(max - min);
|
|
1696
|
+
if (!Number.isFinite(span) || span <= 0) return 0;
|
|
1697
|
+
return Math.max(0, Math.ceil(-Math.log10(span / steps)));
|
|
1698
|
+
}
|
|
1676
1699
|
function isoDate(d) {
|
|
1677
1700
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
1678
1701
|
const day = String(d.getDate()).padStart(2, "0");
|
|
@@ -1768,7 +1791,8 @@ function renderSparkline(el, opts) {
|
|
|
1768
1791
|
const tone = toneVar(opts.tone);
|
|
1769
1792
|
const points = values.map((value, i) => ({
|
|
1770
1793
|
x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
|
|
1771
|
-
|
|
1794
|
+
/* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
|
|
1795
|
+
y: height - pad - Math.max(0, value) / max * (height - pad * 2),
|
|
1772
1796
|
value
|
|
1773
1797
|
}));
|
|
1774
1798
|
const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
|
|
@@ -1893,6 +1917,7 @@ function renderCalendar(el, opts) {
|
|
|
1893
1917
|
weekdayRow.appendChild(s);
|
|
1894
1918
|
});
|
|
1895
1919
|
const max = maxOf(entries.map((e) => e.value));
|
|
1920
|
+
entries.sort((a, b) => a.date.localeCompare(b.date));
|
|
1896
1921
|
const pad = padFirstWeek(grid, entries[0].date, weekStart);
|
|
1897
1922
|
let lastMonth = -1;
|
|
1898
1923
|
entries.forEach((entry, i) => {
|
|
@@ -1951,8 +1976,9 @@ function renderScatter(el, opts) {
|
|
|
1951
1976
|
const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
|
|
1952
1977
|
const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
|
|
1953
1978
|
for (let i = 0; i <= 3; i++) {
|
|
1954
|
-
const y = pad + i * (height - pad * 2) / 3;
|
|
1979
|
+
const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
|
|
1955
1980
|
svg.appendChild(svgEl("line", {
|
|
1981
|
+
class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
|
|
1956
1982
|
x1: String(pad),
|
|
1957
1983
|
x2: String(width - pad),
|
|
1958
1984
|
y1: String(y),
|
|
@@ -1968,12 +1994,13 @@ function renderScatter(el, opts) {
|
|
|
1968
1994
|
"font-size": "8",
|
|
1969
1995
|
fill: "var(--icen-token-text-faint)"
|
|
1970
1996
|
});
|
|
1971
|
-
txt.textContent = fmt(opts,
|
|
1997
|
+
txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
|
|
1972
1998
|
svg.appendChild(txt);
|
|
1973
1999
|
}
|
|
1974
2000
|
for (let i = 0; i <= 4; i++) {
|
|
1975
|
-
const x = pad + i * (width - pad * 2) / 4;
|
|
2001
|
+
const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
|
|
1976
2002
|
svg.appendChild(svgEl("line", {
|
|
2003
|
+
class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
|
|
1977
2004
|
x1: String(x),
|
|
1978
2005
|
x2: String(x),
|
|
1979
2006
|
y1: String(pad),
|
|
@@ -1990,7 +2017,7 @@ function renderScatter(el, opts) {
|
|
|
1990
2017
|
"font-size": "8",
|
|
1991
2018
|
fill: "var(--icen-token-text-faint)"
|
|
1992
2019
|
});
|
|
1993
|
-
txt.textContent = fmt(opts,
|
|
2020
|
+
txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
|
|
1994
2021
|
svg.appendChild(txt);
|
|
1995
2022
|
}
|
|
1996
2023
|
if (opts.yLabel) {
|
|
@@ -2227,6 +2254,14 @@ function normalizeChartSpec(raw) {
|
|
|
2227
2254
|
}
|
|
2228
2255
|
if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
|
|
2229
2256
|
if (typeof s.loading === "boolean") spec.loading = s.loading;
|
|
2257
|
+
if (s.a11y && typeof s.a11y === "object") {
|
|
2258
|
+
const a = s.a11y;
|
|
2259
|
+
const a11y = {};
|
|
2260
|
+
if (typeof a.summary === "boolean") a11y.summary = a.summary;
|
|
2261
|
+
if (typeof a.table === "boolean") a11y.table = a.table;
|
|
2262
|
+
if (typeof a.keyboard === "boolean") a11y.keyboard = a.keyboard;
|
|
2263
|
+
if (Object.keys(a11y).length > 0) spec.a11y = a11y;
|
|
2264
|
+
}
|
|
2230
2265
|
if (Array.isArray(s.marks)) {
|
|
2231
2266
|
const marks = [];
|
|
2232
2267
|
for (const raw2 of s.marks) {
|
|
@@ -2354,6 +2389,7 @@ function renderChartSkeleton(body) {
|
|
|
2354
2389
|
body.appendChild(box);
|
|
2355
2390
|
}
|
|
2356
2391
|
var CHART_MARK_ACCENT = "var(--icen-token-accent)";
|
|
2392
|
+
var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
|
|
2357
2393
|
function markToneVar(tone) {
|
|
2358
2394
|
switch (tone) {
|
|
2359
2395
|
case "success":
|
|
@@ -2489,7 +2525,7 @@ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
|
|
|
2489
2525
|
y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
|
|
2490
2526
|
"text-anchor": "middle",
|
|
2491
2527
|
"font-size": "8",
|
|
2492
|
-
fill:
|
|
2528
|
+
fill: CHART_MARK_ACCENT_TEXT
|
|
2493
2529
|
});
|
|
2494
2530
|
label.textContent = mark.text ?? mark.label;
|
|
2495
2531
|
g.appendChild(label);
|
|
@@ -2581,6 +2617,81 @@ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
|
|
|
2581
2617
|
function chartAriaLabel(title, typeName) {
|
|
2582
2618
|
return title ? `${typeName}\uFF1A${title}` : typeName;
|
|
2583
2619
|
}
|
|
2620
|
+
function summarizeChart(view, type, fmt2) {
|
|
2621
|
+
const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
2622
|
+
const parts = [];
|
|
2623
|
+
if (series.length > 1) parts.push(t("charts.a11y.seriesCount", { p0: series.length }));
|
|
2624
|
+
if (type === "scatter") {
|
|
2625
|
+
const pts = view.points ?? [];
|
|
2626
|
+
if (pts.length > 0) {
|
|
2627
|
+
const xs = pts.map((p) => p.x);
|
|
2628
|
+
const ys = pts.map((p) => p.y);
|
|
2629
|
+
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)) }));
|
|
2630
|
+
}
|
|
2631
|
+
return parts.join("\uFF1B");
|
|
2632
|
+
}
|
|
2633
|
+
const labels = view.labels ?? [];
|
|
2634
|
+
if (labels.length > 1) parts.push(t("charts.a11y.range", { p0: labels[0], p1: labels[labels.length - 1] }));
|
|
2635
|
+
let min = Infinity;
|
|
2636
|
+
let max = -Infinity;
|
|
2637
|
+
let minAt = "";
|
|
2638
|
+
let maxAt = "";
|
|
2639
|
+
for (const s of series) {
|
|
2640
|
+
s.values.forEach((v, i) => {
|
|
2641
|
+
if (v < min) {
|
|
2642
|
+
min = v;
|
|
2643
|
+
minAt = labels[i] ?? String(i + 1);
|
|
2644
|
+
}
|
|
2645
|
+
if (v > max) {
|
|
2646
|
+
max = v;
|
|
2647
|
+
maxAt = labels[i] ?? String(i + 1);
|
|
2648
|
+
}
|
|
2649
|
+
});
|
|
2650
|
+
}
|
|
2651
|
+
if (Number.isFinite(min) && Number.isFinite(max)) {
|
|
2652
|
+
parts.push(t("charts.a11y.min", { p0: fmt2(min), p1: minAt }));
|
|
2653
|
+
parts.push(t("charts.a11y.max", { p0: fmt2(max), p1: maxAt }));
|
|
2654
|
+
}
|
|
2655
|
+
const first = series[0]?.values ?? [];
|
|
2656
|
+
if (first.length > 1) {
|
|
2657
|
+
const d = first[first.length - 1] - first[0];
|
|
2658
|
+
const key = Math.abs(d) < 1e-9 ? "charts.a11y.trendFlat" : d > 0 ? "charts.a11y.trendUp" : "charts.a11y.trendDown";
|
|
2659
|
+
parts.push(t("charts.a11y.trend", { p0: t(key) }));
|
|
2660
|
+
}
|
|
2661
|
+
return parts.join("\uFF1B");
|
|
2662
|
+
}
|
|
2663
|
+
function buildChartTable(view, spec, type, fmt2) {
|
|
2664
|
+
const table = document.createElement("table");
|
|
2665
|
+
table.className = "icen-chart-table";
|
|
2666
|
+
const caption = document.createElement("caption");
|
|
2667
|
+
caption.textContent = t("charts.a11y.tableCaption", { p0: spec.title ?? String(type) });
|
|
2668
|
+
table.appendChild(caption);
|
|
2669
|
+
const addRow = (target, cells, head) => {
|
|
2670
|
+
const tr = document.createElement("tr");
|
|
2671
|
+
for (const c of cells) {
|
|
2672
|
+
const cell = document.createElement(head ? "th" : "td");
|
|
2673
|
+
if (head) cell.scope = target.tagName === "THEAD" ? "col" : "row";
|
|
2674
|
+
cell.textContent = c;
|
|
2675
|
+
tr.appendChild(cell);
|
|
2676
|
+
}
|
|
2677
|
+
target.appendChild(tr);
|
|
2678
|
+
};
|
|
2679
|
+
const thead = table.createTHead();
|
|
2680
|
+
const tbody = table.createTBody();
|
|
2681
|
+
if (type === "scatter") {
|
|
2682
|
+
addRow(thead, ["x", "y"], true);
|
|
2683
|
+
for (const p of view.points ?? []) addRow(tbody, [fmt2(p.x), fmt2(p.y)], false);
|
|
2684
|
+
return table;
|
|
2685
|
+
}
|
|
2686
|
+
const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
2687
|
+
const labels = view.labels ?? [];
|
|
2688
|
+
addRow(thead, ["", ...series.map((s, i) => s.name || String(i + 1))], true);
|
|
2689
|
+
const n = Math.max(labels.length, ...series.map((s) => s.values.length));
|
|
2690
|
+
for (let i = 0; i < n; i++) {
|
|
2691
|
+
addRow(tbody, [labels[i] ?? String(i + 1), ...series.map((s) => fmt2(s.values[i] ?? 0))], false);
|
|
2692
|
+
}
|
|
2693
|
+
return table;
|
|
2694
|
+
}
|
|
2584
2695
|
function svgDimsOf(svg) {
|
|
2585
2696
|
const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
|
|
2586
2697
|
const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
|
|
@@ -2921,6 +3032,7 @@ function renderChart(el, raw) {
|
|
|
2921
3032
|
if (!isZoomableType(t2) || fullLength() < 2) return;
|
|
2922
3033
|
const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
|
|
2923
3034
|
if (!plot) return;
|
|
3035
|
+
plot.style.touchAction = current2.zoom === "x" ? "pan-y" : "none";
|
|
2924
3036
|
const on = (type, fn) => {
|
|
2925
3037
|
plot.addEventListener(type, fn);
|
|
2926
3038
|
};
|
|
@@ -2976,6 +3088,149 @@ function renderChart(el, raw) {
|
|
|
2976
3088
|
render();
|
|
2977
3089
|
});
|
|
2978
3090
|
};
|
|
3091
|
+
const KB_TYPES = /* @__PURE__ */ new Set(["line", "area", "vbar", "hbar", "scatter"]);
|
|
3092
|
+
const kbCursor = { si: 0, i: 0, active: false };
|
|
3093
|
+
let liveRegion = null;
|
|
3094
|
+
let a11ySeq = 0;
|
|
3095
|
+
const a11yOf = () => ({
|
|
3096
|
+
summary: current2.a11y?.summary !== false,
|
|
3097
|
+
table: current2.a11y?.table === true,
|
|
3098
|
+
keyboard: current2.a11y?.keyboard !== false
|
|
3099
|
+
});
|
|
3100
|
+
const seriesViewOf = (view) => view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
|
|
3101
|
+
const kbPointCount = (view) => typeOf() === "scatter" ? view.points?.length ?? 0 : Math.max(0, ...seriesViewOf(view).map((s) => s.values.length), view.labels?.length ?? 0);
|
|
3102
|
+
const kbCursorEl = () => {
|
|
3103
|
+
const t2 = typeOf();
|
|
3104
|
+
const view = viewOf();
|
|
3105
|
+
const series = seriesViewOf(view);
|
|
3106
|
+
const n = kbPointCount(view);
|
|
3107
|
+
if (n < 1) return null;
|
|
3108
|
+
const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
|
|
3109
|
+
const i = clampNum(kbCursor.i, 0, n - 1);
|
|
3110
|
+
if (t2 === "line" || t2 === "area") {
|
|
3111
|
+
const svg = root.querySelector(".icen-chart-line svg");
|
|
3112
|
+
if (!svg) return null;
|
|
3113
|
+
const dots = svg.querySelectorAll("circle");
|
|
3114
|
+
let base = 0;
|
|
3115
|
+
for (let k = 0; k < si; k++) base += Math.min(series[k].values.length, n);
|
|
3116
|
+
return dots.item(base + i) ?? null;
|
|
3117
|
+
}
|
|
3118
|
+
if (t2 === "scatter") return root.querySelector(".icen-chart-scatter svg")?.querySelectorAll("circle").item(i) ?? null;
|
|
3119
|
+
if (t2 === "vbar") return root.querySelectorAll(".icen-chart-vbar-bar").item(series.length > 1 ? i * series.length + si : i) ?? null;
|
|
3120
|
+
if (t2 === "hbar") return root.querySelectorAll(".icen-chart-hbar-bar").item(i) ?? null;
|
|
3121
|
+
return null;
|
|
3122
|
+
};
|
|
3123
|
+
const announceKb = (text) => {
|
|
3124
|
+
if (!liveRegion || !liveRegion.isConnected) {
|
|
3125
|
+
liveRegion = document.createElement("div");
|
|
3126
|
+
liveRegion.className = "icen-chart-live";
|
|
3127
|
+
liveRegion.setAttribute("aria-live", "polite");
|
|
3128
|
+
root.appendChild(liveRegion);
|
|
3129
|
+
}
|
|
3130
|
+
liveRegion.textContent = "";
|
|
3131
|
+
liveRegion.textContent = text;
|
|
3132
|
+
};
|
|
3133
|
+
const applyKbCursor = () => {
|
|
3134
|
+
for (const el2 of root.querySelectorAll(".icen-chart-kb-focus")) el2.classList.remove("icen-chart-kb-focus");
|
|
3135
|
+
if (!kbCursor.active) return;
|
|
3136
|
+
kbCursorEl()?.classList.add("icen-chart-kb-focus");
|
|
3137
|
+
};
|
|
3138
|
+
const announceCursor = () => {
|
|
3139
|
+
const view = viewOf();
|
|
3140
|
+
const series = seriesViewOf(view);
|
|
3141
|
+
const n = kbPointCount(view);
|
|
3142
|
+
if (n < 1) return;
|
|
3143
|
+
const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
|
|
3144
|
+
const i = clampNum(kbCursor.i, 0, Math.max(0, n - 1));
|
|
3145
|
+
const fmt2 = chartFormatValue(current2.format);
|
|
3146
|
+
if (typeOf() === "scatter") {
|
|
3147
|
+
const p = view.points?.[i];
|
|
3148
|
+
if (!p) return;
|
|
3149
|
+
announceKb(t("charts.a11y.point", { p0: `x ${fmt2(p.x)}`, p1: `y ${fmt2(p.y)}`, p2: i + 1, p3: n }));
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
const label = view.labels?.[i] ?? String(i + 1);
|
|
3153
|
+
const value = series[si]?.values[i] ?? 0;
|
|
3154
|
+
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 }));
|
|
3155
|
+
else announceKb(t("charts.a11y.point", { p0: label, p1: fmt2(value), p2: i + 1, p3: n }));
|
|
3156
|
+
};
|
|
3157
|
+
const onKbKeydown = (e) => {
|
|
3158
|
+
const conf = a11yOf();
|
|
3159
|
+
if (!conf.keyboard || !KB_TYPES.has(typeOf())) return;
|
|
3160
|
+
const g = root.querySelector("[data-icen-chart-kb]");
|
|
3161
|
+
if (!g || e.target !== g) return;
|
|
3162
|
+
if (e.key === "Escape") {
|
|
3163
|
+
if (zoomWindow) {
|
|
3164
|
+
zoomWindow = null;
|
|
3165
|
+
kbCursor.active = false;
|
|
3166
|
+
render();
|
|
3167
|
+
}
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
const view = viewOf();
|
|
3171
|
+
const series = seriesViewOf(view);
|
|
3172
|
+
const n = kbPointCount(view);
|
|
3173
|
+
if (n < 1) return;
|
|
3174
|
+
const siMax = Math.max(0, series.length - 1);
|
|
3175
|
+
let moved = true;
|
|
3176
|
+
switch (e.key) {
|
|
3177
|
+
case "ArrowRight":
|
|
3178
|
+
kbCursor.i = clampNum(kbCursor.i + 1, 0, n - 1);
|
|
3179
|
+
break;
|
|
3180
|
+
case "ArrowLeft":
|
|
3181
|
+
kbCursor.i = clampNum(kbCursor.i - 1, 0, n - 1);
|
|
3182
|
+
break;
|
|
3183
|
+
case "ArrowDown":
|
|
3184
|
+
kbCursor.si = clampNum(kbCursor.si + 1, 0, siMax);
|
|
3185
|
+
break;
|
|
3186
|
+
case "ArrowUp":
|
|
3187
|
+
kbCursor.si = clampNum(kbCursor.si - 1, 0, siMax);
|
|
3188
|
+
break;
|
|
3189
|
+
case "Home":
|
|
3190
|
+
kbCursor.i = 0;
|
|
3191
|
+
break;
|
|
3192
|
+
case "End":
|
|
3193
|
+
kbCursor.i = n - 1;
|
|
3194
|
+
break;
|
|
3195
|
+
default:
|
|
3196
|
+
moved = false;
|
|
3197
|
+
}
|
|
3198
|
+
if (!moved) return;
|
|
3199
|
+
e.preventDefault();
|
|
3200
|
+
kbCursor.active = true;
|
|
3201
|
+
applyKbCursor();
|
|
3202
|
+
announceCursor();
|
|
3203
|
+
};
|
|
3204
|
+
root.addEventListener("keydown", onKbKeydown);
|
|
3205
|
+
const applyChartA11yPlus = (view, spec, type, formatValue) => {
|
|
3206
|
+
const conf = a11yOf();
|
|
3207
|
+
const graphic = root.querySelector('[role="img"]');
|
|
3208
|
+
if (!graphic) return;
|
|
3209
|
+
const body = root.querySelector(".icen-chart-body") ?? graphic.parentElement ?? root;
|
|
3210
|
+
const summaryParts = [];
|
|
3211
|
+
if (conf.summary) summaryParts.push(summarizeChart(view, type, formatValue));
|
|
3212
|
+
if (conf.keyboard && KB_TYPES.has(type)) summaryParts.push(t("charts.a11y.keyboardHint"));
|
|
3213
|
+
const summaryText = summaryParts.filter(Boolean).join("\uFF1B");
|
|
3214
|
+
if (summaryText) {
|
|
3215
|
+
const p = document.createElement("p");
|
|
3216
|
+
p.className = "icen-chart-summary";
|
|
3217
|
+
p.id = `icen-chart-a11y-${++a11ySeq}`;
|
|
3218
|
+
p.textContent = summaryText;
|
|
3219
|
+
body.appendChild(p);
|
|
3220
|
+
graphic.setAttribute("aria-describedby", p.id);
|
|
3221
|
+
} else {
|
|
3222
|
+
graphic.removeAttribute("aria-describedby");
|
|
3223
|
+
}
|
|
3224
|
+
if (conf.keyboard && KB_TYPES.has(type)) {
|
|
3225
|
+
graphic.setAttribute("tabindex", "0");
|
|
3226
|
+
graphic.setAttribute("data-icen-chart-kb", "");
|
|
3227
|
+
} else {
|
|
3228
|
+
graphic.removeAttribute("tabindex");
|
|
3229
|
+
graphic.removeAttribute("data-icen-chart-kb");
|
|
3230
|
+
}
|
|
3231
|
+
if (conf.table) body.appendChild(buildChartTable(view, spec, type, formatValue));
|
|
3232
|
+
applyKbCursor();
|
|
3233
|
+
};
|
|
2979
3234
|
const render = () => {
|
|
2980
3235
|
if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
|
|
2981
3236
|
const spec = current2;
|
|
@@ -3047,9 +3302,16 @@ function renderChart(el, raw) {
|
|
|
3047
3302
|
const graphic = root.querySelector('[role="img"]');
|
|
3048
3303
|
if (graphic && !graphic.getAttribute("aria-label")) {
|
|
3049
3304
|
graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
|
|
3305
|
+
} else if (!graphic) {
|
|
3306
|
+
const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
|
|
3307
|
+
if (dom) {
|
|
3308
|
+
dom.setAttribute("role", "img");
|
|
3309
|
+
dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
|
|
3310
|
+
}
|
|
3050
3311
|
}
|
|
3051
3312
|
}
|
|
3052
3313
|
if (loading) return;
|
|
3314
|
+
applyChartA11yPlus(view, spec, type, formatValue);
|
|
3053
3315
|
paintChartMarks(root, view, spec, formatValue, warnedMarks);
|
|
3054
3316
|
bindZoomGesture();
|
|
3055
3317
|
};
|
|
@@ -3131,6 +3393,7 @@ function renderChart(el, raw) {
|
|
|
3131
3393
|
releaseFluidWidth(root);
|
|
3132
3394
|
hiddenLegendKeys.delete(root);
|
|
3133
3395
|
zoomDragCleanup?.();
|
|
3396
|
+
root.removeEventListener("keydown", onKbKeydown);
|
|
3134
3397
|
root.textContent = "";
|
|
3135
3398
|
root.classList.remove("is-loading");
|
|
3136
3399
|
unbindEvents();
|
|
@@ -3759,7 +4022,13 @@ function onKeyDown2(e) {
|
|
|
3759
4022
|
|
|
3760
4023
|
// src/behaviors/datatable.ts
|
|
3761
4024
|
function defaultCompare(a, b) {
|
|
3762
|
-
if (typeof a === "number" && typeof b === "number")
|
|
4025
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
4026
|
+
if (Number.isNaN(a) || Number.isNaN(b)) {
|
|
4027
|
+
if (Number.isNaN(a) && Number.isNaN(b)) return 0;
|
|
4028
|
+
return Number.isNaN(a) ? 1 : -1;
|
|
4029
|
+
}
|
|
4030
|
+
return a - b;
|
|
4031
|
+
}
|
|
3763
4032
|
return String(a ?? "").localeCompare(String(b ?? ""), "zh-CN", { numeric: true });
|
|
3764
4033
|
}
|
|
3765
4034
|
function toNum2(v) {
|
|
@@ -4048,11 +4317,13 @@ function createTable(el, opts) {
|
|
|
4048
4317
|
const body = document.createElement("div");
|
|
4049
4318
|
body.className = "icen-dt-body";
|
|
4050
4319
|
body.setAttribute("role", "rowgroup");
|
|
4051
|
-
const summaryEl = document.createElement("div");
|
|
4052
|
-
summaryEl
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4320
|
+
const summaryEl = opts.summaryRow ? document.createElement("div") : null;
|
|
4321
|
+
if (summaryEl) {
|
|
4322
|
+
summaryEl.className = "icen-dt-row icen-dt-row--summary";
|
|
4323
|
+
summaryEl.setAttribute("role", "row");
|
|
4324
|
+
summaryEl.hidden = true;
|
|
4325
|
+
}
|
|
4326
|
+
canvas.append(head, body, ...summaryEl ? [summaryEl] : []);
|
|
4056
4327
|
scroll.appendChild(canvas);
|
|
4057
4328
|
root.appendChild(scroll);
|
|
4058
4329
|
const foot = document.createElement("div");
|
|
@@ -4866,6 +5137,7 @@ function createTable(el, opts) {
|
|
|
4866
5137
|
return wrap;
|
|
4867
5138
|
}
|
|
4868
5139
|
function renderSummary() {
|
|
5140
|
+
if (!summaryEl) return;
|
|
4869
5141
|
summaryEl.textContent = "";
|
|
4870
5142
|
summaryEl.hidden = true;
|
|
4871
5143
|
const cfg = opts.summaryRow;
|
|
@@ -5062,9 +5334,9 @@ function createTable(el, opts) {
|
|
|
5062
5334
|
}
|
|
5063
5335
|
}
|
|
5064
5336
|
let currentTotal = 0;
|
|
5065
|
-
function visibleRange(total) {
|
|
5337
|
+
function visibleRange(total, avail) {
|
|
5066
5338
|
if (!virtual) {
|
|
5067
|
-
if (opts.remote || opts.pagination === false) return [0, total];
|
|
5339
|
+
if (opts.remote || opts.pagination === false) return [0, Math.min(total, avail)];
|
|
5068
5340
|
const start2 = (page - 1) * pageSize;
|
|
5069
5341
|
return [start2, Math.min(total, start2 + pageSize)];
|
|
5070
5342
|
}
|
|
@@ -5079,6 +5351,10 @@ function createTable(el, opts) {
|
|
|
5079
5351
|
const rows = pipeline();
|
|
5080
5352
|
const entries = groupFn ? flatEntries() : null;
|
|
5081
5353
|
const total = entries ? entries.length : opts.remote ? opts.totalCount ?? data.length : rows.length;
|
|
5354
|
+
if (!opts.remote && opts.pagination !== false) {
|
|
5355
|
+
const pages = Math.max(1, Math.ceil(total / pageSize));
|
|
5356
|
+
if (page > pages) page = pages;
|
|
5357
|
+
}
|
|
5082
5358
|
navTotal = entries ? entries.length : rows.length;
|
|
5083
5359
|
currentTotal = total;
|
|
5084
5360
|
const keepTop = virtual ? scroll.scrollTop : 0;
|
|
@@ -5107,7 +5383,7 @@ function createTable(el, opts) {
|
|
|
5107
5383
|
renderSummary();
|
|
5108
5384
|
return;
|
|
5109
5385
|
}
|
|
5110
|
-
const [start, end] = visibleRange(total);
|
|
5386
|
+
const [start, end] = visibleRange(total, rows.length);
|
|
5111
5387
|
const frag = document.createDocumentFragment();
|
|
5112
5388
|
const offsets = frozenOffsets();
|
|
5113
5389
|
if (virtual && start > 0) {
|
|
@@ -5170,11 +5446,21 @@ function createTable(el, opts) {
|
|
|
5170
5446
|
const pages = Math.ceil(total / pageSize);
|
|
5171
5447
|
const pager = document.createElement("nav");
|
|
5172
5448
|
pager.className = "icen-dt-pager";
|
|
5173
|
-
|
|
5449
|
+
{
|
|
5450
|
+
const base = t("datatable.paginationAria");
|
|
5451
|
+
const used = /* @__PURE__ */ new Set();
|
|
5452
|
+
for (const el2 of document.querySelectorAll(".icen-dt-pager[aria-label]")) {
|
|
5453
|
+
if (!root.contains(el2)) used.add(el2.getAttribute("aria-label") ?? "");
|
|
5454
|
+
}
|
|
5455
|
+
let label = base, n = 2;
|
|
5456
|
+
while (used.has(label)) label = `${base} ${n++}`;
|
|
5457
|
+
pager.setAttribute("aria-label", label);
|
|
5458
|
+
}
|
|
5174
5459
|
const sizeSel = document.createElement("select");
|
|
5175
5460
|
sizeSel.className = "icen-dt-page-size";
|
|
5176
5461
|
sizeSel.setAttribute("aria-label", t("datatable.pageSizeAria"));
|
|
5177
|
-
|
|
5462
|
+
const sizeOptions = pageSizes.includes(pageSize) ? pageSizes : [...pageSizes, pageSize].sort((a, b) => a - b);
|
|
5463
|
+
for (const s of sizeOptions) {
|
|
5178
5464
|
const o = document.createElement("option");
|
|
5179
5465
|
o.value = String(s);
|
|
5180
5466
|
o.textContent = t("pagination.pageSize", { p0: s });
|
|
@@ -5266,6 +5552,7 @@ function createTable(el, opts) {
|
|
|
5266
5552
|
if (destroyed) return;
|
|
5267
5553
|
renderHead();
|
|
5268
5554
|
renderBody();
|
|
5555
|
+
syncFrozenWidths();
|
|
5269
5556
|
}
|
|
5270
5557
|
rekey();
|
|
5271
5558
|
renderAll();
|
|
@@ -5286,12 +5573,52 @@ function createTable(el, opts) {
|
|
|
5286
5573
|
opts.onPageChange?.(page, pageSize);
|
|
5287
5574
|
renderAll();
|
|
5288
5575
|
}
|
|
5576
|
+
function hasFluidFrozen() {
|
|
5577
|
+
return cols().some((c) => frozenSide(c) != null && !/^(\d+(?:\.\d+)?)px/.test(colWidths.get(c.key) ?? c.width ?? ""));
|
|
5578
|
+
}
|
|
5579
|
+
function syncFrozenWidths() {
|
|
5580
|
+
if (!hasFluidFrozen()) return;
|
|
5581
|
+
const visible = cols();
|
|
5582
|
+
const headCells = Array.from(headRow.children);
|
|
5583
|
+
const lead = headCells.length - visible.length;
|
|
5584
|
+
const left = /* @__PURE__ */ new Map();
|
|
5585
|
+
const right = /* @__PURE__ */ new Map();
|
|
5586
|
+
let acc = headCells.slice(0, lead).reduce((s, c) => s + c.offsetWidth, 0);
|
|
5587
|
+
for (let i = 0; i < visible.length; i++) {
|
|
5588
|
+
const c = visible[i];
|
|
5589
|
+
if (frozenSide(c) === "left") left.set(c.key, acc);
|
|
5590
|
+
acc += headCells[lead + i]?.offsetWidth ?? 0;
|
|
5591
|
+
}
|
|
5592
|
+
let accR = 0;
|
|
5593
|
+
for (let i = visible.length - 1; i >= 0; i--) {
|
|
5594
|
+
const c = visible[i];
|
|
5595
|
+
if (frozenSide(c) === "right") right.set(c.key, accR);
|
|
5596
|
+
accR += headCells[lead + i]?.offsetWidth ?? 0;
|
|
5597
|
+
}
|
|
5598
|
+
const rows = [headRow, ...summaryEl ? [summaryEl] : [], ...Array.from(body.querySelectorAll(".icen-dt-row"))];
|
|
5599
|
+
for (const row of rows) {
|
|
5600
|
+
const cells = Array.from(row.children);
|
|
5601
|
+
if (cells.length !== headCells.length) continue;
|
|
5602
|
+
cells.forEach((cell, i) => {
|
|
5603
|
+
const col = i >= lead ? visible[i - lead] : void 0;
|
|
5604
|
+
if (!col) return;
|
|
5605
|
+
const l = left.get(col.key);
|
|
5606
|
+
if (l != null && cell.classList.contains("icen-dt-cell--frozen")) cell.style.left = `${l}px`;
|
|
5607
|
+
const r = right.get(col.key);
|
|
5608
|
+
if (r != null && cell.classList.contains("icen-dt-cell--frozen-right")) cell.style.right = `${r}px`;
|
|
5609
|
+
});
|
|
5610
|
+
}
|
|
5611
|
+
}
|
|
5289
5612
|
return {
|
|
5290
5613
|
setPage,
|
|
5291
5614
|
setPageSize,
|
|
5292
5615
|
setData(next) {
|
|
5293
5616
|
if (editing) cancelEdit(true);
|
|
5294
5617
|
data = next;
|
|
5618
|
+
if (typeof opts.rowKey !== "function" && typeof opts.rowKey !== "string" && selected.size > 0) {
|
|
5619
|
+
selected.clear();
|
|
5620
|
+
emitSelection();
|
|
5621
|
+
}
|
|
5295
5622
|
rekey();
|
|
5296
5623
|
invalidate();
|
|
5297
5624
|
page = 1;
|
|
@@ -5662,6 +5989,15 @@ function svgIcon(svg) {
|
|
|
5662
5989
|
return parseSvg(svg);
|
|
5663
5990
|
}
|
|
5664
5991
|
|
|
5992
|
+
// src/behaviors/url-safety.ts
|
|
5993
|
+
function safeUrl(uri) {
|
|
5994
|
+
const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
|
|
5995
|
+
if (!s) return void 0;
|
|
5996
|
+
if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
|
|
5997
|
+
if (/^data:\s*text\/html/.test(s)) return void 0;
|
|
5998
|
+
return uri;
|
|
5999
|
+
}
|
|
6000
|
+
|
|
5665
6001
|
// src/behaviors/ai-chat.ts
|
|
5666
6002
|
var ICON_COPY = iconHTML("copy");
|
|
5667
6003
|
var ICON_RETRY = iconHTML("refresh");
|
|
@@ -5689,6 +6025,8 @@ function createAiStream(el) {
|
|
|
5689
6025
|
el.setAttribute("aria-busy", "true");
|
|
5690
6026
|
if (reasoning) {
|
|
5691
6027
|
reasoning.classList.add("is-streaming");
|
|
6028
|
+
const timeEl = reasoning.querySelector(".icen-ai-reasoning-time");
|
|
6029
|
+
if (timeEl) timeEl.textContent = t("aiChat.thinkingNow");
|
|
5692
6030
|
setReasoningOpen(reasoning, true);
|
|
5693
6031
|
const head = reasoning.querySelector(".icen-ai-reasoning-head");
|
|
5694
6032
|
if (head && head.dataset.icenReasoningStart == null) head.dataset.icenReasoningStart = String(startedAt);
|
|
@@ -5776,10 +6114,9 @@ var ROLE_AVATAR = {
|
|
|
5776
6114
|
system: t("aiChat.roleSystem"),
|
|
5777
6115
|
tool: t("aiChat.roleTool")
|
|
5778
6116
|
};
|
|
5779
|
-
function
|
|
5780
|
-
const
|
|
5781
|
-
|
|
5782
|
-
return uri;
|
|
6117
|
+
function safeContentUrl(part) {
|
|
6118
|
+
const src = aiContentUrl(part);
|
|
6119
|
+
return src ? safeUrl(src) : void 0;
|
|
5783
6120
|
}
|
|
5784
6121
|
function renderAiContentPart(part) {
|
|
5785
6122
|
if (part.type === "text") {
|
|
@@ -5789,7 +6126,7 @@ function renderAiContentPart(part) {
|
|
|
5789
6126
|
return span;
|
|
5790
6127
|
}
|
|
5791
6128
|
if (part.type === "image") {
|
|
5792
|
-
const src =
|
|
6129
|
+
const src = safeContentUrl(part);
|
|
5793
6130
|
if (!src) return void 0;
|
|
5794
6131
|
const img = document.createElement("img");
|
|
5795
6132
|
img.className = "icen-ai-msg-media icen-ai-msg-media--image";
|
|
@@ -5799,7 +6136,7 @@ function renderAiContentPart(part) {
|
|
|
5799
6136
|
return img;
|
|
5800
6137
|
}
|
|
5801
6138
|
if (part.type === "audio") {
|
|
5802
|
-
const src =
|
|
6139
|
+
const src = safeContentUrl(part);
|
|
5803
6140
|
if (!src) return void 0;
|
|
5804
6141
|
const audio = document.createElement("audio");
|
|
5805
6142
|
audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
|
|
@@ -5808,7 +6145,7 @@ function renderAiContentPart(part) {
|
|
|
5808
6145
|
return audio;
|
|
5809
6146
|
}
|
|
5810
6147
|
if (part.type === "video") {
|
|
5811
|
-
const src =
|
|
6148
|
+
const src = safeContentUrl(part);
|
|
5812
6149
|
if (!src) return void 0;
|
|
5813
6150
|
const video = document.createElement("video");
|
|
5814
6151
|
video.className = "icen-ai-msg-media icen-ai-msg-media--video";
|
|
@@ -5820,7 +6157,7 @@ function renderAiContentPart(part) {
|
|
|
5820
6157
|
if (part.type === "file") {
|
|
5821
6158
|
const chip = h("span", "icen-ai-msg-file");
|
|
5822
6159
|
chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
|
|
5823
|
-
const href2 = part.url ?
|
|
6160
|
+
const href2 = part.url ? safeUrl(part.url) : void 0;
|
|
5824
6161
|
if (href2 && /^(https?:|data:)/i.test(href2)) {
|
|
5825
6162
|
const a2 = document.createElement("a");
|
|
5826
6163
|
a2.className = "icen-ai-msg-file-link";
|
|
@@ -5833,7 +6170,7 @@ function renderAiContentPart(part) {
|
|
|
5833
6170
|
}
|
|
5834
6171
|
const a = document.createElement("a");
|
|
5835
6172
|
a.className = "icen-ai-msg-link";
|
|
5836
|
-
const href =
|
|
6173
|
+
const href = safeUrl(part.uri);
|
|
5837
6174
|
if (href) a.href = href;
|
|
5838
6175
|
a.textContent = part.name ?? part.uri;
|
|
5839
6176
|
a.title = part.uri;
|
|
@@ -5895,7 +6232,7 @@ function renderAiMessage(scrollEl, model) {
|
|
|
5895
6232
|
errEl.textContent = message;
|
|
5896
6233
|
},
|
|
5897
6234
|
stream() {
|
|
5898
|
-
const span = h("span", "ai-msg-stream-text");
|
|
6235
|
+
const span = h("span", "icen-ai-msg-text ai-msg-stream-text");
|
|
5899
6236
|
body.appendChild(span);
|
|
5900
6237
|
return createAiStream(span);
|
|
5901
6238
|
}
|
|
@@ -6035,8 +6372,12 @@ function buildApproval() {
|
|
|
6035
6372
|
}
|
|
6036
6373
|
function applyTint(item, model) {
|
|
6037
6374
|
const tint = getAiKind(model.kind).tint;
|
|
6038
|
-
if (tint)
|
|
6039
|
-
|
|
6375
|
+
if (tint) {
|
|
6376
|
+
const slot = tint === "muted" ? "text-muted" : tint;
|
|
6377
|
+
item.style.setProperty("--ai-item-tint", `var(--icen-token-${slot})`);
|
|
6378
|
+
} else {
|
|
6379
|
+
item.style.removeProperty("--ai-item-tint");
|
|
6380
|
+
}
|
|
6040
6381
|
}
|
|
6041
6382
|
function applyKindVisual(parts, model) {
|
|
6042
6383
|
const kind = getAiKind(model.kind);
|