@icen.ai/ui 0.5.0 → 0.8.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.
Files changed (151) hide show
  1. package/AGENTS.md +262 -0
  2. package/README.md +52 -13
  3. package/dist/base.css +33 -5
  4. package/dist/behaviors/accordion.d.mts +7 -0
  5. package/dist/behaviors/accordion.mjs +37 -11
  6. package/dist/behaviors/ai-chat.d.mts +59 -0
  7. package/dist/behaviors/ai-chat.mjs +580 -0
  8. package/dist/behaviors/ai-composer.d.mts +137 -0
  9. package/dist/behaviors/ai-composer.mjs +2114 -0
  10. package/dist/behaviors/ai-core.d.mts +156 -0
  11. package/dist/behaviors/ai-core.mjs +504 -0
  12. package/dist/behaviors/ai-diff.d.mts +53 -0
  13. package/dist/behaviors/ai-diff.mjs +413 -0
  14. package/dist/behaviors/ai-panel.d.mts +101 -0
  15. package/dist/behaviors/ai-panel.mjs +1087 -0
  16. package/dist/behaviors/ai-provider.d.mts +198 -0
  17. package/dist/behaviors/ai-provider.mjs +1061 -0
  18. package/dist/behaviors/ai-tool.d.mts +26 -0
  19. package/dist/behaviors/ai-tool.mjs +2173 -0
  20. package/dist/behaviors/ai-tools.d.mts +84 -0
  21. package/dist/behaviors/ai-tools.mjs +1762 -0
  22. package/dist/behaviors/back-top.d.mts +20 -0
  23. package/dist/behaviors/back-top.mjs +64 -32
  24. package/dist/behaviors/carousel.d.mts +7 -0
  25. package/dist/behaviors/carousel.mjs +72 -27
  26. package/dist/behaviors/charts.d.mts +296 -0
  27. package/dist/behaviors/charts.mjs +1364 -440
  28. package/dist/behaviors/command-palette.d.mts +42 -0
  29. package/dist/behaviors/command-palette.mjs +167 -27
  30. package/dist/behaviors/context-menu.d.mts +53 -0
  31. package/dist/behaviors/context-menu.mjs +127 -39
  32. package/dist/behaviors/controls.d.mts +59 -0
  33. package/dist/behaviors/controls.mjs +601 -0
  34. package/dist/behaviors/copy.d.mts +7 -0
  35. package/dist/behaviors/copy.mjs +41 -15
  36. package/dist/behaviors/datatable.d.mts +90 -0
  37. package/dist/behaviors/datatable.mjs +279 -53
  38. package/dist/behaviors/date-picker.d.mts +4 -0
  39. package/dist/behaviors/date-picker.mjs +276 -69
  40. package/dist/behaviors/dropdown.d.mts +8 -0
  41. package/dist/behaviors/dropdown.mjs +171 -28
  42. package/dist/behaviors/events.d.mts +330 -0
  43. package/dist/behaviors/events.mjs +208 -0
  44. package/dist/behaviors/input.d.mts +4 -0
  45. package/dist/behaviors/input.mjs +52 -32
  46. package/dist/behaviors/modal.d.mts +30 -0
  47. package/dist/behaviors/modal.mjs +87 -16
  48. package/dist/behaviors/nav.d.mts +7 -0
  49. package/dist/behaviors/nav.mjs +57 -15
  50. package/dist/behaviors/notification.d.mts +188 -0
  51. package/dist/behaviors/notification.mjs +274 -140
  52. package/dist/behaviors/popover.d.mts +82 -0
  53. package/dist/behaviors/popover.mjs +92 -5
  54. package/dist/behaviors/select.d.mts +6 -0
  55. package/dist/behaviors/select.mjs +287 -45
  56. package/dist/behaviors/sidebar.d.mts +7 -0
  57. package/dist/behaviors/sidebar.mjs +44 -13
  58. package/dist/behaviors/slider.d.mts +7 -0
  59. package/dist/behaviors/slider.mjs +55 -43
  60. package/dist/behaviors/split-pane.d.mts +8 -0
  61. package/dist/behaviors/split-pane.mjs +70 -29
  62. package/dist/behaviors/tabs.d.mts +9 -0
  63. package/dist/behaviors/tabs.mjs +102 -26
  64. package/dist/behaviors/tag-input.d.mts +7 -0
  65. package/dist/behaviors/tag-input.mjs +66 -17
  66. package/dist/behaviors/theme.d.mts +36 -0
  67. package/dist/behaviors/theme.mjs +51 -5
  68. package/dist/behaviors/toast.d.mts +48 -0
  69. package/dist/behaviors/toast.mjs +98 -25
  70. package/dist/behaviors/tree.d.mts +7 -0
  71. package/dist/behaviors/tree.mjs +39 -15
  72. package/dist/behaviors/upload.d.mts +4 -0
  73. package/dist/behaviors/upload.mjs +79 -44
  74. package/dist/cli.mjs +1 -1
  75. package/dist/components/ai-chat.css +1037 -0
  76. package/dist/components/ai-chat.mjs +3 -0
  77. package/dist/components/ai-composer.mjs +3 -0
  78. package/dist/components/ai-context.mjs +2 -0
  79. package/dist/components/ai-diff.css +311 -0
  80. package/dist/components/ai-diff.mjs +3 -0
  81. package/dist/components/ai-files.mjs +3 -0
  82. package/dist/components/ai-message.mjs +3 -0
  83. package/dist/components/ai-panel.css +682 -0
  84. package/dist/components/ai-reasoning.mjs +3 -0
  85. package/dist/components/ai-subagent.mjs +2 -0
  86. package/dist/components/ai-todo.mjs +2 -0
  87. package/dist/components/ai-tool-call.mjs +2 -0
  88. package/dist/components/ai-tool.css +532 -0
  89. package/dist/components/ai-usage.mjs +3 -0
  90. package/dist/components/badge.css +5 -9
  91. package/dist/components/breadcrumb.css +0 -36
  92. package/dist/components/btn.css +4 -7
  93. package/dist/components/card.css +3 -6
  94. package/dist/components/chart-bar.css +10 -0
  95. package/dist/components/chart-calendar.mjs +4 -0
  96. package/dist/components/chart-gauge.css +1 -1
  97. package/dist/components/chart-heatmap.css +40 -0
  98. package/dist/components/chart-pie.css +0 -6
  99. package/dist/components/chart-scatter.css +24 -0
  100. package/dist/components/chart-scatter.mjs +4 -0
  101. package/dist/components/charts.css +87 -2
  102. package/dist/components/charts.mjs +1 -0
  103. package/dist/components/command-palette.css +2 -2
  104. package/dist/components/content.css +11 -25
  105. package/dist/components/copy.css +8 -8
  106. package/dist/components/datatable.css +5 -9
  107. package/dist/components/date-picker.css +4 -8
  108. package/dist/components/empty.css +0 -4
  109. package/dist/components/feedback.css +10 -17
  110. package/dist/components/form.css +13 -14
  111. package/dist/components/input.css +2 -2
  112. package/dist/components/layout.css +36 -36
  113. package/dist/components/media.css +12 -8
  114. package/dist/components/menu.css +2 -2
  115. package/dist/components/modal.css +1 -1
  116. package/dist/components/nav.css +11 -6
  117. package/dist/components/notification.css +27 -28
  118. package/dist/components/pagination.css +4 -2
  119. package/dist/components/pagination.mjs +1 -0
  120. package/dist/components/panel.css +16 -16
  121. package/dist/components/pill.css +15 -15
  122. package/dist/components/rating.mjs +1 -0
  123. package/dist/components/segmented.css +14 -6
  124. package/dist/components/segmented.mjs +1 -0
  125. package/dist/components/select.css +79 -24
  126. package/dist/components/sidebar.css +1 -1
  127. package/dist/components/split-pane.css +0 -1
  128. package/dist/components/stat.css +14 -18
  129. package/dist/components/steps.css +15 -5
  130. package/dist/components/steps.mjs +1 -0
  131. package/dist/components/switch.css +11 -13
  132. package/dist/components/switch.mjs +1 -0
  133. package/dist/components/table.css +46 -47
  134. package/dist/components/table.mjs +1 -0
  135. package/dist/components/tabs.css +57 -45
  136. package/dist/components/tag-input.css +5 -10
  137. package/dist/components/toast.css +16 -13
  138. package/dist/components/tooltip.css +2 -2
  139. package/dist/components/upload.css +0 -15
  140. package/dist/index.d.mts +39 -0
  141. package/dist/index.mjs +11243 -3312
  142. package/dist/registry.json +147 -9
  143. package/dist/retro-effects.css +23 -32
  144. package/dist/tokens/colors.css +4 -1
  145. package/dist/tokens/retro-effects.css +23 -32
  146. package/dist/tokens/style-profiles.css +24 -2
  147. package/dist/tokens/typography.css +2 -0
  148. package/dist/tokens.css +30 -3
  149. package/dist/ui.css +3420 -645
  150. package/docs/spec/ai-native.md +662 -0
  151. package/package.json +15 -5
