@icen.ai/ui 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +63 -14
- package/README.md +17 -9
- package/dist/base.css +4 -3
- package/dist/behaviors/accordion.d.mts +5 -2
- package/dist/behaviors/accordion.mjs +36 -11
- package/dist/behaviors/ai-branch.d.mts +19 -0
- package/dist/behaviors/ai-branch.mjs +217 -0
- package/dist/behaviors/ai-chat.d.mts +11 -7
- package/dist/behaviors/ai-chat.mjs +134 -51
- package/dist/behaviors/ai-composer.d.mts +28 -3
- package/dist/behaviors/ai-composer.mjs +399 -229
- package/dist/behaviors/ai-core.d.mts +9 -4
- package/dist/behaviors/ai-core.mjs +21 -8
- package/dist/behaviors/ai-diff.d.mts +2 -2
- package/dist/behaviors/ai-diff.mjs +172 -41
- package/dist/behaviors/ai-feedback.d.mts +26 -0
- package/dist/behaviors/ai-feedback.mjs +303 -0
- package/dist/behaviors/ai-panel.d.mts +26 -9
- package/dist/behaviors/ai-panel.mjs +211 -110
- package/dist/behaviors/ai-provider.mjs +54 -48
- package/dist/behaviors/ai-threads.d.mts +38 -0
- package/dist/behaviors/ai-threads.mjs +319 -0
- package/dist/behaviors/ai-tool.d.mts +12 -4
- package/dist/behaviors/ai-tool.mjs +316 -263
- package/dist/behaviors/ai-tools.d.mts +9 -6
- package/dist/behaviors/ai-tools.mjs +264 -155
- package/dist/behaviors/back-top.mjs +16 -1
- package/dist/behaviors/carousel.d.mts +5 -2
- package/dist/behaviors/carousel.mjs +53 -26
- package/dist/behaviors/charts.d.mts +170 -22
- package/dist/behaviors/charts.mjs +1016 -150
- package/dist/behaviors/command-palette.d.mts +40 -6
- package/dist/behaviors/command-palette.mjs +143 -15
- package/dist/behaviors/context-menu.d.mts +21 -4
- package/dist/behaviors/context-menu.mjs +122 -38
- package/dist/behaviors/controls.d.mts +59 -0
- package/dist/behaviors/controls.mjs +601 -0
- package/dist/behaviors/copy.d.mts +5 -2
- package/dist/behaviors/copy.mjs +37 -12
- package/dist/behaviors/datatable.d.mts +12 -0
- package/dist/behaviors/datatable.mjs +226 -43
- package/dist/behaviors/date-picker.d.mts +2 -2
- package/dist/behaviors/date-picker.mjs +171 -32
- package/dist/behaviors/dropdown.d.mts +6 -2
- package/dist/behaviors/dropdown.mjs +164 -25
- package/dist/behaviors/events.d.mts +523 -0
- package/dist/behaviors/events.mjs +208 -0
- package/dist/behaviors/input.mjs +25 -12
- package/dist/behaviors/kb-access.d.mts +34 -0
- package/dist/behaviors/kb-access.mjs +569 -0
- package/dist/behaviors/kb-acl.d.mts +50 -0
- package/dist/behaviors/kb-acl.mjs +405 -0
- package/dist/behaviors/kb-answer.d.mts +38 -0
- package/dist/behaviors/kb-answer.mjs +2055 -0
- package/dist/behaviors/kb-audit.d.mts +23 -0
- package/dist/behaviors/kb-audit.mjs +375 -0
- package/dist/behaviors/kb-canvas.d.mts +44 -0
- package/dist/behaviors/kb-canvas.mjs +589 -0
- package/dist/behaviors/kb-chain.d.mts +15 -0
- package/dist/behaviors/kb-chain.mjs +270 -0
- package/dist/behaviors/kb-checkpoint.d.mts +16 -0
- package/dist/behaviors/kb-checkpoint.mjs +342 -0
- package/dist/behaviors/kb-chunks.d.mts +31 -0
- package/dist/behaviors/kb-chunks.mjs +475 -0
- package/dist/behaviors/kb-citation.d.mts +38 -0
- package/dist/behaviors/kb-citation.mjs +677 -0
- package/dist/behaviors/kb-clarify.d.mts +20 -0
- package/dist/behaviors/kb-clarify.mjs +248 -0
- package/dist/behaviors/kb-conflict.d.mts +22 -0
- package/dist/behaviors/kb-conflict.mjs +284 -0
- package/dist/behaviors/kb-connector.d.mts +17 -0
- package/dist/behaviors/kb-connector.mjs +375 -0
- package/dist/behaviors/kb-core.d.mts +529 -0
- package/dist/behaviors/kb-core.mjs +890 -0
- package/dist/behaviors/kb-eval.d.mts +22 -0
- package/dist/behaviors/kb-eval.mjs +408 -0
- package/dist/behaviors/kb-explain.d.mts +11 -0
- package/dist/behaviors/kb-explain.mjs +243 -0
- package/dist/behaviors/kb-filter.d.mts +31 -0
- package/dist/behaviors/kb-filter.mjs +587 -0
- package/dist/behaviors/kb-gap.d.mts +27 -0
- package/dist/behaviors/kb-gap.mjs +273 -0
- package/dist/behaviors/kb-hittest.d.mts +34 -0
- package/dist/behaviors/kb-hittest.mjs +409 -0
- package/dist/behaviors/kb-metadata.d.mts +29 -0
- package/dist/behaviors/kb-metadata.mjs +326 -0
- package/dist/behaviors/kb-passage.d.mts +41 -0
- package/dist/behaviors/kb-passage.mjs +529 -0
- package/dist/behaviors/kb-pipeline.d.mts +18 -0
- package/dist/behaviors/kb-pipeline.mjs +381 -0
- package/dist/behaviors/kb-qa.d.mts +26 -0
- package/dist/behaviors/kb-qa.mjs +332 -0
- package/dist/behaviors/kb-rerank.d.mts +20 -0
- package/dist/behaviors/kb-rerank.mjs +315 -0
- package/dist/behaviors/kb-retrieval.d.mts +49 -0
- package/dist/behaviors/kb-retrieval.mjs +746 -0
- package/dist/behaviors/kb-review.d.mts +44 -0
- package/dist/behaviors/kb-review.mjs +451 -0
- package/dist/behaviors/kb-sandbox.d.mts +33 -0
- package/dist/behaviors/kb-sandbox.mjs +325 -0
- package/dist/behaviors/kb-segment.d.mts +32 -0
- package/dist/behaviors/kb-segment.mjs +499 -0
- package/dist/behaviors/kb-sources.d.mts +27 -0
- package/dist/behaviors/kb-sources.mjs +373 -0
- package/dist/behaviors/kb-sql.d.mts +43 -0
- package/dist/behaviors/kb-sql.mjs +948 -0
- package/dist/behaviors/kb-trace.d.mts +16 -0
- package/dist/behaviors/kb-trace.mjs +414 -0
- package/dist/behaviors/kb-visibility.d.mts +44 -0
- package/dist/behaviors/kb-visibility.mjs +403 -0
- package/dist/behaviors/kb-who-can.d.mts +32 -0
- package/dist/behaviors/kb-who-can.mjs +379 -0
- package/dist/behaviors/modal.d.mts +24 -5
- package/dist/behaviors/modal.mjs +76 -10
- package/dist/behaviors/nav.d.mts +1 -1
- package/dist/behaviors/nav.mjs +33 -7
- package/dist/behaviors/notification.d.mts +20 -4
- package/dist/behaviors/notification.mjs +53 -73
- package/dist/behaviors/popover.d.mts +39 -3
- package/dist/behaviors/popover.mjs +90 -4
- package/dist/behaviors/select.d.mts +4 -2
- package/dist/behaviors/select.mjs +161 -24
- package/dist/behaviors/sidebar.d.mts +5 -2
- package/dist/behaviors/sidebar.mjs +43 -13
- package/dist/behaviors/slider.d.mts +5 -2
- package/dist/behaviors/slider.mjs +54 -43
- package/dist/behaviors/split-pane.d.mts +6 -2
- package/dist/behaviors/split-pane.mjs +62 -21
- package/dist/behaviors/tabs.d.mts +3 -2
- package/dist/behaviors/tabs.mjs +65 -14
- package/dist/behaviors/tag-input.d.mts +5 -2
- package/dist/behaviors/tag-input.mjs +61 -21
- package/dist/behaviors/theme.d.mts +13 -2
- package/dist/behaviors/theme.mjs +48 -4
- package/dist/behaviors/toast.d.mts +30 -8
- package/dist/behaviors/toast.mjs +74 -7
- package/dist/behaviors/tree.d.mts +5 -2
- package/dist/behaviors/tree.mjs +38 -15
- package/dist/behaviors/upload.mjs +21 -23
- package/dist/cli.mjs +1 -1
- package/dist/components/ai-branch.mjs +3 -0
- package/dist/components/ai-chat.css +295 -0
- package/dist/components/ai-feedback.mjs +3 -0
- package/dist/components/ai-panel.css +218 -1
- package/dist/components/ai-threads.mjs +3 -0
- package/dist/components/ai-tool-call.mjs +1 -1
- package/dist/components/badge.css +1 -1
- package/dist/components/breadcrumb.css +0 -32
- package/dist/components/chart-calendar.mjs +1 -2
- package/dist/components/chart-graph.css +57 -0
- package/dist/components/chart-graph.mjs +4 -0
- package/dist/components/chart-map.mjs +3 -0
- package/dist/components/chart-pie.css +0 -6
- package/dist/components/chart-scatter.mjs +1 -1
- package/dist/components/charts.css +33 -1
- package/dist/components/charts.mjs +1 -0
- package/dist/components/content.css +3 -16
- package/dist/components/datatable.css +1 -1
- package/dist/components/date-picker.css +1 -1
- package/dist/components/kb-access.mjs +4 -0
- package/dist/components/kb-acl.mjs +4 -0
- package/dist/components/kb-agent.css +481 -0
- package/dist/components/kb-answer.mjs +4 -0
- package/dist/components/kb-audit.mjs +4 -0
- package/dist/components/kb-canvas.mjs +4 -0
- package/dist/components/kb-chain.mjs +4 -0
- package/dist/components/kb-checkpoint.mjs +4 -0
- package/dist/components/kb-chunks.mjs +4 -0
- package/dist/components/kb-citation.mjs +4 -0
- package/dist/components/kb-clarify.mjs +4 -0
- package/dist/components/kb-conflict.mjs +4 -0
- package/dist/components/kb-connector.mjs +4 -0
- package/dist/components/kb-data.css +649 -0
- package/dist/components/kb-eval.mjs +4 -0
- package/dist/components/kb-explain.mjs +4 -0
- package/dist/components/kb-filter.mjs +4 -0
- package/dist/components/kb-gap.mjs +4 -0
- package/dist/components/kb-ground.css +566 -0
- package/dist/components/kb-hittest.mjs +4 -0
- package/dist/components/kb-ingest.css +898 -0
- package/dist/components/kb-metadata.mjs +4 -0
- package/dist/components/kb-ops.css +548 -0
- package/dist/components/kb-passage.mjs +4 -0
- package/dist/components/kb-perm.css +444 -0
- package/dist/components/kb-pipeline.mjs +4 -0
- package/dist/components/kb-qa.mjs +4 -0
- package/dist/components/kb-rerank.mjs +4 -0
- package/dist/components/kb-retrieval.mjs +4 -0
- package/dist/components/kb-review.mjs +4 -0
- package/dist/components/kb-sandbox.mjs +4 -0
- package/dist/components/kb-search.css +940 -0
- package/dist/components/kb-segment.mjs +4 -0
- package/dist/components/kb-sources.mjs +4 -0
- package/dist/components/kb-sql.mjs +4 -0
- package/dist/components/kb-trace.mjs +4 -0
- package/dist/components/kb-visibility.mjs +4 -0
- package/dist/components/kb-who-can.mjs +4 -0
- package/dist/components/kb.css +252 -0
- package/dist/components/kb.mjs +9 -0
- package/dist/components/notification.css +2 -3
- package/dist/components/pagination.css +3 -1
- package/dist/components/pagination.mjs +1 -0
- package/dist/components/rating.mjs +1 -0
- package/dist/components/segmented.css +9 -1
- package/dist/components/segmented.mjs +1 -1
- package/dist/components/select.css +67 -4
- package/dist/components/steps.css +13 -3
- package/dist/components/steps.mjs +1 -0
- package/dist/components/switch.css +3 -1
- package/dist/components/switch.mjs +1 -0
- package/dist/components/table.mjs +1 -0
- package/dist/components/tabs.css +23 -0
- package/dist/components/tag-input.css +1 -6
- package/dist/components/upload.css +0 -15
- package/dist/index.d.mts +48 -11
- package/dist/index.mjs +13205 -3615
- package/dist/registry.json +366 -15
- package/dist/retro-effects.css +3 -16
- package/dist/tokens/retro-effects.css +3 -16
- package/dist/tokens/style-profiles.css +3 -2
- package/dist/tokens/typography.css +2 -0
- package/dist/tokens.css +5 -2
- package/dist/ui.css +5713 -267
- package/docs/research/2026-10-03-ai-kb-components.md +392 -0
- package/docs/research/2026-10-03-kb-permissions.md +992 -0
- package/docs/spec/ai-native.md +7 -4
- package/docs/spec/kb-family.md +443 -0
- package/package.json +2 -2
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
// src/behaviors/ai-core.ts
|
|
2
|
+
var AI_STATUSES = [
|
|
3
|
+
"pending",
|
|
4
|
+
"running",
|
|
5
|
+
"streaming",
|
|
6
|
+
"approval",
|
|
7
|
+
"done",
|
|
8
|
+
"error",
|
|
9
|
+
"cancelled"
|
|
10
|
+
];
|
|
2
11
|
function aiStatusLabel(s) {
|
|
3
12
|
const labels = {
|
|
4
13
|
pending: "\u7B49\u5F85",
|
|
@@ -135,10 +144,9 @@ var BUILTIN_KINDS = {
|
|
|
135
144
|
note: { label: "\u7B14\u8BB0", icon: ICON_FILE_TEXT, tint: "muted" },
|
|
136
145
|
chart: { label: "\u56FE\u8868", icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
|
|
137
146
|
};
|
|
138
|
-
var FALLBACK_KIND = { label: "\u7B14\u8BB0", icon: ICON_FILE_TEXT, tint: "muted" };
|
|
139
147
|
var kindRegistry = new Map(Object.entries(BUILTIN_KINDS));
|
|
140
148
|
function getAiKind(name) {
|
|
141
|
-
return kindRegistry.get(name.trim().toLowerCase()) ??
|
|
149
|
+
return kindRegistry.get(name.trim().toLowerCase()) ?? BUILTIN_KINDS.note;
|
|
142
150
|
}
|
|
143
151
|
function str(v) {
|
|
144
152
|
return typeof v === "string" && v ? v : void 0;
|
|
@@ -267,6 +275,12 @@ function normalizeContentParts(raw) {
|
|
|
267
275
|
}
|
|
268
276
|
return out;
|
|
269
277
|
}
|
|
278
|
+
function h(tag, className, text) {
|
|
279
|
+
const node = document.createElement(tag);
|
|
280
|
+
if (className) node.className = className;
|
|
281
|
+
if (text != null) node.textContent = text;
|
|
282
|
+
return node;
|
|
283
|
+
}
|
|
270
284
|
function svgIcon(svg2) {
|
|
271
285
|
if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
|
|
272
286
|
let parsed;
|
|
@@ -279,15 +293,15 @@ function svgIcon(svg2) {
|
|
|
279
293
|
if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
|
|
280
294
|
return null;
|
|
281
295
|
}
|
|
282
|
-
const sanitize = (
|
|
283
|
-
for (const attr of Array.from(
|
|
296
|
+
const sanitize = (el) => {
|
|
297
|
+
for (const attr of Array.from(el.attributes)) {
|
|
284
298
|
const name = attr.name.toLowerCase();
|
|
285
|
-
if (name.startsWith("on"))
|
|
299
|
+
if (name.startsWith("on")) el.removeAttribute(attr.name);
|
|
286
300
|
if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
|
|
287
|
-
|
|
301
|
+
el.removeAttribute(attr.name);
|
|
288
302
|
}
|
|
289
303
|
}
|
|
290
|
-
for (const child of Array.from(
|
|
304
|
+
for (const child of Array.from(el.children)) {
|
|
291
305
|
const tag = child.tagName.toLowerCase();
|
|
292
306
|
if (tag === "script" || tag === "foreignobject") {
|
|
293
307
|
child.remove();
|
|
@@ -300,21 +314,22 @@ function svgIcon(svg2) {
|
|
|
300
314
|
return document.importNode(root, true);
|
|
301
315
|
}
|
|
302
316
|
|
|
317
|
+
// src/behaviors/events.ts
|
|
318
|
+
function emitIcen(source, type, detail) {
|
|
319
|
+
return source.dispatchEvent(
|
|
320
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
303
324
|
// src/behaviors/ai-chat.ts
|
|
304
325
|
function safeHref(uri) {
|
|
305
326
|
const s = uri.trim().toLowerCase();
|
|
306
327
|
if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
|
|
307
328
|
return uri;
|
|
308
329
|
}
|
|
309
|
-
function el(tag, className, text) {
|
|
310
|
-
const node = document.createElement(tag);
|
|
311
|
-
if (className) node.className = className;
|
|
312
|
-
if (text != null) node.textContent = text;
|
|
313
|
-
return node;
|
|
314
|
-
}
|
|
315
330
|
function renderAiContentPart(part) {
|
|
316
331
|
if (part.type === "text") {
|
|
317
|
-
const span =
|
|
332
|
+
const span = h("span", "ai-msg-text");
|
|
318
333
|
span.textContent = part.text;
|
|
319
334
|
if (part.state === "streaming") span.classList.add("is-streaming");
|
|
320
335
|
return span;
|
|
@@ -349,8 +364,8 @@ function renderAiContentPart(part) {
|
|
|
349
364
|
return video;
|
|
350
365
|
}
|
|
351
366
|
if (part.type === "file") {
|
|
352
|
-
const chip =
|
|
353
|
-
chip.appendChild(
|
|
367
|
+
const chip = h("span", "ai-msg-file");
|
|
368
|
+
chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? "\u6587\u4EF6"));
|
|
354
369
|
const href2 = part.url ? safeHref(part.url) : void 0;
|
|
355
370
|
if (href2 && /^(https?:|data:)/i.test(href2)) {
|
|
356
371
|
const a2 = document.createElement("a");
|
|
@@ -373,7 +388,10 @@ function renderAiContentPart(part) {
|
|
|
373
388
|
|
|
374
389
|
// src/behaviors/charts.ts
|
|
375
390
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
391
|
+
var REGISTERED_TONES = /* @__PURE__ */ new Map();
|
|
376
392
|
function toneVar(tone = "accent") {
|
|
393
|
+
const registered = REGISTERED_TONES.get(tone);
|
|
394
|
+
if (registered) return registered;
|
|
377
395
|
switch (tone) {
|
|
378
396
|
case "success":
|
|
379
397
|
return "var(--token-success)";
|
|
@@ -405,15 +423,15 @@ function sampleLabels(labels, max = 7) {
|
|
|
405
423
|
return out;
|
|
406
424
|
}
|
|
407
425
|
function svgEl(tag, attrs) {
|
|
408
|
-
const
|
|
409
|
-
for (const [k, v] of Object.entries(attrs))
|
|
410
|
-
return
|
|
426
|
+
const el = document.createElementNS(SVG_NS, tag);
|
|
427
|
+
for (const [k, v] of Object.entries(attrs)) el.setAttribute(k, v);
|
|
428
|
+
return el;
|
|
411
429
|
}
|
|
412
|
-
function renderEmpty(
|
|
430
|
+
function renderEmpty(el, label) {
|
|
413
431
|
const box = document.createElement("div");
|
|
414
432
|
box.className = "chart-empty";
|
|
415
433
|
box.textContent = label ?? "\u6682\u65E0\u6570\u636E";
|
|
416
|
-
|
|
434
|
+
el.appendChild(box);
|
|
417
435
|
}
|
|
418
436
|
function legendItem(label, valueText, tone) {
|
|
419
437
|
const row = document.createElement("div");
|
|
@@ -479,30 +497,30 @@ var CHART_EYE_OFF_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24
|
|
|
479
497
|
function parseChartSvg(svg2) {
|
|
480
498
|
try {
|
|
481
499
|
const doc = new DOMParser().parseFromString(svg2, "image/svg+xml");
|
|
482
|
-
const
|
|
483
|
-
return
|
|
500
|
+
const el = doc.documentElement;
|
|
501
|
+
return el && el.tagName.toLowerCase() === "svg" && !doc.querySelector("parsererror") ? document.importNode(el, true) : null;
|
|
484
502
|
} catch {
|
|
485
503
|
return null;
|
|
486
504
|
}
|
|
487
505
|
}
|
|
488
|
-
function withChrome(
|
|
489
|
-
if (
|
|
490
|
-
|
|
491
|
-
paint(
|
|
506
|
+
function withChrome(el, opts, hasLegend, paint, state) {
|
|
507
|
+
if (el.dataset.chartBody != null) {
|
|
508
|
+
el.textContent = "";
|
|
509
|
+
paint(el);
|
|
492
510
|
return;
|
|
493
511
|
}
|
|
494
|
-
|
|
512
|
+
el.textContent = "";
|
|
495
513
|
const body = document.createElement("div");
|
|
496
514
|
body.className = "chart-body";
|
|
497
515
|
body.dataset.chartBody = "";
|
|
498
516
|
if (!opts.title && !hasLegend) {
|
|
499
|
-
|
|
517
|
+
el.appendChild(body);
|
|
500
518
|
paint(body);
|
|
501
519
|
return;
|
|
502
520
|
}
|
|
503
521
|
let hidden = state && state.hidden != null ? state.hidden : opts.legend === false;
|
|
504
522
|
if (state) state.hidden = hidden;
|
|
505
|
-
|
|
523
|
+
el.setAttribute("data-legend-hidden", String(hidden));
|
|
506
524
|
const head = document.createElement("div");
|
|
507
525
|
head.className = "chart-head";
|
|
508
526
|
const title = document.createElement("div");
|
|
@@ -514,7 +532,7 @@ function withChrome(el2, opts, hasLegend, paint, state) {
|
|
|
514
532
|
eye.className = "chart-legend-eye";
|
|
515
533
|
eye.dataset.chartLegendEye = "";
|
|
516
534
|
const syncEye = () => {
|
|
517
|
-
const nowHidden =
|
|
535
|
+
const nowHidden = el.getAttribute("data-legend-hidden") === "true";
|
|
518
536
|
eye.setAttribute("aria-pressed", String(!nowHidden));
|
|
519
537
|
eye.setAttribute("aria-label", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
|
|
520
538
|
eye.setAttribute("title", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
|
|
@@ -522,22 +540,19 @@ function withChrome(el2, opts, hasLegend, paint, state) {
|
|
|
522
540
|
if (icon) eye.replaceChildren(icon);
|
|
523
541
|
};
|
|
524
542
|
eye.addEventListener("click", () => {
|
|
525
|
-
const nowHidden =
|
|
543
|
+
const nowHidden = el.getAttribute("data-legend-hidden") === "true";
|
|
526
544
|
hidden = !nowHidden;
|
|
527
545
|
if (state) state.hidden = hidden;
|
|
528
|
-
|
|
546
|
+
el.setAttribute("data-legend-hidden", String(hidden));
|
|
529
547
|
syncEye();
|
|
530
|
-
|
|
531
|
-
bubbles: true,
|
|
532
|
-
detail: { visible: hidden ? false : true }
|
|
533
|
-
}));
|
|
548
|
+
emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
|
|
534
549
|
});
|
|
535
550
|
syncEye();
|
|
536
551
|
head.append(title, eye);
|
|
537
|
-
|
|
552
|
+
el.append(head, body);
|
|
538
553
|
paint(body);
|
|
539
554
|
}
|
|
540
|
-
function toggleLegend(items, scope
|
|
555
|
+
function toggleLegend(items, scope) {
|
|
541
556
|
const legend = document.createElement("div");
|
|
542
557
|
legend.className = "chart-legend chart-legend--toggle";
|
|
543
558
|
for (const item of items) {
|
|
@@ -556,10 +571,7 @@ function toggleLegend(items, scope, _opts) {
|
|
|
556
571
|
scope.querySelectorAll(`[data-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
|
|
557
572
|
m.classList.toggle("is-off", off);
|
|
558
573
|
});
|
|
559
|
-
legend
|
|
560
|
-
bubbles: true,
|
|
561
|
-
detail: { key: item.key, seriesIndex: item.si, hidden: off }
|
|
562
|
-
}));
|
|
574
|
+
emitIcen(legend, "icen:chart-legend-toggle", { key: item.key, seriesIndex: item.si, hidden: off });
|
|
563
575
|
};
|
|
564
576
|
row.addEventListener("click", toggle);
|
|
565
577
|
row.addEventListener("keydown", (e) => {
|
|
@@ -577,12 +589,12 @@ function toggleLegend(items, scope, _opts) {
|
|
|
577
589
|
}
|
|
578
590
|
return legend;
|
|
579
591
|
}
|
|
580
|
-
function renderVBar(
|
|
581
|
-
if (typeof document === "undefined") return;
|
|
592
|
+
function renderVBar(el, opts) {
|
|
593
|
+
if (typeof document === "undefined") return el;
|
|
582
594
|
const seriesList = normalizeSeriesInput(opts);
|
|
583
595
|
const labels = opts.labels ?? [];
|
|
584
596
|
const n = Math.min(labels.length, ...seriesList.map((s) => s.values.length));
|
|
585
|
-
withChrome(
|
|
597
|
+
withChrome(el, opts, seriesList.length > 1, (body) => {
|
|
586
598
|
if (n === 0 || seriesList.length === 0) {
|
|
587
599
|
renderEmpty(body, opts.emptyLabel);
|
|
588
600
|
return;
|
|
@@ -629,12 +641,14 @@ function renderVBar(el2, opts) {
|
|
|
629
641
|
wrap.appendChild(track);
|
|
630
642
|
}
|
|
631
643
|
body.append(wrap, labelsRow(labelsUsed));
|
|
632
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap
|
|
644
|
+
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
|
|
633
645
|
});
|
|
646
|
+
attachChartInteraction(el, "vbar");
|
|
647
|
+
return el;
|
|
634
648
|
}
|
|
635
|
-
function renderHBar(
|
|
636
|
-
if (typeof document === "undefined") return;
|
|
637
|
-
withChrome(
|
|
649
|
+
function renderHBar(el, opts) {
|
|
650
|
+
if (typeof document === "undefined") return el;
|
|
651
|
+
withChrome(el, opts, false, (body) => {
|
|
638
652
|
const n = Math.min(opts.labels.length, opts.values.length);
|
|
639
653
|
if (n === 0) {
|
|
640
654
|
renderEmpty(body, opts.emptyLabel);
|
|
@@ -667,10 +681,12 @@ function renderHBar(el2, opts) {
|
|
|
667
681
|
});
|
|
668
682
|
body.appendChild(wrap);
|
|
669
683
|
});
|
|
684
|
+
attachChartInteraction(el, "hbar");
|
|
685
|
+
return el;
|
|
670
686
|
}
|
|
671
|
-
function renderStack(
|
|
672
|
-
if (typeof document === "undefined") return;
|
|
673
|
-
withChrome(
|
|
687
|
+
function renderStack(el, opts) {
|
|
688
|
+
if (typeof document === "undefined") return el;
|
|
689
|
+
withChrome(el, opts, opts.segments.length > 0, (body) => {
|
|
674
690
|
const total = opts.segments.reduce((sum2, s) => sum2 + s.value, 0);
|
|
675
691
|
if (opts.segments.length === 0 || total <= 0) {
|
|
676
692
|
renderEmpty(body, opts.emptyLabel);
|
|
@@ -678,13 +694,13 @@ function renderStack(el2, opts) {
|
|
|
678
694
|
}
|
|
679
695
|
const bar = document.createElement("div");
|
|
680
696
|
bar.className = "chart-stack";
|
|
681
|
-
for (const seg of opts.segments) {
|
|
697
|
+
for (const [segIndex, seg] of opts.segments.entries()) {
|
|
682
698
|
const s = document.createElement("div");
|
|
683
699
|
s.className = "chart-stack-seg";
|
|
684
700
|
s.style.width = `${seg.value / total * 100}%`;
|
|
685
701
|
if (seg.tone) s.style.setProperty("--chart-tone", toneVar(seg.tone));
|
|
686
702
|
s.setAttribute("title", `${seg.label}: ${fmt(opts, seg.value)}`);
|
|
687
|
-
setMarkData(s, { index:
|
|
703
|
+
setMarkData(s, { index: segIndex, label: seg.label, value: seg.value });
|
|
688
704
|
bar.appendChild(s);
|
|
689
705
|
}
|
|
690
706
|
const legend = document.createElement("div");
|
|
@@ -694,10 +710,12 @@ function renderStack(el2, opts) {
|
|
|
694
710
|
}
|
|
695
711
|
body.append(bar, legend);
|
|
696
712
|
});
|
|
713
|
+
attachChartInteraction(el, "stack");
|
|
714
|
+
return el;
|
|
697
715
|
}
|
|
698
|
-
function renderDonut(
|
|
699
|
-
if (typeof document === "undefined") return;
|
|
700
|
-
withChrome(
|
|
716
|
+
function renderDonut(el, opts) {
|
|
717
|
+
if (typeof document === "undefined") return el;
|
|
718
|
+
withChrome(el, opts, opts.segments.length > 0, (body) => {
|
|
701
719
|
const total = opts.segments.reduce((sum2, s) => sum2 + s.value, 0);
|
|
702
720
|
if (opts.segments.length === 0 || total <= 0) {
|
|
703
721
|
renderEmpty(body, opts.emptyLabel);
|
|
@@ -743,14 +761,16 @@ function renderDonut(el2, opts) {
|
|
|
743
761
|
wrap.append(svg2, legend);
|
|
744
762
|
body.appendChild(wrap);
|
|
745
763
|
});
|
|
764
|
+
attachChartInteraction(el, "donut");
|
|
765
|
+
return el;
|
|
746
766
|
}
|
|
747
767
|
var lineGradientSeq = 0;
|
|
748
|
-
function renderLine(
|
|
749
|
-
if (typeof document === "undefined") return;
|
|
768
|
+
function renderLine(el, opts) {
|
|
769
|
+
if (typeof document === "undefined") return el;
|
|
750
770
|
const seriesList = normalizeSeriesInput(opts);
|
|
751
771
|
const labels = opts.labels ?? [];
|
|
752
772
|
const n = Math.min(labels.length, ...seriesList.map((s) => s.values.length));
|
|
753
|
-
withChrome(
|
|
773
|
+
withChrome(el, opts, seriesList.length > 1, (body) => {
|
|
754
774
|
if (n === 0 || seriesList.length === 0) {
|
|
755
775
|
renderEmpty(body, opts.emptyLabel);
|
|
756
776
|
return;
|
|
@@ -851,12 +871,14 @@ function renderLine(el2, opts) {
|
|
|
851
871
|
if (defs.firstChild) svg2.insertBefore(defs, svg2.firstChild);
|
|
852
872
|
wrap.append(svg2, labelsRow(sampleLabels(labelsUsed)));
|
|
853
873
|
body.appendChild(wrap);
|
|
854
|
-
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap
|
|
874
|
+
if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
|
|
855
875
|
});
|
|
876
|
+
attachChartInteraction(el, "line");
|
|
877
|
+
return el;
|
|
856
878
|
}
|
|
857
|
-
function renderRadar(
|
|
858
|
-
if (typeof document === "undefined") return;
|
|
859
|
-
withChrome(
|
|
879
|
+
function renderRadar(el, opts) {
|
|
880
|
+
if (typeof document === "undefined") return el;
|
|
881
|
+
withChrome(el, opts, opts.series.length > 1, (body) => {
|
|
860
882
|
const axes = opts.axes;
|
|
861
883
|
const n = axes.length;
|
|
862
884
|
if (n < 3 || opts.series.length === 0) {
|
|
@@ -957,13 +979,12 @@ function renderRadar(el2, opts) {
|
|
|
957
979
|
}
|
|
958
980
|
legendItems.push({ key: s.name || `\u7CFB\u5217${si + 1}`, label: s.name || `\u7CFB\u5217${si + 1}`, tone: s.tone, si });
|
|
959
981
|
});
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
l.className = "chart-legend";
|
|
963
|
-
return l;
|
|
964
|
-
})());
|
|
982
|
+
const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
|
|
983
|
+
wrap.append(svg2, ...legend ? [legend] : []);
|
|
965
984
|
body.appendChild(wrap);
|
|
966
985
|
});
|
|
986
|
+
attachChartInteraction(el, "radar");
|
|
987
|
+
return el;
|
|
967
988
|
}
|
|
968
989
|
function niceCeil(v) {
|
|
969
990
|
if (v <= 0) return 1;
|
|
@@ -982,9 +1003,42 @@ function isoDate(d) {
|
|
|
982
1003
|
const day = String(d.getDate()).padStart(2, "0");
|
|
983
1004
|
return `${d.getFullYear()}-${m}-${day}`;
|
|
984
1005
|
}
|
|
985
|
-
function
|
|
986
|
-
|
|
987
|
-
|
|
1006
|
+
function weekdayLabelAt(defaults, day) {
|
|
1007
|
+
return defaults[(day + 6) % 7] ?? "";
|
|
1008
|
+
}
|
|
1009
|
+
function levelOf(v, max) {
|
|
1010
|
+
return v <= 0 ? 0 : Math.min(4, Math.ceil(v / max * 4));
|
|
1011
|
+
}
|
|
1012
|
+
function padFirstWeek(grid, firstDate, weekStart) {
|
|
1013
|
+
const first = /* @__PURE__ */ new Date(`${firstDate}T00:00:00`);
|
|
1014
|
+
const pad = (first.getDay() + 7 - weekStart) % 7;
|
|
1015
|
+
for (let i = 0; i < pad; i++) {
|
|
1016
|
+
const blank = document.createElement("span");
|
|
1017
|
+
blank.className = "chart-heatmap-cell is-blank";
|
|
1018
|
+
grid.appendChild(blank);
|
|
1019
|
+
}
|
|
1020
|
+
return pad;
|
|
1021
|
+
}
|
|
1022
|
+
function heatmapLegend(labels) {
|
|
1023
|
+
const legend = document.createElement("div");
|
|
1024
|
+
legend.className = "chart-heatmap-legend";
|
|
1025
|
+
const less = document.createElement("span");
|
|
1026
|
+
less.textContent = labels?.less ?? "\u5C11";
|
|
1027
|
+
const more = document.createElement("span");
|
|
1028
|
+
more.textContent = labels?.more ?? "\u591A";
|
|
1029
|
+
legend.appendChild(less);
|
|
1030
|
+
for (let lv = 0; lv <= 4; lv++) {
|
|
1031
|
+
const cell = document.createElement("span");
|
|
1032
|
+
cell.className = "chart-heatmap-cell";
|
|
1033
|
+
cell.dataset.level = String(lv);
|
|
1034
|
+
legend.appendChild(cell);
|
|
1035
|
+
}
|
|
1036
|
+
legend.appendChild(more);
|
|
1037
|
+
return legend;
|
|
1038
|
+
}
|
|
1039
|
+
function renderHeatmap(el, opts) {
|
|
1040
|
+
if (typeof document === "undefined") return el;
|
|
1041
|
+
withChrome(el, opts, true, (body) => {
|
|
988
1042
|
let entries;
|
|
989
1043
|
if (opts.data && opts.data.length > 0) {
|
|
990
1044
|
entries = opts.data;
|
|
@@ -1002,49 +1056,30 @@ function renderHeatmap(el2, opts) {
|
|
|
1002
1056
|
const weeks = opts.weeks ?? Math.ceil(entries.length / 7);
|
|
1003
1057
|
if (entries.length > weeks * 7) entries = entries.slice(entries.length - weeks * 7);
|
|
1004
1058
|
const max = maxOf(entries.map((e) => e.value));
|
|
1005
|
-
const levelOf = (v) => v <= 0 ? 0 : Math.min(4, Math.ceil(v / max * 4));
|
|
1006
1059
|
const wrap = document.createElement("div");
|
|
1007
1060
|
wrap.className = "chart-heatmap";
|
|
1008
1061
|
if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
|
|
1009
1062
|
const grid = document.createElement("div");
|
|
1010
1063
|
grid.className = "chart-heatmap-grid";
|
|
1011
1064
|
grid.setAttribute("role", "img");
|
|
1012
|
-
|
|
1013
|
-
const
|
|
1014
|
-
for (let i = 0; i < pad; i++) {
|
|
1015
|
-
const blank = document.createElement("span");
|
|
1016
|
-
blank.className = "chart-heatmap-cell is-blank";
|
|
1017
|
-
grid.appendChild(blank);
|
|
1018
|
-
}
|
|
1019
|
-
for (const entry of entries) {
|
|
1065
|
+
padFirstWeek(grid, entries[0].date, opts.weekStart === 0 ? 0 : 1);
|
|
1066
|
+
for (const [i, entry] of entries.entries()) {
|
|
1020
1067
|
const cell = document.createElement("span");
|
|
1021
1068
|
cell.className = "chart-heatmap-cell";
|
|
1022
|
-
cell.dataset.level = String(levelOf(entry.value));
|
|
1069
|
+
cell.dataset.level = String(levelOf(entry.value, max));
|
|
1023
1070
|
cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
|
|
1024
|
-
setMarkData(cell, { index:
|
|
1071
|
+
setMarkData(cell, { index: i, label: entry.date, value: entry.value });
|
|
1025
1072
|
grid.appendChild(cell);
|
|
1026
1073
|
}
|
|
1027
|
-
|
|
1028
|
-
legend.className = "chart-heatmap-legend";
|
|
1029
|
-
const less = document.createElement("span");
|
|
1030
|
-
less.textContent = "\u5C11";
|
|
1031
|
-
const more = document.createElement("span");
|
|
1032
|
-
more.textContent = "\u591A";
|
|
1033
|
-
legend.appendChild(less);
|
|
1034
|
-
for (let lv = 0; lv <= 4; lv++) {
|
|
1035
|
-
const cell = document.createElement("span");
|
|
1036
|
-
cell.className = "chart-heatmap-cell";
|
|
1037
|
-
cell.dataset.level = String(lv);
|
|
1038
|
-
legend.appendChild(cell);
|
|
1039
|
-
}
|
|
1040
|
-
legend.appendChild(more);
|
|
1041
|
-
wrap.append(grid, legend);
|
|
1074
|
+
wrap.append(grid, heatmapLegend(opts.labels));
|
|
1042
1075
|
body.appendChild(wrap);
|
|
1043
1076
|
});
|
|
1077
|
+
attachChartInteraction(el, "heatmap");
|
|
1078
|
+
return el;
|
|
1044
1079
|
}
|
|
1045
|
-
function renderSparkline(
|
|
1046
|
-
if (typeof document === "undefined") return;
|
|
1047
|
-
withChrome(
|
|
1080
|
+
function renderSparkline(el, opts) {
|
|
1081
|
+
if (typeof document === "undefined") return el;
|
|
1082
|
+
withChrome(el, opts, false, (body) => {
|
|
1048
1083
|
const values = opts.values;
|
|
1049
1084
|
if (values.length === 0) {
|
|
1050
1085
|
renderEmpty(body, opts.emptyLabel);
|
|
@@ -1098,10 +1133,12 @@ function renderSparkline(el2, opts) {
|
|
|
1098
1133
|
wrap.appendChild(svg2);
|
|
1099
1134
|
body.appendChild(wrap);
|
|
1100
1135
|
});
|
|
1136
|
+
attachChartInteraction(el, "sparkline");
|
|
1137
|
+
return el;
|
|
1101
1138
|
}
|
|
1102
|
-
function renderGauge(
|
|
1103
|
-
if (typeof document === "undefined") return;
|
|
1104
|
-
|
|
1139
|
+
function renderGauge(el, opts) {
|
|
1140
|
+
if (typeof document === "undefined") return el;
|
|
1141
|
+
el.textContent = "";
|
|
1105
1142
|
const max = opts.max ?? 100;
|
|
1106
1143
|
const ratio = max > 0 ? Math.min(1, Math.max(0, opts.value / max)) : 0;
|
|
1107
1144
|
const radius = 42;
|
|
@@ -1143,11 +1180,13 @@ function renderGauge(el2, opts) {
|
|
|
1143
1180
|
center.appendChild(lab);
|
|
1144
1181
|
}
|
|
1145
1182
|
wrap.append(svg2, center);
|
|
1146
|
-
|
|
1183
|
+
el.appendChild(wrap);
|
|
1184
|
+
attachChartInteraction(el, "gauge");
|
|
1185
|
+
return el;
|
|
1147
1186
|
}
|
|
1148
|
-
function renderCalendar(
|
|
1149
|
-
if (typeof document === "undefined") return;
|
|
1150
|
-
withChrome(
|
|
1187
|
+
function renderCalendar(el, opts) {
|
|
1188
|
+
if (typeof document === "undefined") return el;
|
|
1189
|
+
withChrome(el, opts, true, (body) => {
|
|
1151
1190
|
let entries;
|
|
1152
1191
|
if (opts.data && opts.data.length > 0) {
|
|
1153
1192
|
entries = opts.data;
|
|
@@ -1160,6 +1199,10 @@ function renderCalendar(el2, opts) {
|
|
|
1160
1199
|
const wrap = document.createElement("div");
|
|
1161
1200
|
wrap.className = "chart-calendar";
|
|
1162
1201
|
if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
|
|
1202
|
+
const weekStart = opts.weekStart === 0 ? 0 : 1;
|
|
1203
|
+
const weekdayDefaults = ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"];
|
|
1204
|
+
const weekdayLabels = opts.labels?.weekdays ?? weekdayDefaults.map((_, i) => weekdayLabelAt(weekdayDefaults, (weekStart + i) % 7));
|
|
1205
|
+
const monthLabel = (m) => opts.labels?.months?.[m] ?? `${m + 1}\u6708`;
|
|
1163
1206
|
const grid = document.createElement("div");
|
|
1164
1207
|
grid.className = "chart-heatmap-grid";
|
|
1165
1208
|
grid.setAttribute("role", "img");
|
|
@@ -1167,20 +1210,13 @@ function renderCalendar(el2, opts) {
|
|
|
1167
1210
|
months.className = "chart-calendar-months";
|
|
1168
1211
|
const weekdayRow = document.createElement("div");
|
|
1169
1212
|
weekdayRow.className = "chart-calendar-weekdays";
|
|
1170
|
-
|
|
1213
|
+
weekdayLabels.forEach((w) => {
|
|
1171
1214
|
const s = document.createElement("span");
|
|
1172
1215
|
s.textContent = w;
|
|
1173
1216
|
weekdayRow.appendChild(s);
|
|
1174
1217
|
});
|
|
1175
1218
|
const max = maxOf(entries.map((e) => e.value));
|
|
1176
|
-
const
|
|
1177
|
-
const first = /* @__PURE__ */ new Date(`${entries[0].date}T00:00:00`);
|
|
1178
|
-
const pad = (first.getDay() + 6) % 7;
|
|
1179
|
-
for (let i = 0; i < pad; i++) {
|
|
1180
|
-
const blank = document.createElement("span");
|
|
1181
|
-
blank.className = "chart-heatmap-cell is-blank";
|
|
1182
|
-
grid.appendChild(blank);
|
|
1183
|
-
}
|
|
1219
|
+
const pad = padFirstWeek(grid, entries[0].date, weekStart);
|
|
1184
1220
|
let lastMonth = -1;
|
|
1185
1221
|
entries.forEach((entry, i) => {
|
|
1186
1222
|
const d = /* @__PURE__ */ new Date(`${entry.date}T00:00:00`);
|
|
@@ -1189,40 +1225,29 @@ function renderCalendar(el2, opts) {
|
|
|
1189
1225
|
lastMonth = d.getMonth();
|
|
1190
1226
|
const label = document.createElement("span");
|
|
1191
1227
|
label.className = "chart-calendar-month";
|
|
1192
|
-
label.textContent =
|
|
1228
|
+
label.textContent = monthLabel(d.getMonth());
|
|
1193
1229
|
label.style.setProperty("--col", String(col));
|
|
1194
1230
|
months.appendChild(label);
|
|
1195
1231
|
}
|
|
1196
1232
|
const cell = document.createElement("span");
|
|
1197
1233
|
cell.className = "chart-heatmap-cell";
|
|
1198
|
-
cell.dataset.level = String(levelOf(entry.value));
|
|
1234
|
+
cell.dataset.level = String(levelOf(entry.value, max));
|
|
1199
1235
|
cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
|
|
1200
1236
|
setMarkData(cell, { index: i, label: entry.date, value: entry.value });
|
|
1201
1237
|
grid.appendChild(cell);
|
|
1202
1238
|
});
|
|
1203
|
-
const legend =
|
|
1204
|
-
legend.className = "chart-heatmap-legend";
|
|
1205
|
-
const less = document.createElement("span");
|
|
1206
|
-
less.textContent = "\u5C11";
|
|
1207
|
-
const more = document.createElement("span");
|
|
1208
|
-
more.textContent = "\u591A";
|
|
1209
|
-
legend.appendChild(less);
|
|
1210
|
-
for (let lv = 0; lv <= 4; lv++) {
|
|
1211
|
-
const cell = document.createElement("span");
|
|
1212
|
-
cell.className = "chart-heatmap-cell";
|
|
1213
|
-
cell.dataset.level = String(lv);
|
|
1214
|
-
legend.appendChild(cell);
|
|
1215
|
-
}
|
|
1216
|
-
legend.appendChild(more);
|
|
1239
|
+
const legend = heatmapLegend(opts.labels);
|
|
1217
1240
|
const columns = Math.max(1, Math.ceil((pad + entries.length) / 7));
|
|
1218
1241
|
months.style.setProperty("--columns", String(columns));
|
|
1219
1242
|
wrap.append(months, weekdayRow, grid, legend);
|
|
1220
1243
|
body.appendChild(wrap);
|
|
1221
1244
|
});
|
|
1245
|
+
attachChartInteraction(el, "calendar");
|
|
1246
|
+
return el;
|
|
1222
1247
|
}
|
|
1223
|
-
function renderScatter(
|
|
1224
|
-
if (typeof document === "undefined") return;
|
|
1225
|
-
withChrome(
|
|
1248
|
+
function renderScatter(el, opts) {
|
|
1249
|
+
if (typeof document === "undefined") return el;
|
|
1250
|
+
withChrome(el, opts, false, (body) => {
|
|
1226
1251
|
const pts = opts.points.filter((p) => Number.isFinite(p.x) && Number.isFinite(p.y));
|
|
1227
1252
|
if (pts.length === 0) {
|
|
1228
1253
|
renderEmpty(body, opts.emptyLabel);
|
|
@@ -1266,7 +1291,7 @@ function renderScatter(el2, opts) {
|
|
|
1266
1291
|
"font-size": "8",
|
|
1267
1292
|
fill: "var(--token-text-faint)"
|
|
1268
1293
|
});
|
|
1269
|
-
txt.textContent =
|
|
1294
|
+
txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
|
|
1270
1295
|
svg2.appendChild(txt);
|
|
1271
1296
|
}
|
|
1272
1297
|
for (let i = 0; i <= 4; i++) {
|
|
@@ -1288,7 +1313,7 @@ function renderScatter(el2, opts) {
|
|
|
1288
1313
|
"font-size": "8",
|
|
1289
1314
|
fill: "var(--token-text-faint)"
|
|
1290
1315
|
});
|
|
1291
|
-
txt.textContent =
|
|
1316
|
+
txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
|
|
1292
1317
|
svg2.appendChild(txt);
|
|
1293
1318
|
}
|
|
1294
1319
|
if (opts.yLabel) {
|
|
@@ -1312,7 +1337,7 @@ function renderScatter(el2, opts) {
|
|
|
1312
1337
|
"stroke-width": "1"
|
|
1313
1338
|
});
|
|
1314
1339
|
const title = svgEl("title", {});
|
|
1315
|
-
title.textContent = `${p.label ?? `#${i + 1}`}: (${p.x}, ${p.y}${p.size != null ? `, size ${p.size}` : ""})`;
|
|
1340
|
+
title.textContent = `${p.label ?? `#${i + 1}`}: (${fmt(opts, p.x)}, ${fmt(opts, p.y)}${p.size != null ? `, size ${fmt(opts, p.size)}` : ""})`;
|
|
1316
1341
|
c.appendChild(title);
|
|
1317
1342
|
setMarkData(c, { index: i, label: p.label ?? `#${i + 1}`, value: p.y });
|
|
1318
1343
|
c.dataset.chartX = String(p.x);
|
|
@@ -1321,6 +1346,8 @@ function renderScatter(el2, opts) {
|
|
|
1321
1346
|
wrap.appendChild(svg2);
|
|
1322
1347
|
body.appendChild(wrap);
|
|
1323
1348
|
});
|
|
1349
|
+
attachChartInteraction(el, "scatter");
|
|
1350
|
+
return el;
|
|
1324
1351
|
}
|
|
1325
1352
|
function chartFormatValue(format) {
|
|
1326
1353
|
if (!format) return (v) => String(v);
|
|
@@ -1451,7 +1478,7 @@ function normalizeChartSpec(raw) {
|
|
|
1451
1478
|
}
|
|
1452
1479
|
}
|
|
1453
1480
|
if (!src || typeof src !== "object" || Array.isArray(src)) {
|
|
1454
|
-
if (Array.isArray(
|
|
1481
|
+
if (Array.isArray(src)) src = { data: src };
|
|
1455
1482
|
else return {};
|
|
1456
1483
|
}
|
|
1457
1484
|
const s = src;
|
|
@@ -1521,6 +1548,7 @@ function normalizeChartSpec(raw) {
|
|
|
1521
1548
|
}
|
|
1522
1549
|
return spec;
|
|
1523
1550
|
}
|
|
1551
|
+
var TEMPORAL_HIT_RATIO = 0.6;
|
|
1524
1552
|
function looksTemporal(labels) {
|
|
1525
1553
|
if (labels.length === 0) return false;
|
|
1526
1554
|
let hits = 0;
|
|
@@ -1534,7 +1562,7 @@ function looksTemporal(labels) {
|
|
|
1534
1562
|
else if (/^(v|ver\.?|version[ .]?)?\d+(\.\d+)+$/i.test(l)) hits++;
|
|
1535
1563
|
else if (/^\d{4}$/.test(l)) hits++;
|
|
1536
1564
|
}
|
|
1537
|
-
return hits / labels.length >=
|
|
1565
|
+
return hits / labels.length >= TEMPORAL_HIT_RATIO;
|
|
1538
1566
|
}
|
|
1539
1567
|
function inferChartType(spec) {
|
|
1540
1568
|
if (spec.points && spec.points.length > 0) return "scatter";
|
|
@@ -1569,7 +1597,7 @@ function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
|
|
|
1569
1597
|
pointerX: pointer?.x,
|
|
1570
1598
|
pointerY: pointer?.y
|
|
1571
1599
|
};
|
|
1572
|
-
root
|
|
1600
|
+
emitIcen(root, `icen:chart-${type}`, detail);
|
|
1573
1601
|
}
|
|
1574
1602
|
var tooltipEl = null;
|
|
1575
1603
|
function chartTooltip() {
|
|
@@ -1582,6 +1610,12 @@ function chartTooltip() {
|
|
|
1582
1610
|
}
|
|
1583
1611
|
return tooltipEl;
|
|
1584
1612
|
}
|
|
1613
|
+
function applyTooltipSizing(host) {
|
|
1614
|
+
const tip = chartTooltip();
|
|
1615
|
+
const raw = host?.closest(".chart, [data-chart-root]")?.getAttribute("data-panel-max") ?? null;
|
|
1616
|
+
const n = raw != null ? Number(raw) : NaN;
|
|
1617
|
+
tip.style.maxWidth = Number.isFinite(n) && n > 0 ? `${n}px` : "";
|
|
1618
|
+
}
|
|
1585
1619
|
function tooltipText(mark) {
|
|
1586
1620
|
const label = mark.getAttribute("data-chart-label") ?? "";
|
|
1587
1621
|
const series = mark.getAttribute("data-chart-series-name");
|
|
@@ -1601,6 +1635,101 @@ function moveTooltip(x, y) {
|
|
|
1601
1635
|
tip.style.left = `${Math.round(left)}px`;
|
|
1602
1636
|
tip.style.top = `${Math.round(top)}px`;
|
|
1603
1637
|
}
|
|
1638
|
+
var chartDelegateMeta = /* @__PURE__ */ new WeakMap();
|
|
1639
|
+
var chartDelegateUnbind = /* @__PURE__ */ new WeakMap();
|
|
1640
|
+
function bindChartEvents(root) {
|
|
1641
|
+
const noop = () => void 0;
|
|
1642
|
+
if (typeof document === "undefined") return noop;
|
|
1643
|
+
const attached = root;
|
|
1644
|
+
if (attached.__icenChartBound) {
|
|
1645
|
+
const prev = chartDelegateUnbind.get(root);
|
|
1646
|
+
if (prev) return prev;
|
|
1647
|
+
}
|
|
1648
|
+
for (let p = root.parentElement; p; p = p.parentElement) {
|
|
1649
|
+
if (p.__icenChartBound) return noop;
|
|
1650
|
+
}
|
|
1651
|
+
const typeNow = () => chartDelegateMeta.get(root)?.type() ?? "vbar";
|
|
1652
|
+
const tipEnabled = () => chartDelegateMeta.get(root)?.tooltip() ?? true;
|
|
1653
|
+
const markOf = (e) => {
|
|
1654
|
+
const t = e.target;
|
|
1655
|
+
return t instanceof Element ? t.closest("[data-chart-mark]") : null;
|
|
1656
|
+
};
|
|
1657
|
+
let hoverMark = null;
|
|
1658
|
+
const enterMark = (mark, x, y) => {
|
|
1659
|
+
hoverMark = mark;
|
|
1660
|
+
mark.classList.add("is-hover");
|
|
1661
|
+
dispatchChartEvent(root, "hover", mark, typeNow(), "enter", { x, y });
|
|
1662
|
+
if (tipEnabled()) {
|
|
1663
|
+
const tip = chartTooltip();
|
|
1664
|
+
tip.textContent = tooltipText(mark);
|
|
1665
|
+
applyTooltipSizing(mark);
|
|
1666
|
+
tip.hidden = false;
|
|
1667
|
+
moveTooltip(x, y);
|
|
1668
|
+
}
|
|
1669
|
+
};
|
|
1670
|
+
const leaveMark = (pointer) => {
|
|
1671
|
+
if (!hoverMark) return;
|
|
1672
|
+
hoverMark.classList.remove("is-hover");
|
|
1673
|
+
dispatchChartEvent(root, "hover", hoverMark, typeNow(), "leave", pointer);
|
|
1674
|
+
hoverMark = null;
|
|
1675
|
+
chartTooltip().hidden = true;
|
|
1676
|
+
};
|
|
1677
|
+
const bindings = [];
|
|
1678
|
+
const on = (type, fn) => {
|
|
1679
|
+
const listener = (evt) => fn(evt);
|
|
1680
|
+
root.addEventListener(type, listener);
|
|
1681
|
+
bindings.push([type, listener]);
|
|
1682
|
+
};
|
|
1683
|
+
on("pointerover", (e) => {
|
|
1684
|
+
const mark = markOf(e);
|
|
1685
|
+
if (!mark || mark === hoverMark) return;
|
|
1686
|
+
leaveMark({ x: e.clientX, y: e.clientY });
|
|
1687
|
+
enterMark(mark, e.clientX, e.clientY);
|
|
1688
|
+
});
|
|
1689
|
+
on("pointermove", (e) => {
|
|
1690
|
+
if (hoverMark && tipEnabled()) {
|
|
1691
|
+
dispatchChartEvent(root, "hover", hoverMark, typeNow(), "move", { x: e.clientX, y: e.clientY });
|
|
1692
|
+
moveTooltip(e.clientX, e.clientY);
|
|
1693
|
+
}
|
|
1694
|
+
});
|
|
1695
|
+
on("pointerout", (e) => {
|
|
1696
|
+
const mark = markOf(e);
|
|
1697
|
+
if (mark && mark === hoverMark) leaveMark({ x: e.clientX, y: e.clientY });
|
|
1698
|
+
});
|
|
1699
|
+
on("pointerleave", () => leaveMark());
|
|
1700
|
+
on("click", (e) => {
|
|
1701
|
+
const mark = markOf(e);
|
|
1702
|
+
if (mark) dispatchChartEvent(root, "click", mark, typeNow(), void 0, { x: e.clientX, y: e.clientY });
|
|
1703
|
+
});
|
|
1704
|
+
on("dblclick", (e) => {
|
|
1705
|
+
const mark = markOf(e);
|
|
1706
|
+
if (mark) dispatchChartEvent(root, "dblclick", mark, typeNow(), void 0, { x: e.clientX, y: e.clientY });
|
|
1707
|
+
});
|
|
1708
|
+
on("contextmenu", (e) => {
|
|
1709
|
+
const mark = markOf(e);
|
|
1710
|
+
if (!mark) return;
|
|
1711
|
+
e.preventDefault();
|
|
1712
|
+
dispatchChartEvent(root, "contextmenu", mark, typeNow(), void 0, { x: e.clientX, y: e.clientY });
|
|
1713
|
+
});
|
|
1714
|
+
const unbind = () => {
|
|
1715
|
+
for (const [type, listener] of bindings) root.removeEventListener(type, listener);
|
|
1716
|
+
bindings.length = 0;
|
|
1717
|
+
attached.__icenChartBound = false;
|
|
1718
|
+
chartDelegateUnbind.delete(root);
|
|
1719
|
+
if (hoverMark) {
|
|
1720
|
+
hoverMark.classList.remove("is-hover");
|
|
1721
|
+
hoverMark = null;
|
|
1722
|
+
}
|
|
1723
|
+
chartTooltip().hidden = true;
|
|
1724
|
+
};
|
|
1725
|
+
attached.__icenChartBound = true;
|
|
1726
|
+
chartDelegateUnbind.set(root, unbind);
|
|
1727
|
+
return unbind;
|
|
1728
|
+
}
|
|
1729
|
+
function attachChartInteraction(el, type) {
|
|
1730
|
+
chartDelegateMeta.set(el, { type: () => type, tooltip: () => true });
|
|
1731
|
+
bindChartEvents(el);
|
|
1732
|
+
}
|
|
1604
1733
|
function hasLegendOf(spec) {
|
|
1605
1734
|
switch (spec.type) {
|
|
1606
1735
|
case "donut":
|
|
@@ -1617,15 +1746,12 @@ function hasLegendOf(spec) {
|
|
|
1617
1746
|
return false;
|
|
1618
1747
|
}
|
|
1619
1748
|
}
|
|
1620
|
-
function renderChart(
|
|
1749
|
+
function renderChart(el, raw) {
|
|
1621
1750
|
const noop = () => void 0;
|
|
1622
1751
|
if (typeof document === "undefined") {
|
|
1623
|
-
return { el
|
|
1752
|
+
return { el, spec: {}, update: noop, on: () => noop, destroy: noop };
|
|
1624
1753
|
}
|
|
1625
|
-
const root =
|
|
1626
|
-
const attached = root;
|
|
1627
|
-
const wasBound = attached.__icenChartBound === true;
|
|
1628
|
-
attached.__icenChartBound = true;
|
|
1754
|
+
const root = el;
|
|
1629
1755
|
let current = normalizeChartSpec(raw);
|
|
1630
1756
|
const typeOf = () => current.type ?? "vbar";
|
|
1631
1757
|
const legendState = { hidden: null };
|
|
@@ -1660,10 +1786,10 @@ function renderChart(el2, raw) {
|
|
|
1660
1786
|
break;
|
|
1661
1787
|
}
|
|
1662
1788
|
case "heatmap":
|
|
1663
|
-
renderHeatmap(body, { values: spec.values, data: spec.data, weeks: spec.weeks, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
|
|
1789
|
+
renderHeatmap(body, { values: spec.values, data: spec.data, weeks: spec.weeks, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend, weekStart: spec.i18n?.weekStart, labels: spec.i18n });
|
|
1664
1790
|
break;
|
|
1665
1791
|
case "calendar":
|
|
1666
|
-
renderCalendar(body, { dates: spec.dates, values: spec.values, data: spec.data, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
|
|
1792
|
+
renderCalendar(body, { dates: spec.dates, values: spec.values, data: spec.data, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend, weekStart: spec.i18n?.weekStart, labels: spec.i18n });
|
|
1667
1793
|
break;
|
|
1668
1794
|
case "sparkline":
|
|
1669
1795
|
renderSparkline(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
|
|
@@ -1679,63 +1805,8 @@ function renderChart(el2, raw) {
|
|
|
1679
1805
|
}
|
|
1680
1806
|
});
|
|
1681
1807
|
};
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
const t = e.target;
|
|
1685
|
-
return t instanceof Element ? t.closest("[data-chart-mark]") : null;
|
|
1686
|
-
};
|
|
1687
|
-
const tipEnabled = () => current.tooltip !== false;
|
|
1688
|
-
let hoverMark = null;
|
|
1689
|
-
const enterMark = (mark, x, y) => {
|
|
1690
|
-
hoverMark = mark;
|
|
1691
|
-
mark.classList.add("is-hover");
|
|
1692
|
-
dispatchChartEvent(root, "hover", mark, typeOf(), "enter", { x, y });
|
|
1693
|
-
if (tipEnabled()) {
|
|
1694
|
-
const tip = chartTooltip();
|
|
1695
|
-
tip.textContent = tooltipText(mark);
|
|
1696
|
-
tip.hidden = false;
|
|
1697
|
-
moveTooltip(x, y);
|
|
1698
|
-
}
|
|
1699
|
-
};
|
|
1700
|
-
const leaveMark = (pointer) => {
|
|
1701
|
-
if (!hoverMark) return;
|
|
1702
|
-
hoverMark.classList.remove("is-hover");
|
|
1703
|
-
dispatchChartEvent(root, "hover", hoverMark, typeOf(), "leave", pointer);
|
|
1704
|
-
hoverMark = null;
|
|
1705
|
-
chartTooltip().hidden = true;
|
|
1706
|
-
};
|
|
1707
|
-
root.addEventListener("pointerover", (e) => {
|
|
1708
|
-
const mark = markOf(e);
|
|
1709
|
-
if (!mark || mark === hoverMark) return;
|
|
1710
|
-
leaveMark({ x: e.clientX, y: e.clientY });
|
|
1711
|
-
enterMark(mark, e.clientX, e.clientY);
|
|
1712
|
-
});
|
|
1713
|
-
root.addEventListener("pointermove", (e) => {
|
|
1714
|
-
if (hoverMark && tipEnabled()) {
|
|
1715
|
-
dispatchChartEvent(root, "hover", hoverMark, typeOf(), "move", { x: e.clientX, y: e.clientY });
|
|
1716
|
-
moveTooltip(e.clientX, e.clientY);
|
|
1717
|
-
}
|
|
1718
|
-
});
|
|
1719
|
-
root.addEventListener("pointerout", (e) => {
|
|
1720
|
-
const mark = markOf(e);
|
|
1721
|
-
if (mark && mark === hoverMark) leaveMark({ x: e.clientX, y: e.clientY });
|
|
1722
|
-
});
|
|
1723
|
-
root.addEventListener("pointerleave", () => leaveMark());
|
|
1724
|
-
root.addEventListener("click", (e) => {
|
|
1725
|
-
const mark = markOf(e);
|
|
1726
|
-
if (mark) dispatchChartEvent(root, "click", mark, typeOf(), void 0, { x: e.clientX, y: e.clientY });
|
|
1727
|
-
});
|
|
1728
|
-
root.addEventListener("dblclick", (e) => {
|
|
1729
|
-
const mark = markOf(e);
|
|
1730
|
-
if (mark) dispatchChartEvent(root, "dblclick", mark, typeOf(), void 0, { x: e.clientX, y: e.clientY });
|
|
1731
|
-
});
|
|
1732
|
-
root.addEventListener("contextmenu", (e) => {
|
|
1733
|
-
const mark = markOf(e);
|
|
1734
|
-
if (!mark) return;
|
|
1735
|
-
e.preventDefault();
|
|
1736
|
-
dispatchChartEvent(root, "contextmenu", mark, typeOf(), void 0, { x: e.clientX, y: e.clientY });
|
|
1737
|
-
});
|
|
1738
|
-
}
|
|
1808
|
+
chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current.tooltip !== false });
|
|
1809
|
+
const unbindEvents = bindChartEvents(root);
|
|
1739
1810
|
render();
|
|
1740
1811
|
return {
|
|
1741
1812
|
el: root,
|
|
@@ -1753,28 +1824,18 @@ function renderChart(el2, raw) {
|
|
|
1753
1824
|
},
|
|
1754
1825
|
destroy() {
|
|
1755
1826
|
root.textContent = "";
|
|
1756
|
-
|
|
1827
|
+
unbindEvents();
|
|
1757
1828
|
chartTooltip().hidden = true;
|
|
1758
1829
|
}
|
|
1759
1830
|
};
|
|
1760
1831
|
}
|
|
1832
|
+
var GRAPH_W = 360;
|
|
1833
|
+
var GRAPH_H = 260;
|
|
1834
|
+
var GRAPH_PAD = 28;
|
|
1835
|
+
var GRAPH_LW = GRAPH_W - GRAPH_PAD * 2;
|
|
1836
|
+
var GRAPH_LH = GRAPH_H - GRAPH_PAD * 2;
|
|
1761
1837
|
|
|
1762
1838
|
// src/behaviors/ai-tool.ts
|
|
1763
|
-
var AI_STATUSES = [
|
|
1764
|
-
"pending",
|
|
1765
|
-
"running",
|
|
1766
|
-
"streaming",
|
|
1767
|
-
"approval",
|
|
1768
|
-
"done",
|
|
1769
|
-
"error",
|
|
1770
|
-
"cancelled"
|
|
1771
|
-
];
|
|
1772
|
-
function h(tag, className, text) {
|
|
1773
|
-
const node = document.createElement(tag);
|
|
1774
|
-
if (className) node.className = className;
|
|
1775
|
-
if (text != null) node.textContent = text;
|
|
1776
|
-
return node;
|
|
1777
|
-
}
|
|
1778
1839
|
function setStatusClass(item, status) {
|
|
1779
1840
|
for (const s of AI_STATUSES) item.classList.toggle(`is-${s}`, s === status);
|
|
1780
1841
|
}
|
|
@@ -1921,11 +1982,11 @@ function applyStatusMeta(parts, status, meta) {
|
|
|
1921
1982
|
parts.metaEl.textContent = meta;
|
|
1922
1983
|
parts.metaEl.hidden = !meta;
|
|
1923
1984
|
}
|
|
1924
|
-
function renderAiToolCall(
|
|
1985
|
+
function renderAiToolCall(el, model) {
|
|
1925
1986
|
if (typeof document === "undefined") {
|
|
1926
|
-
return { el
|
|
1987
|
+
return { el, update: () => void 0 };
|
|
1927
1988
|
}
|
|
1928
|
-
const item =
|
|
1989
|
+
const item = el;
|
|
1929
1990
|
let current = model;
|
|
1930
1991
|
item.className = `ai-tool ai-tool--${model.kind}`;
|
|
1931
1992
|
item.dataset.aiId = model.id;
|
|
@@ -1942,12 +2003,9 @@ function renderAiToolCall(el2, model) {
|
|
|
1942
2003
|
parts.head.setAttribute("aria-expanded", String(open));
|
|
1943
2004
|
body.hidden = !open;
|
|
1944
2005
|
if (fire) {
|
|
1945
|
-
item
|
|
1946
|
-
new CustomEvent("icen:ai-toggle", { detail: { el: item, open }, bubbles: true })
|
|
1947
|
-
);
|
|
2006
|
+
emitIcen(item, "icen:ai-toggle", { el: item, open });
|
|
1948
2007
|
}
|
|
1949
2008
|
};
|
|
1950
|
-
let prevStatus = null;
|
|
1951
2009
|
const apply = (m) => {
|
|
1952
2010
|
setStatusClass(item, m.status);
|
|
1953
2011
|
applyTint(item, m);
|
|
@@ -1960,7 +2018,6 @@ function renderAiToolCall(el2, model) {
|
|
|
1960
2018
|
approval.reason.textContent = reason;
|
|
1961
2019
|
approval.reason.hidden = !reason;
|
|
1962
2020
|
if (!item.dataset.aiUserToggled && defaultExpanded(m)) setOpen(true);
|
|
1963
|
-
prevStatus = m.status;
|
|
1964
2021
|
};
|
|
1965
2022
|
apply(current);
|
|
1966
2023
|
return {
|
|
@@ -1971,11 +2028,11 @@ function renderAiToolCall(el2, model) {
|
|
|
1971
2028
|
}
|
|
1972
2029
|
};
|
|
1973
2030
|
}
|
|
1974
|
-
function renderAiSubagent(
|
|
2031
|
+
function renderAiSubagent(el, model) {
|
|
1975
2032
|
if (typeof document === "undefined") {
|
|
1976
|
-
return { el
|
|
2033
|
+
return { el, update: () => void 0 };
|
|
1977
2034
|
}
|
|
1978
|
-
const item =
|
|
2035
|
+
const item = el;
|
|
1979
2036
|
let current = model;
|
|
1980
2037
|
item.className = "ai-subagent";
|
|
1981
2038
|
item.dataset.aiId = model.id;
|
|
@@ -1992,9 +2049,7 @@ function renderAiSubagent(el2, model) {
|
|
|
1992
2049
|
parts.head.setAttribute("aria-expanded", String(open));
|
|
1993
2050
|
body.hidden = !open;
|
|
1994
2051
|
if (fire) {
|
|
1995
|
-
item
|
|
1996
|
-
new CustomEvent("icen:ai-toggle", { detail: { el: item, open }, bubbles: true })
|
|
1997
|
-
);
|
|
2052
|
+
emitIcen(item, "icen:ai-toggle", { el: item, open });
|
|
1998
2053
|
}
|
|
1999
2054
|
};
|
|
2000
2055
|
const activityHandles = /* @__PURE__ */ new Map();
|
|
@@ -2021,7 +2076,6 @@ function renderAiSubagent(el2, model) {
|
|
|
2021
2076
|
}
|
|
2022
2077
|
}
|
|
2023
2078
|
};
|
|
2024
|
-
let prevStatus = null;
|
|
2025
2079
|
const apply = (m) => {
|
|
2026
2080
|
setStatusClass(item, m.status);
|
|
2027
2081
|
applyTint(item, m);
|
|
@@ -2034,7 +2088,6 @@ function renderAiSubagent(el2, model) {
|
|
|
2034
2088
|
result.textContent = receipt;
|
|
2035
2089
|
result.hidden = !receipt;
|
|
2036
2090
|
if (!item.dataset.aiUserToggled && defaultExpanded(m)) setOpen(true);
|
|
2037
|
-
prevStatus = m.status;
|
|
2038
2091
|
};
|
|
2039
2092
|
apply(current);
|
|
2040
2093
|
return {
|
|
@@ -2048,7 +2101,7 @@ function renderAiSubagent(el2, model) {
|
|
|
2048
2101
|
function setupItem(item, kind) {
|
|
2049
2102
|
const marked = item;
|
|
2050
2103
|
const flag = kind === "tool" ? "__icenAiToolInit" : "__icenAiSubagentInit";
|
|
2051
|
-
if (marked[flag]) return;
|
|
2104
|
+
if (marked[flag]) return () => void 0;
|
|
2052
2105
|
marked[flag] = true;
|
|
2053
2106
|
const headClass = kind === "tool" ? ".ai-tool-head" : ".ai-subagent-head";
|
|
2054
2107
|
const bodyClass = kind === "tool" ? ".ai-tool-body" : ".ai-subagent-body";
|
|
@@ -2058,64 +2111,64 @@ function setupItem(item, kind) {
|
|
|
2058
2111
|
head?.setAttribute("aria-expanded", String(open));
|
|
2059
2112
|
if (body) body.hidden = !open;
|
|
2060
2113
|
if (fire) {
|
|
2061
|
-
item
|
|
2062
|
-
new CustomEvent("icen:ai-toggle", { detail: { el: item, open }, bubbles: true })
|
|
2063
|
-
);
|
|
2114
|
+
emitIcen(item, "icen:ai-toggle", { el: item, open });
|
|
2064
2115
|
}
|
|
2065
2116
|
};
|
|
2066
|
-
|
|
2117
|
+
const onCardClick = (ev) => {
|
|
2067
2118
|
const target = ev.target;
|
|
2068
2119
|
if (!(target instanceof Element)) return;
|
|
2069
2120
|
const ownerOf = (node) => node.closest(".ai-tool, .ai-subagent");
|
|
2070
2121
|
const approveBtn = target.closest("[data-ai-approve]");
|
|
2071
2122
|
if (approveBtn && ownerOf(approveBtn) === item) {
|
|
2072
|
-
item.
|
|
2073
|
-
new CustomEvent("icen:ai-approve", {
|
|
2074
|
-
detail: { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" },
|
|
2075
|
-
bubbles: true
|
|
2076
|
-
})
|
|
2077
|
-
);
|
|
2123
|
+
emitIcen(item, "icen:ai-approve", { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" });
|
|
2078
2124
|
return;
|
|
2079
2125
|
}
|
|
2080
2126
|
const rejectBtn = target.closest("[data-ai-reject]");
|
|
2081
2127
|
if (rejectBtn && ownerOf(rejectBtn) === item) {
|
|
2082
|
-
item.
|
|
2083
|
-
new CustomEvent("icen:ai-reject", {
|
|
2084
|
-
detail: { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" },
|
|
2085
|
-
bubbles: true
|
|
2086
|
-
})
|
|
2087
|
-
);
|
|
2128
|
+
emitIcen(item, "icen:ai-reject", { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" });
|
|
2088
2129
|
return;
|
|
2089
2130
|
}
|
|
2090
2131
|
const headEl = target.closest(".ai-tool-head, .ai-subagent-head");
|
|
2091
2132
|
if (!headEl || ownerOf(headEl) !== item || !head) return;
|
|
2092
2133
|
item.dataset.aiUserToggled = "1";
|
|
2093
2134
|
setOpen(head.getAttribute("aria-expanded") !== "true");
|
|
2094
|
-
}
|
|
2135
|
+
};
|
|
2136
|
+
item.addEventListener("click", onCardClick);
|
|
2095
2137
|
if (body?.hidden) {
|
|
2096
2138
|
const kindName = item.dataset.aiKind ?? "";
|
|
2097
2139
|
const isErr = item.classList.contains("is-error");
|
|
2098
2140
|
const isApproval = item.classList.contains("is-approval");
|
|
2099
2141
|
if (isErr || isApproval || kindName === "chart") {
|
|
2100
|
-
item.dataset.aiUserToggled = "";
|
|
2101
2142
|
setOpen(true, false);
|
|
2102
2143
|
delete item.dataset.aiUserToggled;
|
|
2103
2144
|
}
|
|
2104
2145
|
}
|
|
2146
|
+
return () => {
|
|
2147
|
+
item.removeEventListener("click", onCardClick);
|
|
2148
|
+
marked[flag] = false;
|
|
2149
|
+
};
|
|
2105
2150
|
}
|
|
2106
2151
|
function initItems(root, selector, kind) {
|
|
2107
|
-
if (typeof document === "undefined") return;
|
|
2152
|
+
if (typeof document === "undefined") return [];
|
|
2108
2153
|
const scope = root ?? document;
|
|
2109
2154
|
const items = [];
|
|
2110
2155
|
if (scope instanceof Element && scope.matches(selector)) items.push(scope);
|
|
2111
2156
|
items.push(...Array.from(scope.querySelectorAll(selector)));
|
|
2112
|
-
|
|
2157
|
+
return items.map((item) => setupItem(item, kind));
|
|
2113
2158
|
}
|
|
2114
2159
|
function initAiTool(root) {
|
|
2115
|
-
initItems(root, ".ai-tool", "tool");
|
|
2160
|
+
const cleanups = initItems(root, ".ai-tool", "tool");
|
|
2161
|
+
return () => {
|
|
2162
|
+
for (const fn of cleanups) fn();
|
|
2163
|
+
cleanups.length = 0;
|
|
2164
|
+
};
|
|
2116
2165
|
}
|
|
2117
2166
|
function initAiSubagent(root) {
|
|
2118
|
-
initItems(root, ".ai-subagent", "subagent");
|
|
2167
|
+
const cleanups = initItems(root, ".ai-subagent", "subagent");
|
|
2168
|
+
return () => {
|
|
2169
|
+
for (const fn of cleanups) fn();
|
|
2170
|
+
cleanups.length = 0;
|
|
2171
|
+
};
|
|
2119
2172
|
}
|
|
2120
2173
|
export {
|
|
2121
2174
|
initAiSubagent,
|