@@ -0,0 +1,20 @@
1
+ interface BackTopOptions {
2
+ /** 是否自动创建一个默认按钮(portal 到 body) */
3
+ autoCreate?: boolean;
4
+ /** 显示阈值(px),默认 320 */
5
+ threshold?: number;
6
+ /** 滚动容器选择器,默认 window */
7
+ target?: string;
8
+ /** 滚动到多少 px,默认 0 */
9
+ offset?: number;
10
+ /** 扫描根节点,默认 document */
11
+ root?: ParentNode;
12
+ }
13
+ /**
14
+ * 初始化:扫描 root 下的 .back-top[data-back-top] 与 [data-back-top-auto]。
15
+ * 传 autoCreate 时自动创建一个默认按钮。
16
+ * 返回销毁函数:移除本次初始化挂上的全部 scroll/resize/click 监听。
17
+ */
18
+ declare function initBackTop(opts?: BackTopOptions): () => void;
19
+
20
+ export { initBackTop };
@@ -1,4 +1,16 @@
1
+ // src/behaviors/events.ts
2
+ function emitIcen(source, type, detail) {
3
+ return source.dispatchEvent(
4
+ new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
5
+ );
6
+ }
7
+
1
8
  // src/behaviors/back-top.ts
9
+ function numOr(value, fallback) {
10
+ if (value === void 0 || value === "") return fallback;
11
+ const n = Number(value);
12
+ return Number.isFinite(n) ? n : fallback;
13
+ }
2
14
  var AUTO_BTN_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m18 15-6-6-6 6"/></svg>';
3
15
  function prefersReducedMotion() {
4
16
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
@@ -26,11 +38,11 @@ function scrollToTop(target, offset = 0) {
26
38
  }
27
39
  function setup(btn, opts = {}) {
28
40
  const el = btn;
29
- if (el.__icenBackTopInit) return;
41
+ if (el.__icenBackTopInit) return void 0;
30
42
  el.__icenBackTopInit = true;
31
- const threshold = Number(btn.dataset.backTopThreshold ?? opts.threshold ?? 320) || 320;
43
+ const threshold = numOr(btn.dataset.backTopThreshold ?? opts.threshold, 320);
32
44
  const target = btn.dataset.backTopTarget ?? opts.target;
33
- const offset = Number(btn.dataset.backTopOffset ?? opts.offset ?? 0) || 0;
45
+ const offset = numOr(btn.dataset.backTopOffset ?? opts.offset, 0);
34
46
  let ticking = false;
35
47
  const apply = () => {
36
48
  ticking = false;
@@ -43,41 +55,61 @@ function setup(btn, opts = {}) {
43
55
  window.requestAnimationFrame(apply);
44
56
  };
45
57
  const { el: targetEl, isWindow } = getScrollTarget(target);
46
- if (isWindow) {
47
- window.addEventListener("scroll", onScroll, { passive: true });
48
- } else if (targetEl) {
49
- targetEl.addEventListener("scroll", onScroll, { passive: true });
50
- }
58
+ const scrollHost = !isWindow && targetEl ? targetEl : window;
59
+ scrollHost.addEventListener("scroll", onScroll, { passive: true });
51
60
  window.addEventListener("resize", onScroll, { passive: true });
52
- btn.addEventListener("click", () => scrollToTop(target, offset));
61
+ const onClick = () => {
62
+ scrollToTop(target, offset);
63
+ emitIcen(btn, "icen:back-top", {});
64
+ };
65
+ btn.addEventListener("click", onClick);
53
66
  apply();
67
+ return () => {
68
+ scrollHost.removeEventListener("scroll", onScroll);
69
+ window.removeEventListener("resize", onScroll);
70
+ btn.removeEventListener("click", onClick);
71
+ el.__icenBackTopInit = false;
72
+ };
54
73
  }
55
74
  function initBackTop(opts = {}) {
56
- if (typeof document === "undefined") return;
57
- if (typeof window === "undefined") return;
58
- const root = opts.root ?? document;
59
- if (opts.autoCreate) {
60
- let btn = document.body.querySelector(".back-top[data-back-top-auto]");
61
- if (!btn) {
62
- btn = document.createElement("button");
63
- btn.type = "button";
64
- btn.className = "back-top";
65
- btn.setAttribute("data-back-top", "");
66
- btn.setAttribute("data-back-top-auto", "");
67
- btn.setAttribute("aria-label", "\u56DE\u5230\u9876\u90E8");
68
- btn.innerHTML = AUTO_BTN_SVG;
69
- document.body.appendChild(btn);
75
+ const cleanups = [];
76
+ if (typeof document !== "undefined" && typeof window !== "undefined") {
77
+ const root = opts.root ?? document;
78
+ if (opts.autoCreate) {
79
+ let btn = document.body.querySelector(".back-top[data-back-top-auto]");
80
+ let created = false;
81
+ if (!btn) {
82
+ btn = document.createElement("button");
83
+ btn.type = "button";
84
+ btn.className = "back-top";
85
+ btn.setAttribute("data-back-top", "");
86
+ btn.setAttribute("data-back-top-auto", "");
87
+ btn.setAttribute("aria-label", "\u56DE\u5230\u9876\u90E8");
88
+ const svg = new DOMParser().parseFromString(AUTO_BTN_SVG, "image/svg+xml").documentElement;
89
+ btn.appendChild(document.importNode(svg, true));
90
+ document.body.appendChild(btn);
91
+ created = true;
92
+ }
93
+ const cleanup = setup(btn, opts);
94
+ if (cleanup) cleanups.push(cleanup);
95
+ if (created) cleanups.push(() => {
96
+ btn?.remove();
97
+ });
98
+ }
99
+ const candidates = [];
100
+ if (root instanceof Element && root.matches(".back-top[data-back-top]")) candidates.push(root);
101
+ candidates.push(...Array.from(root.querySelectorAll(".back-top[data-back-top]")));
102
+ for (const c of candidates) {
103
+ const el = c;
104
+ if (el.hasAttribute("data-back-top-auto") && opts.autoCreate) continue;
105
+ const cleanup = setup(el, opts);
106
+ if (cleanup) cleanups.push(cleanup);
70
107
  }
71
- setup(btn, opts);
72
- }
73
- const candidates = [];
74
- if (root instanceof Element && root.matches(".back-top[data-back-top]")) candidates.push(root);
75
- candidates.push(...Array.from(root.querySelectorAll(".back-top[data-back-top]")));
76
- for (const c of candidates) {
77
- const el = c;
78
- if (el.hasAttribute("data-back-top-auto") && opts.autoCreate) continue;
79
- setup(el, opts);
80
108
  }
109
+ return () => {
110
+ for (const fn of cleanups) fn();
111
+ cleanups.length = 0;
112
+ };
81
113
  }
82
114
  export {
83
115
  initBackTop
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 为 root 下每个 .carousel 初始化(root 自身是 .carousel 也算)。
3
+ * 返回销毁函数:移除本次挂上的全部监听并复位幂等标记(销毁后可重新 init)。SSR 下返回 no-op。
4
+ */
5
+ declare function initCarousel(root?: ParentNode): () => void;
6
+
7
+ export { initCarousel };
@@ -1,50 +1,74 @@
1
+ // src/behaviors/events.ts
2
+ function emitIcen(source, type, detail) {
3
+ return source.dispatchEvent(
4
+ new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
5
+ );
6
+ }
7
+
1
8
  // src/behaviors/carousel.ts
2
9
  function setup(carousel) {
3
10
  const el = carousel;
4
- if (el.__icenCarouselInit) return;
5
- el.__icenCarouselInit = true;
11
+ if (el.__icenCarouselInit) return void 0;
6
12
  const track = carousel.querySelector(":scope > .carousel-track");
7
- if (!track) return;
8
- const slides = Array.from(track.querySelectorAll(":scope > .carousel-slide"));
9
- const count = slides.length;
10
- if (count === 0) return;
13
+ if (!track) return void 0;
11
14
  const prev = carousel.querySelector(".carousel-arrow--prev");
12
15
  const next = carousel.querySelector(".carousel-arrow--next");
13
16
  const dotsBox = carousel.querySelector(".carousel-dots");
17
+ const querySlides = () => Array.from(track.querySelectorAll(":scope > .carousel-slide"));
14
18
  let index = 0;
15
- const dots = [];
16
- if (dotsBox && count > 1) {
19
+ let slides = querySlides();
20
+ let count = slides.length;
21
+ if (count === 0) return void 0;
22
+ el.__icenCarouselInit = true;
23
+ let dots = [];
24
+ let dotOffs = [];
25
+ function buildDots() {
26
+ for (const off of dotOffs) off();
27
+ dotOffs = [];
28
+ if (!dotsBox) return;
29
+ while (dotsBox.firstChild) dotsBox.removeChild(dotsBox.firstChild);
30
+ dots = [];
31
+ if (count <= 1) return;
17
32
  for (let i = 0; i < count; i++) {
18
33
  const dot = document.createElement("button");
19
34
  dot.type = "button";
20
35
  dot.className = "carousel-dot";
21
36
  dot.setAttribute("aria-label", `\u7B2C ${i + 1} \u5F20`);
22
- dot.addEventListener("click", () => go(i));
37
+ const onDotClick = () => go(i);
38
+ dot.addEventListener("click", onDotClick);
39
+ dotOffs.push(() => dot.removeEventListener("click", onDotClick));
23
40
  dotsBox.appendChild(dot);
24
41
  dots.push(dot);
25
42
  }
26
43
  }
27
- function render() {
28
- if (!track) return;
44
+ function syncSlides() {
45
+ slides = querySlides();
46
+ if (slides.length === count) return;
47
+ count = slides.length;
48
+ if (index >= count) index = Math.max(0, count - 1);
49
+ buildDots();
50
+ }
51
+ const render = () => {
29
52
  track.style.transform = `translateX(${-index * 100}%)`;
30
53
  slides.forEach((s, i) => s.setAttribute("aria-hidden", String(i !== index)));
31
54
  dots.forEach((d, i) => {
32
- d.classList.toggle("active", i === index);
55
+ d.classList.toggle("is-active", i === index);
33
56
  if (i === index) d.setAttribute("aria-current", "true");
34
57
  else d.removeAttribute("aria-current");
35
58
  });
36
- carousel.dispatchEvent(new CustomEvent("icen:carousel-change", {
37
- bubbles: true,
38
- detail: { index, count }
39
- }));
40
- }
59
+ };
41
60
  function go(i) {
61
+ syncSlides();
62
+ if (count === 0) return;
42
63
  index = (i % count + count) % count;
43
64
  render();
65
+ emitIcen(carousel, "icen:carousel-change", { index, count });
44
66
  }
45
- prev?.addEventListener("click", () => go(index - 1));
46
- next?.addEventListener("click", () => go(index + 1));
47
- carousel.addEventListener("keydown", (ev) => {
67
+ const onPrev = () => go(index - 1);
68
+ const onNext = () => go(index + 1);
69
+ prev?.addEventListener("click", onPrev);
70
+ next?.addEventListener("click", onNext);
71
+ const onKeyDown = (ev) => {
48
72
  const kev = ev;
49
73
  switch (kev.key) {
50
74
  case "ArrowLeft":
@@ -64,15 +88,36 @@ function setup(carousel) {
64
88
  go(count - 1);
65
89
  break;
66
90
  }
67
- });
91
+ };
92
+ carousel.addEventListener("keydown", onKeyDown);
93
+ buildDots();
68
94
  render();
95
+ return () => {
96
+ prev?.removeEventListener("click", onPrev);
97
+ next?.removeEventListener("click", onNext);
98
+ carousel.removeEventListener("keydown", onKeyDown);
99
+ for (const off of dotOffs) off();
100
+ dotOffs = [];
101
+ dotsBox?.replaceChildren();
102
+ el.__icenCarouselInit = false;
103
+ };
69
104
  }
70
- function initCarousel(root = document) {
71
- if (typeof document === "undefined") return;
72
- const containers = [];
73
- if (root instanceof Element && root.matches(".carousel")) containers.push(root);
74
- containers.push(...Array.from(root.querySelectorAll(".carousel")));
75
- for (const c of containers) setup(c);
105
+ function initCarousel(root) {
106
+ const cleanups = [];
107
+ if (typeof document !== "undefined") {
108
+ const scope = root ?? document;
109
+ const containers = [];
110
+ if (scope instanceof Element && scope.matches(".carousel")) containers.push(scope);
111
+ containers.push(...Array.from(scope.querySelectorAll(".carousel")));
112
+ for (const c of containers) {
113
+ const cleanup = setup(c);
114
+ if (cleanup) cleanups.push(cleanup);
115
+ }
116
+ }
117
+ return () => {
118
+ for (const fn of cleanups) fn();
119
+ cleanups.length = 0;
120
+ };
76
121
  }
77
122
  export {
78
123
  initCarousel
@@ -0,0 +1,296 @@
1
+ /** 色调名:内置 5 语义名(经 --token-* 取色);`string & {}` 保自动补全同时放行 registerChartTone 注册的命名档 */
2
+ type ChartTone = 'accent' | 'success' | 'warning' | 'error' | 'muted' | (string & {});
3
+ interface ChartSeriesOptions extends ChartChromeOptions {
4
+ labels: string[];
5
+ values: number[];
6
+ tone?: ChartTone;
7
+ emptyLabel?: string;
8
+ formatValue?: (value: number) => string;
9
+ }
10
+ interface ChartSegment {
11
+ label: string;
12
+ value: number;
13
+ tone?: ChartTone;
14
+ }
15
+ interface ChartSegmentsOptions extends ChartChromeOptions {
16
+ segments: ChartSegment[];
17
+ emptyLabel?: string;
18
+ formatValue?: (value: number) => string;
19
+ }
20
+ /**
21
+ * 注册自定义调色盘档位(CSS 变量名,宿主须在样式里提供该变量);tone 取值在
22
+ * 内置 5 语义名(accent/success/warning/error/muted)与调色盘序号之外的自定义
23
+ * 命名档。注册后任意 tone 槽位(spec.series[i].tone / segments[].tone / 各渲染器
24
+ * opts.tone)用该名字取色;查不到该变量时浏览器回退到初始色。
25
+ *
26
+ * @example
27
+ * ```css
28
+ * :root { --my-brand: #e2543e; }
29
+ * ```
30
+ * registerChartTone('brand', '--my-brand');
31
+ * spec.series[0].tone = 'brand';
32
+ */
33
+ declare function registerChartTone(name: string, cssVar: string): void;
34
+ /** 多系列系列项(ChartSpec 的 series 与各图型共用形态);tone 可为语义名或调色盘序号 1..6 */
35
+ interface ChartSeriesSpec {
36
+ name: string;
37
+ values: number[];
38
+ tone?: ChartTone | number;
39
+ }
40
+ /** 交互事件携带的标记数据(renderChart 委托层据此派 icen:chart-* 事件) */
41
+ interface ChartMarkData {
42
+ index?: number;
43
+ seriesIndex?: number;
44
+ seriesName?: string;
45
+ label?: string;
46
+ value?: number;
47
+ }
48
+ /** chrome 选项(各渲染器 options 皆含):title 进头部行;legend=false 初始隐藏图例 */
49
+ interface ChartChromeOptions {
50
+ title?: string;
51
+ legend?: boolean;
52
+ }
53
+ /** 垂直柱状图(单系列,或 series 多系列分组/堆叠——通用层与 renderChart 消费) */
54
+ interface ChartVBarOptions extends ChartSeriesOptions {
55
+ /** 多系列(labels 共用,values 长度对齐);缺省回落单系列 values */
56
+ series?: ChartSeriesSpec[];
57
+ /** 多系列时堆叠(默认分组并排) */
58
+ stacked?: boolean;
59
+ }
60
+ declare function renderVBar(el: HTMLElement, opts: ChartVBarOptions): HTMLElement;
61
+ /** 水平条形图 */
62
+ declare function renderHBar(el: HTMLElement, opts: ChartSeriesOptions): HTMLElement;
63
+ /** 堆叠条形图(单条 100% + 图例) */
64
+ declare function renderStack(el: HTMLElement, opts: ChartSegmentsOptions): HTMLElement;
65
+ /** 环形图(SVG stroke-dasharray 累加)+ 图例百分比 */
66
+ declare function renderDonut(el: HTMLElement, opts: ChartSegmentsOptions): HTMLElement;
67
+ /** 折线图(面积渐变 + 网格 + 数据点 + 底部 ≤7 个轴标签;series 多系列走调色盘 + 可切换图例) */
68
+ interface ChartLineOptions extends ChartSeriesOptions {
69
+ /** 多系列(labels 共用);缺省回落单系列 values */
70
+ series?: ChartSeriesSpec[];
71
+ /** 多系列时是否填充面积(默认首系列填充;area 类型全填充) */
72
+ fill?: boolean;
73
+ }
74
+ declare function renderLine(el: HTMLElement, opts: ChartLineOptions): HTMLElement;
75
+ /** 面积图(与折线同族,以面积填充为视觉主体) */
76
+ declare function renderArea(el: HTMLElement, opts: ChartSeriesOptions): HTMLElement;
77
+ interface RadarSeries {
78
+ name: string;
79
+ /** 各轴的值(0..max,顺序与 axes 一致) */
80
+ values: number[];
81
+ tone?: ChartTone;
82
+ }
83
+ interface ChartRadarOptions extends ChartChromeOptions {
84
+ /** 各轴名(顺时针排列,首轴指向正上方) */
85
+ axes: string[];
86
+ /** 一个或多个系列。values 长度须等于 axes 长度 */
87
+ series: RadarSeries[];
88
+ /** 各轴最大值(默认取全部系列该轴最大向上取整) */
89
+ max?: number;
90
+ /** 网格环层数(默认 4) */
91
+ levels?: number;
92
+ emptyLabel?: string;
93
+ formatValue?: (value: number) => string;
94
+ }
95
+ /** 雷达图(N 轴蛛网 + 多系列多边形 + 图例)。 */
96
+ declare function renderRadar(el: HTMLElement, opts: ChartRadarOptions): HTMLElement;
97
+ interface HeatmapDatum {
98
+ /** YYYY-MM-DD;仅用于 tooltip 与首周对齐 */
99
+ date: string;
100
+ value: number;
101
+ }
102
+ /** calendar/heatmap 本地化文案:纯字符串描述符,保持 JSON 可序列化(ChartSpec 是 AI 可调用的纯 JSON 契约,禁函数) */
103
+ interface ChartI18nLabels {
104
+ /** 周标签(7 项,行序与 weekStart 对齐;缺省 ['一','','三','','五','','日'],weekStart=0 时自动旋转为周日首) */
105
+ weekdays?: string[];
106
+ /** 月标签(12 项,索引即月 0..11;缺省 `${m+1}月`) */
107
+ months?: string[];
108
+ /** 色阶图例左端文案(默认「少」) */
109
+ less?: string;
110
+ /** 色阶图例右端文案(默认「多」) */
111
+ more?: string;
112
+ }
113
+ interface ChartHeatmapOptions extends ChartChromeOptions {
114
+ /** 精确形态:日期 + 值(旧 → 新)。与 values 二选一,data 优先。 */
115
+ data?: HeatmapDatum[];
116
+ /** 便捷形态:最近 N 天的值(旧 → 新),日期从今天回推 */
117
+ values?: number[];
118
+ /** 列数(周),默认按数据量推算(向上取整到整周) */
119
+ weeks?: number;
120
+ tone?: ChartTone;
121
+ /** 本地化:周首日(0=周日,默认 1=周一;与 date-picker 的 data-date-picker-week-start 语义对齐)与标签文案(纯字符串,保持 JSON 可序列化) */
122
+ weekStart?: 0 | 1;
123
+ labels?: ChartI18nLabels;
124
+ emptyLabel?: string;
125
+ formatValue?: (value: number) => string;
126
+ }
127
+ /** GitHub 贡献图式热力格:7 行(默认周一 → 周日,weekStart=0 则周日起)× N 周列,5 档色阶。 */
128
+ declare function renderHeatmap(el: HTMLElement, opts: ChartHeatmapOptions): HTMLElement;
129
+ /** 迷你趋势线(无轴小图,适合嵌入指标卡)。 */
130
+ declare function renderSparkline(el: HTMLElement, opts: ChartSeriesOptions): HTMLElement;
131
+ interface ChartGaugeOptions {
132
+ value: number;
133
+ max?: number;
134
+ tone?: ChartTone;
135
+ /** 中心百分比下方的小标签 */
136
+ label?: string;
137
+ formatValue?: (value: number) => string;
138
+ }
139
+ /** 进度环(环形单值 + 中心百分比)。 */
140
+ declare function renderGauge(el: HTMLElement, opts: ChartGaugeOptions): HTMLElement;
141
+ interface ChartCalendarOptions extends ChartChromeOptions {
142
+ /** ISO 日期数组(YYYY-MM-DD,与 values 配对;或用 data) */
143
+ dates?: string[];
144
+ values?: number[];
145
+ /** 精确形态:{date, value}[](与 dates+values 二选一,优先) */
146
+ data?: HeatmapDatum[];
147
+ tone?: ChartTone;
148
+ /** 本地化:周首日(0=周日,默认 1=周一;与 date-picker 的 data-date-picker-week-start 语义对齐)与标签文案(纯字符串,保持 JSON 可序列化) */
149
+ weekStart?: 0 | 1;
150
+ labels?: ChartI18nLabels;
151
+ emptyLabel?: string;
152
+ formatValue?: (value: number) => string;
153
+ }
154
+ /** 贡献日历(calendar heatmap):dates → 自动周布局 + 月份标签,GitHub 同款。周首日与文案可经 weekStart/labels 本地化。 */
155
+ declare function renderCalendar(el: HTMLElement, opts: ChartCalendarOptions): HTMLElement;
156
+ interface ChartPointSpec {
157
+ x: number;
158
+ y: number;
159
+ /** 第三维:气泡大小(映射到半径 3–10) */
160
+ size?: number;
161
+ label?: string;
162
+ }
163
+ interface ChartScatterOptions extends ChartChromeOptions {
164
+ points: ChartPointSpec[];
165
+ tone?: ChartTone;
166
+ /** X 轴名称(图例/tooltip 用) */
167
+ xLabel?: string;
168
+ yLabel?: string;
169
+ emptyLabel?: string;
170
+ formatValue?: (value: number) => string;
171
+ }
172
+ /** 散点图(可选 size 第三维 → 气泡);坐标域自动 nice 取整 + 边界刻度 */
173
+ declare function renderScatter(el: HTMLElement, opts: ChartScatterOptions): HTMLElement;
174
+ type ChartType = 'line' | 'area' | 'vbar' | 'hbar' | 'stack' | 'donut' | 'radar' | 'heatmap' | 'calendar' | 'sparkline' | 'gauge' | 'scatter';
175
+ /** 数值格式化描述符(替代函数回调——可 JSON 序列化,AI 可给) */
176
+ interface ChartValueFormat {
177
+ /** 值后缀单位("ms" / "¥" / "个") */
178
+ unit?: string;
179
+ /** compact:1.2k/3.4M;percent:原值即百分数补 %;ms:时长自适应(800ms/1.2s/3m);raw(默认) */
180
+ notation?: 'compact' | 'percent' | 'ms' | 'raw';
181
+ }
182
+ /** 任意维度数据记录 + 维度映射(data[] 路径:字段名可完全自定义) */
183
+ interface ChartDims {
184
+ /** 类目/横轴字段(默认 'label') */
185
+ label?: string;
186
+ /** 系列分组字段(默认 'series';存在即多系列) */
187
+ series?: string;
188
+ /** 数值字段(默认 'value') */
189
+ value?: string;
190
+ /** 散点 x 字段(默认 'x') */
191
+ x?: string;
192
+ /** 散点 y 字段(默认 'y') */
193
+ y?: string;
194
+ /** 散点 size 字段(默认 'size') */
195
+ size?: string;
196
+ }
197
+ /** 统一图表规格(纯 JSON;type 缺省由 inferChartType 推断) */
198
+ interface ChartSpec {
199
+ type?: string;
200
+ title?: string;
201
+ /** 类目轴(line/area/vbar/hbar) */
202
+ labels?: string[];
203
+ /** 单系列值(labels 配对;多系列用 series) */
204
+ values?: number[];
205
+ /** 多系列(line/vbar/radar) */
206
+ series?: ChartSeriesSpec[];
207
+ /** 占比型(donut/stack) */
208
+ segments?: ChartSegment[];
209
+ /** 雷达轴 */
210
+ axes?: string[];
211
+ /** 散点(或经 dims 从 data[] 提取) */
212
+ points?: ChartPointSpec[];
213
+ /** 任意维度原始记录 + dims 字段映射(pivot 到上述形态) */
214
+ data?: Record<string, unknown>[];
215
+ dims?: ChartDims;
216
+ /** 贡献日历:ISO 日期(与 values 配对) */
217
+ dates?: string[];
218
+ tone?: ChartTone;
219
+ /** vbar 多系列:堆叠(默认分组) */
220
+ stacked?: boolean;
221
+ /** line 多系列:填充面积 */
222
+ fill?: boolean;
223
+ weeks?: number;
224
+ /** radar/gauge 的值域上限 */
225
+ max?: number;
226
+ /** radar 网格层数 */
227
+ levels?: number;
228
+ format?: ChartValueFormat;
229
+ /** 内置 tooltip(默认开;false 关闭后只派事件) */
230
+ tooltip?: boolean;
231
+ /** 图例:false = 初始隐藏(头部行的小眼睛仍可再展开);true/缺省 = 显示 */
232
+ legend?: boolean;
233
+ emptyLabel?: string;
234
+ /** 本地化透传(calendar/heatmap):weekStart 0=周日/1=周一 与标签文案,纯字符串保持 JSON 可序列化 */
235
+ i18n?: ChartI18nLabels & {
236
+ weekStart?: 0 | 1;
237
+ };
238
+ }
239
+ /** 格式化描述符 → 函数(底层渲染器的 formatValue 槽) */
240
+ declare function chartFormatValue(format?: ChartValueFormat): (value: number) => string;
241
+ /**
242
+ * 归一化 ChartSpec:字符串输入尝试 JSON.parse;类型别名纠正;数值容错转换;
243
+ * data[] + dims pivot 到 labels/values/series/points。不抛异常——纠不了的
244
+ * 字段丢弃,返回的 spec 一定可交给 infer/render(空数据走 .chart-empty)。
245
+ */
246
+ declare function normalizeChartSpec(raw: unknown): ChartSpec;
247
+ /** 未指定 type 时的自动选型(确定性规则,AI 只给数据也能画对) */
248
+ declare function inferChartType(spec: ChartSpec): ChartType;
249
+ type ChartEventName = 'hover' | 'click' | 'dblclick' | 'contextmenu';
250
+ interface ChartEventDetail extends ChartMarkData {
251
+ type: ChartEventName;
252
+ /** hover 专有:enter / leave / move */
253
+ phase?: 'enter' | 'move' | 'leave';
254
+ /** 归一后的图型 */
255
+ chart: ChartType;
256
+ /** 事件发生时的标记元素 */
257
+ target?: Element;
258
+ /** 指针视口坐标(tooltip 定位/自定义浮层用) */
259
+ pointerX?: number;
260
+ pointerY?: number;
261
+ }
262
+ interface ChartHandle {
263
+ el: HTMLElement;
264
+ /** 归一 + 推断后的当前规格 */
265
+ spec: ChartSpec;
266
+ /** 原地重渲染(保留事件委托与句柄) */
267
+ update(next: ChartSpec | unknown): void;
268
+ /** icen:chart-<name> 监听糖(hover/click/dblclick/contextmenu);返回解绑函数 */
269
+ on(name: ChartEventName, listener: (detail: ChartEventDetail, event: Event) => void): () => void;
270
+ /** 清空渲染并解绑交互委托(destroy 后可重新 renderChart) */
271
+ destroy(): void;
272
+ }
273
+ /**
274
+ * 在图表容器上挂交互委托(幂等,沿用 __icenChartBound 标记):pointer / click /
275
+ * dblclick / contextmenu 归一到 [data-chart-mark] 标记 → icen:chart-hover
276
+ * (phase enter/move/leave)/ icen:chart-click / icen:chart-dblclick /
277
+ * icen:chart-contextmenu(均 bubbles,detail 含 index/seriesIndex/seriesName/
278
+ * label/value/指针坐标;右键默认 preventDefault),内置 tooltip portal 跟随指针。
279
+ *
280
+ * renderChart 内部即调它;12 个底层渲染器(renderVBar…renderScatter)收尾也会
281
+ * 自动调用——**直调底层渲染器同样能收 icen:chart-\* 事件**,无需经过 renderChart
282
+ * (detail.chart 报该渲染器的图型)。容器已处于某个绑定了委托的外层图表容器
283
+ * 内时自动跳过(renderChart → 底层渲染器路径,外层已覆盖该子树,防重复派发)。
284
+ * 返回解绑函数(移除全部监听并复位标记;解绑后可重新 bind / 重新渲染)。
285
+ */
286
+ declare function bindChartEvents(root: HTMLElement): () => void;
287
+ /**
288
+ * 统一入口:normalizeChartSpec → inferChartType(type 缺省时)→ 分发到底层
289
+ * 渲染器,并在 el 上挂交互委托(hover/click/dblclick/contextmenu → icen:chart-*,
290
+ * bubbles,detail 含 index/seriesIndex/seriesName/label/value/指针坐标)与可选
291
+ * tooltip(spec.tooltip !== false 时 portal 跟随指针;右键默认 preventDefault)。
292
+ * spec.title 有值时渲染 .chart-title。返回 { el, spec, update, on, destroy }。
293
+ */
294
+ declare function renderChart(el: HTMLElement, raw: ChartSpec | unknown): ChartHandle;
295
+
296
+ export { type ChartCalendarOptions, type ChartChromeOptions, type ChartDims, type ChartEventDetail, type ChartEventName, type ChartGaugeOptions, type ChartHandle, type ChartHeatmapOptions, type ChartI18nLabels, type ChartLineOptions, type ChartMarkData, type ChartPointSpec, type ChartRadarOptions, type ChartScatterOptions, type ChartSegment, type ChartSegmentsOptions, type ChartSeriesOptions, type ChartSeriesSpec, type ChartSpec, type ChartTone, type ChartType, type ChartVBarOptions, type ChartValueFormat, type HeatmapDatum, type RadarSeries, bindChartEvents, chartFormatValue, inferChartType, normalizeChartSpec, registerChartTone, renderArea, renderCalendar, renderChart, renderDonut, renderGauge, renderHBar, renderHeatmap, renderLine, renderRadar, renderScatter, renderSparkline, renderStack, renderVBar };