@cardenelabs/cdl 0.6.1 → 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.
Files changed (43) hide show
  1. package/CHANGELOG.md +401 -0
  2. package/SPEC.md +32 -17
  3. package/dist/index.cjs +820 -364
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +68 -14
  6. package/dist/index.d.ts +68 -14
  7. package/dist/index.js +820 -364
  8. package/dist/index.js.map +1 -1
  9. package/dist/react.cjs +692 -254
  10. package/dist/react.cjs.map +1 -1
  11. package/dist/react.d.cts +1 -1
  12. package/dist/react.d.ts +1 -1
  13. package/dist/react.js +692 -254
  14. package/dist/react.js.map +1 -1
  15. package/dist/{render-DquCvgOB.d.cts → render-hmFRAabt.d.cts} +33 -2
  16. package/dist/{render-DquCvgOB.d.ts → render-hmFRAabt.d.ts} +33 -2
  17. package/package.json +6 -3
  18. package/src/kinds/box-lines.ts +120 -0
  19. package/src/kinds/gantt.tsx +152 -24
  20. package/src/kinds/mind-map.tsx +77 -16
  21. package/src/kinds/quadrant.tsx +28 -2
  22. package/src/kinds/shape-blockchain.tsx +65 -12
  23. package/src/kinds/shape-region.tsx +152 -34
  24. package/src/kinds/tree.tsx +121 -24
  25. package/src/layout/collisions.ts +10 -2
  26. package/src/layout/footer-shape.ts +86 -24
  27. package/src/layout/lifeline.ts +80 -0
  28. package/src/layout/spec.ts +21 -2
  29. package/src/layout/text-width.ts +92 -4
  30. package/src/layout/viewbox.ts +0 -8
  31. package/src/layout.ts +8 -1
  32. package/src/presets.ts +120 -22
  33. package/src/render/header.tsx +3 -1
  34. package/src/render/nodes.tsx +6 -5
  35. package/src/render/payload-binding.ts +88 -3
  36. package/src/render/stage.tsx +17 -34
  37. package/src/render/template-fields.ts +212 -0
  38. package/src/render/utils.ts +32 -2
  39. package/src/render.tsx +2 -9
  40. package/src/types.ts +33 -2
  41. package/src/validate.ts +27 -9
  42. package/src/visual-validate.ts +34 -1
  43. package/src/layout/label-shift.ts +0 -28
package/dist/react.js CHANGED
@@ -460,7 +460,35 @@ function isCJK(code) {
460
460
  function isHalfwidthKana(code) {
461
461
  return code >= 65377 && code <= 65500;
462
462
  }
463
+ var EMOJI_ADVANCE_EM = 1.05;
464
+ var MONO_EMOJI_ADVANCE_EM = 1.16;
465
+ var WIDE_SYMBOL_ADVANCE_EM = 0.95;
466
+ function isEmoji(code) {
467
+ return code >= 126976 && code <= 129791 || // 絵文字の主要面
468
+ code >= 9728 && code <= 10175 || // 記号と絵文字 (♻ ✅ ❤ 等)
469
+ code >= 127462 && code <= 127487;
470
+ }
471
+ function isEmojiGrapheme(grapheme, firstCode) {
472
+ return isEmoji(firstCode) || grapheme.includes("\uFE0F");
473
+ }
474
+ function isWideSymbol(code) {
475
+ return code >= 8592 && code <= 8703 || // 矢印
476
+ code >= 9472 && code <= 9599 || // 罫線
477
+ code >= 9632 && code <= 9727 || // 幾何図形
478
+ code >= 11008 && code <= 11263;
479
+ }
480
+ var CLUSTER_JOINER_RE = /\u200d|\ufe0f|[\u{1f000}-\u{1faff}]|[\u{2600}-\u{27bf}]/u;
481
+ var \u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B;
482
+ function segmentGraphemes(text) {
483
+ if (typeof Intl === "undefined" || typeof Intl.Segmenter !== "function") {
484
+ return [...text];
485
+ }
486
+ \u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B ??= new Intl.Segmenter(void 0, { granularity: "grapheme" });
487
+ return [...\u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B.segment(text)].map((s) => s.segment);
488
+ }
463
489
  function defaultAdvanceEm(ch, code) {
490
+ if (isEmoji(code)) return EMOJI_ADVANCE_EM;
491
+ if (isWideSymbol(code)) return WIDE_SYMBOL_ADVANCE_EM;
464
492
  if (isCJK(code)) return 1.08;
465
493
  if (isHalfwidthKana(code)) return 0.72;
466
494
  if (ch >= "a" && ch <= "z") return 0.73;
@@ -474,19 +502,23 @@ function measureTextWidth(text, opts = {}) {
474
502
  const fontFamily = opts.fontFamily ?? "sans";
475
503
  let advanceEmSum = 0;
476
504
  let charCount = 0;
477
- for (const ch of text) {
505
+ const \u6587\u5B57\u5217 = CLUSTER_JOINER_RE.test(text) ? segmentGraphemes(text) : [...text];
506
+ for (const ch of \u6587\u5B57\u5217) {
478
507
  charCount++;
508
+ const code = ch.codePointAt(0) ?? 0;
509
+ if (isEmojiGrapheme(ch, code)) {
510
+ advanceEmSum += fontFamily === "mono" ? MONO_EMOJI_ADVANCE_EM : EMOJI_ADVANCE_EM;
511
+ continue;
512
+ }
479
513
  if (fontFamily === "mono") {
480
- const code2 = ch.codePointAt(0) ?? 0;
481
- advanceEmSum += isCJK(code2) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM;
514
+ advanceEmSum += isCJK(code) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM;
482
515
  continue;
483
516
  }
484
- const code = ch.codePointAt(0) ?? 0;
485
517
  if (isCJK(code)) {
486
518
  advanceEmSum += 1.08;
487
519
  continue;
488
520
  }
489
- const table = INTER_BOLD_ADVANCE_EM[ch];
521
+ const table = ch.length === 1 ? INTER_BOLD_ADVANCE_EM[ch] : void 0;
490
522
  advanceEmSum += table !== void 0 ? table : defaultAdvanceEm(ch, code);
491
523
  }
492
524
  const w = advanceEmSum * fontSize + letterSpacing * charCount;
@@ -542,13 +574,15 @@ var KINDS_WITHOUT_TITLE_TEXT = /* @__PURE__ */ new Set([
542
574
  "funnel-stages",
543
575
  "quadrant-matrix",
544
576
  "tree-hierarchy",
545
- "journey-map",
546
- // 形の中に自前の文字を置く (title は使わない)
547
- "shape-blockchain-block"
577
+ "journey-map"
548
578
  ]);
549
579
  function rendersTitleText(kind) {
550
580
  return !KINDS_WITHOUT_TITLE_TEXT.has(kind ?? "");
551
581
  }
582
+ var KINDS_FITTING_OWN_TITLE = /* @__PURE__ */ new Set(["shape-blockchain-block"]);
583
+ function fitsOwnTitleWidth(kind) {
584
+ return KINDS_FITTING_OWN_TITLE.has(kind ?? "");
585
+ }
552
586
  var KINDS_WITH_ROW_TEXT = /* @__PURE__ */ new Set([
553
587
  // 専用の表組み (StorageNode)
554
588
  "storage",
@@ -735,6 +769,70 @@ function buildDiagramAltText(topic, phase) {
735
769
  return parts.join(" ");
736
770
  }
737
771
 
772
+ // src/layout/footer-shape.ts
773
+ var SHAPE_DRAW_UP_EXTENT = {
774
+ "shape-robot-arm": 201,
775
+ // 実測 上 129
776
+ "shape-iot-sensor": 120,
777
+ // 48
778
+ "shape-credit-card": 113,
779
+ // 40.8
780
+ "shape-exchange": 107,
781
+ // 35
782
+ "shape-storefront": 104,
783
+ // 32
784
+ "shape-cdn-edge": 103,
785
+ // 30.8
786
+ "shape-payment-provider": 101,
787
+ // 29
788
+ "shape-gear": 96,
789
+ // 23.9
790
+ "shape-rpc-node": 94,
791
+ // 22
792
+ "shape-wallet": 84
793
+ // 12.1
794
+ };
795
+ function lifelineFooterNodes(lanes, nodes) {
796
+ const \u6570 = /* @__PURE__ */ new Map();
797
+ for (const n of nodes) \u6570.set(n.lane, (\u6570.get(n.lane) ?? 0) + 1);
798
+ const lifelineLanes = /* @__PURE__ */ new Set();
799
+ for (const lane of lanes) {
800
+ if (lane.lifeline) lifelineLanes.add(lane.id);
801
+ }
802
+ return nodes.filter(
803
+ (n) => n.role === "lifeline-footer" && lifelineLanes.has(n.lane) && (\u6570.get(n.lane) ?? 0) >= 2
804
+ );
805
+ }
806
+ function footerShapeDropY(kind, h) {
807
+ const extent = SHAPE_DRAW_UP_EXTENT[kind];
808
+ if (extent === void 0) return 0;
809
+ if (!Number.isFinite(h) || h <= 0) return 0;
810
+ return Math.max(0, extent - h);
811
+ }
812
+ function footerShapeDrops(lanes, nodes) {
813
+ return footerShapeDropsOf(lifelineFooterNodes(lanes, nodes));
814
+ }
815
+ function footerShapeDropsOf(footers) {
816
+ const drops = /* @__PURE__ */ new Map();
817
+ for (const footer of footers) {
818
+ const dy = footerShapeDropY(footer.kind, footer.h);
819
+ if (dy > 0) drops.set(footer.id, dy);
820
+ }
821
+ return drops;
822
+ }
823
+ function applyFooterShapeDrops(lanes, nodes) {
824
+ const drops = footerShapeDrops(lanes, nodes);
825
+ if (drops.size === 0) return nodes;
826
+ return nodes.map((n) => {
827
+ if (n.posX !== void 0 && n.posY !== void 0) return n;
828
+ const dy = drops.get(n.id);
829
+ return dy === void 0 ? n : { ...n, cy: n.cy + dy };
830
+ });
831
+ }
832
+ function footerShapeDrawTop(node) {
833
+ return node.cy - node.h / 2 - footerShapeDropY(node.kind, node.h);
834
+ }
835
+
738
836
  // src/layout/collisions.ts
739
837
  var LANE_LABEL_CLEARANCE_MARGIN = 2;
740
838
  function collectBBoxes(lanes, nodes, edges) {
@@ -750,14 +848,16 @@ function collectBBoxes(lanes, nodes, edges) {
750
848
  h: 28
751
849
  });
752
850
  }
851
+ const footerDraw = footerShapeDrops(lanes, nodes);
753
852
  for (const n of nodes) {
853
+ const up = footerDraw.get(n.id) ?? 0;
754
854
  out.push({
755
855
  kind: "node",
756
856
  id: n.id,
757
857
  x: n.cx - n.w / 2,
758
- y: n.cy - n.h / 2,
858
+ y: n.cy - n.h / 2 - up,
759
859
  w: n.w,
760
- h: n.h
860
+ h: n.h + up
761
861
  });
762
862
  }
763
863
  for (const e of edges) {
@@ -3582,67 +3682,6 @@ function layoutNodes(diag, lanes) {
3582
3682
  return out;
3583
3683
  }
3584
3684
 
3585
- // src/layout/footer-shape.ts
3586
- var SHAPE_DRAW_UP_EXTENT = {
3587
- "shape-robot-arm": 201,
3588
- // 実測 上 129
3589
- "shape-iot-sensor": 120,
3590
- // 48
3591
- "shape-credit-card": 113,
3592
- // 40.8
3593
- "shape-exchange": 107,
3594
- // 35
3595
- "shape-storefront": 104,
3596
- // 32
3597
- "shape-cdn-edge": 103,
3598
- // 30.8
3599
- "shape-payment-provider": 101,
3600
- // 29
3601
- "shape-gear": 96,
3602
- // 23.9
3603
- "shape-rpc-node": 94,
3604
- // 22
3605
- "shape-wallet": 84
3606
- // 12.1
3607
- };
3608
- function lifelineFooterNodes(lanes, nodes) {
3609
- const byLane = /* @__PURE__ */ new Map();
3610
- for (const n of nodes) {
3611
- const inside = byLane.get(n.lane);
3612
- if (inside) inside.push(n);
3613
- else byLane.set(n.lane, [n]);
3614
- }
3615
- const footers = [];
3616
- for (const lane of lanes) {
3617
- if (!lane.lifeline) continue;
3618
- const inside = byLane.get(lane.id);
3619
- if (inside === void 0 || inside.length < 2) continue;
3620
- let footer = inside[0];
3621
- for (const n of inside) {
3622
- if (n.cy >= footer.cy) footer = n;
3623
- }
3624
- footers.push(footer);
3625
- }
3626
- return footers;
3627
- }
3628
- function footerShapeDropY(kind, h) {
3629
- const extent = SHAPE_DRAW_UP_EXTENT[kind];
3630
- if (extent === void 0) return 0;
3631
- if (!Number.isFinite(h) || h <= 0) return 0;
3632
- return Math.max(0, extent - h);
3633
- }
3634
- function footerShapeDrops(lanes, nodes) {
3635
- return footerShapeDropsOf(lifelineFooterNodes(lanes, nodes));
3636
- }
3637
- function footerShapeDropsOf(footers) {
3638
- const drops = /* @__PURE__ */ new Map();
3639
- for (const footer of footers) {
3640
- const dy = footerShapeDropY(footer.kind, footer.h);
3641
- if (dy > 0) drops.set(footer.id, dy);
3642
- }
3643
- return drops;
3644
- }
3645
-
3646
3685
  // src/layout/viewbox.ts
3647
3686
  function computeViewBox(lanes, nodes, edges, bboxes, viewport) {
3648
3687
  let maxX = 0;
@@ -3663,11 +3702,6 @@ function computeViewBox(lanes, nodes, edges, bboxes, viewport) {
3663
3702
  maxX = Math.max(maxX, n.cx + n.w / 2);
3664
3703
  maxY = Math.max(maxY, n.cy + n.h / 2);
3665
3704
  }
3666
- const footerDrops = footerShapeDrops(lanes, nodes);
3667
- for (const n of nodes) {
3668
- const dy = footerDrops.get(n.id);
3669
- if (dy !== void 0) maxY = Math.max(maxY, n.cy + n.h / 2 + dy);
3670
- }
3671
3705
  if (!Number.isFinite(minX)) minX = 0;
3672
3706
  if (!Number.isFinite(minY)) minY = 0;
3673
3707
  const x = minX - VIEW_PAD;
@@ -3745,7 +3779,7 @@ function applyRowLevelNodeShifts(nodes, lanes, nodeShifts) {
3745
3779
  }
3746
3780
  function layout(diag) {
3747
3781
  const lanes = layoutLanes(diag);
3748
- const rawNodes = layoutNodes(diag, lanes);
3782
+ const rawNodes = applyFooterShapeDrops(lanes, layoutNodes(diag, lanes));
3749
3783
  const expandedLanes = expandLanesForNodes(lanes, rawNodes);
3750
3784
  const gapExpandedLanes = expandLaneGapsForEdgeLabels(expandedLanes, rawNodes, diag.edges);
3751
3785
  const nodes = rawNodes.map((n) => {
@@ -4608,7 +4642,7 @@ function templateRefIds(text) {
4608
4642
  return out;
4609
4643
  }
4610
4644
  function computeStateValues(laid, phaseIdx, progress) {
4611
- const values = {};
4645
+ const values = /* @__PURE__ */ Object.create(null);
4612
4646
  for (const s of laid.states) values[s.id] = s.initial;
4613
4647
  for (let i = 0; i < laid.phases.length; i++) {
4614
4648
  const phase = laid.phases[i];
@@ -4626,10 +4660,20 @@ function computeStateValues(laid, phaseIdx, progress) {
4626
4660
  }
4627
4661
  }
4628
4662
  }
4629
- const out = {};
4663
+ const out = /* @__PURE__ */ Object.create(null);
4630
4664
  for (const [k, v] of Object.entries(values)) out[k] = String(v);
4631
4665
  return withDerivedValues(out, laid.derived);
4632
4666
  }
4667
+ function mergeStateValues(base, overrides) {
4668
+ const merged = Object.assign(/* @__PURE__ */ Object.create(null), base);
4669
+ for (const key of Object.keys(overrides)) {
4670
+ const v = overrides[key];
4671
+ if (typeof v === "number" || typeof v === "string" || typeof v === "boolean") {
4672
+ merged[key] = String(v);
4673
+ }
4674
+ }
4675
+ return merged;
4676
+ }
4633
4677
  function interpolate(template, values) {
4634
4678
  return template.replace(TEMPLATE_REF_RE, (_, id, accessor) => {
4635
4679
  const raw = Object.hasOwn(values, id) ? values[id] : void 0;
@@ -4779,6 +4823,65 @@ function pathSubpath(d, progress) {
4779
4823
  return d;
4780
4824
  }
4781
4825
 
4826
+ // src/render/template-fields.ts
4827
+ var TEXT_FIELDS = ["title", "eyebrow", "subtitle", "value", "wBind", "hBind", "visibleIf"];
4828
+ var LIST_FIELDS = ["rows"];
4829
+ var NUMERIC_FIELDS = ["opacity", "renderOffsetX", "renderOffsetY"];
4830
+ var SHAPE_TEMPLATE_FIELDS = ["source", "radius", "fillProgress", "angle", "level", "rotation", "fill"];
4831
+ function shapeTexts(shape) {
4832
+ if (!shape) return [];
4833
+ const out = [];
4834
+ const \u4E2D\u8EAB = shape;
4835
+ for (const f of SHAPE_TEMPLATE_FIELDS) {
4836
+ const v = \u4E2D\u8EAB[f];
4837
+ if (typeof v === "string" && v) out.push(v);
4838
+ }
4839
+ return out;
4840
+ }
4841
+ function payloadTexts(node) {
4842
+ const out = [];
4843
+ const \u8DB3\u3059 = (v) => {
4844
+ if (typeof v === "string" && v) out.push(v);
4845
+ };
4846
+ for (const d of node.chartData ?? []) \u8DB3\u3059(d.value);
4847
+ for (const s of node.funnelData ?? []) \u8DB3\u3059(s.count);
4848
+ for (const t of node.ganttData ?? []) {
4849
+ \u8DB3\u3059(t.startIdx);
4850
+ \u8DB3\u3059(t.endIdx);
4851
+ }
4852
+ for (const i of node.quadrantData?.items ?? []) \u8DB3\u3059(i.quadrant);
4853
+ for (const s of node.journeyData ?? []) \u8DB3\u3059(s.emotion);
4854
+ for (const n of node.treeData ?? []) {
4855
+ \u8DB3\u3059(n.title);
4856
+ \u8DB3\u3059(n.subtitle);
4857
+ }
4858
+ if (node.mindData) {
4859
+ \u8DB3\u3059(node.mindData.rootTitle);
4860
+ for (const b of node.mindData.branches) {
4861
+ \u8DB3\u3059(b.title);
4862
+ \u8DB3\u3059(b.subtitle);
4863
+ }
4864
+ }
4865
+ return out;
4866
+ }
4867
+ function nodeTemplateTexts(node) {
4868
+ const out = [];
4869
+ for (const f of TEXT_FIELDS) {
4870
+ const v = node[f];
4871
+ if (typeof v === "string" && v) out.push(v);
4872
+ }
4873
+ for (const f of LIST_FIELDS) {
4874
+ for (const v of node[f] ?? []) if (v) out.push(v);
4875
+ }
4876
+ for (const f of NUMERIC_FIELDS) {
4877
+ const v = node[f];
4878
+ if (typeof v === "string" && v) out.push(v);
4879
+ }
4880
+ out.push(...shapeTexts(node.shape));
4881
+ out.push(...payloadTexts(node));
4882
+ return out;
4883
+ }
4884
+
4782
4885
  // src/validate.ts
4783
4886
  var TONES2 = new Set(TONES);
4784
4887
  var KINDS = new Set(NODE_KINDS);
@@ -4837,7 +4940,13 @@ function validate(diag) {
4837
4940
  const nodeIds = new Set(diag.nodes.map((n) => n.id));
4838
4941
  const edgeIds = new Set(diag.edges.map((e) => e.id));
4839
4942
  const stateIds = new Set(diag.states.map((s) => s.id));
4840
- const readableIds = /* @__PURE__ */ new Set([...stateIds, ...(diag.derived ?? []).map((d) => d.id)]);
4943
+ const readableIds = /* @__PURE__ */ new Set([
4944
+ ...stateIds,
4945
+ ...(diag.derived ?? []).map((d) => d.id),
4946
+ ...(diag.inputs ?? []).map((i) => i.id),
4947
+ ...(diag.formulas ?? []).map((f) => f.id),
4948
+ ...(diag.scrollTriggers ?? []).map((t) => t.id)
4949
+ ]);
4841
4950
  const suggest = (target, candidates) => {
4842
4951
  const list = [...candidates];
4843
4952
  if (list.length === 0) return "";
@@ -4904,10 +5013,7 @@ function validate(diag) {
4904
5013
  }
4905
5014
  }
4906
5015
  for (const n of diag.nodes) {
4907
- const checks = [];
4908
- if (n.value) checks.push(n.value);
4909
- if (n.rows) checks.push(...n.rows);
4910
- for (const text of checks) {
5016
+ for (const text of nodeTemplateTexts(n)) {
4911
5017
  for (const id of templateRefIds(text)) {
4912
5018
  if (!readableIds.has(id)) {
4913
5019
  warnings.push(`node "${n.id}" \u304C\u672A\u5B9A\u7FA9 state "${id}" \u3092\u53C2\u7167`);
@@ -4935,8 +5041,7 @@ function validate(diag) {
4935
5041
  for (const s of p.sets) stateUsed.add(s.stateId);
4936
5042
  }
4937
5043
  for (const n of diag.nodes) {
4938
- const texts2 = [n.value, ...n.rows ?? []].filter(Boolean);
4939
- for (const text of texts2) {
5044
+ for (const text of nodeTemplateTexts(n)) {
4940
5045
  for (const id of templateRefIds(text)) stateUsed.add(id);
4941
5046
  }
4942
5047
  }
@@ -5124,7 +5229,7 @@ function StateDiffCard({
5124
5229
  ] }) }),
5125
5230
  /* @__PURE__ */ jsx("tbody", { style: { color: "var(--cdl-text, #1a1f2a)" }, children: states.map((s) => {
5126
5231
  const initial = String(s.initial);
5127
- const current = stateValues[s.id] ?? initial;
5232
+ const current = Object.hasOwn(stateValues, s.id) ? stateValues[s.id] : initial;
5128
5233
  const changed = initial !== current;
5129
5234
  return /* @__PURE__ */ jsxs("tr", { children: [
5130
5235
  /* @__PURE__ */ jsx("td", { className: "py-1 text-left text-[12px]", children: s.id }),
@@ -6428,6 +6533,42 @@ function resolveJourneyData(steps, values) {
6428
6533
  return e.ok ? { ...s, emotion: e.value } : { ...s, emotion: e.value, unresolved: true };
6429
6534
  });
6430
6535
  }
6536
+ function resolveBoundText(raw, values) {
6537
+ if (!raw.includes("{")) return { value: raw, ok: true };
6538
+ const resolved = interpolate(raw, values);
6539
+ return hasUnresolvedRef(resolved) ? { value: resolved, ok: false } : { value: resolved, ok: true };
6540
+ }
6541
+ function resolveTreeData(nodes, values) {
6542
+ const \u8AAD\u3080 = nodes.some((n) => n.title.includes("{") || (n.subtitle?.includes("{") ?? false));
6543
+ if (!\u8AAD\u3080) return nodes;
6544
+ return nodes.map((n) => {
6545
+ const title = resolveBoundText(n.title, values);
6546
+ const subtitle = n.subtitle === void 0 ? void 0 : resolveBoundText(n.subtitle, values);
6547
+ const \u89E3\u6C7A\u5F8C = {
6548
+ ...n,
6549
+ title: title.value,
6550
+ ...subtitle ? { subtitle: subtitle.value } : {}
6551
+ };
6552
+ return title.ok && (subtitle?.ok ?? true) ? \u89E3\u6C7A\u5F8C : { ...\u89E3\u6C7A\u5F8C, unresolved: true };
6553
+ });
6554
+ }
6555
+ function resolveMindData(data, values) {
6556
+ const \u8AAD\u3080 = data.rootTitle.includes("{") || data.branches.some((b) => b.title.includes("{") || (b.subtitle?.includes("{") ?? false));
6557
+ if (!\u8AAD\u3080) return data;
6558
+ const root = resolveBoundText(data.rootTitle, values);
6559
+ const branches = data.branches.map((b) => {
6560
+ const title = resolveBoundText(b.title, values);
6561
+ const subtitle = b.subtitle === void 0 ? void 0 : resolveBoundText(b.subtitle, values);
6562
+ const \u89E3\u6C7A\u5F8C2 = {
6563
+ ...b,
6564
+ title: title.value,
6565
+ ...subtitle ? { subtitle: subtitle.value } : {}
6566
+ };
6567
+ return title.ok && (subtitle?.ok ?? true) ? \u89E3\u6C7A\u5F8C2 : { ...\u89E3\u6C7A\u5F8C2, unresolved: true };
6568
+ });
6569
+ const \u89E3\u6C7A\u5F8C = { ...data, rootTitle: root.value, branches };
6570
+ return root.ok ? \u89E3\u6C7A\u5F8C : { ...\u89E3\u6C7A\u5F8C, unresolved: true };
6571
+ }
6431
6572
  function ChartLineNode({
6432
6573
  node,
6433
6574
  active,
@@ -6834,16 +6975,53 @@ function GanttNode({
6834
6975
  const rowGap = 20;
6835
6976
  const rowCount = tasks.length || 1;
6836
6977
  const rowH = Math.max(28, (canvasH - rowGap * (rowCount + 1)) / rowCount);
6837
- const maxIdx = Math.max(1, Math.ceil(Math.max(...tasks.map((t) => t.endIdx + 1), 1)));
6978
+ const \u4F4D\u7F6E\u306E\u4E0A\u9650 = 1e6;
6979
+ const \u53CE\u3081\u305F = tasks.map((t) => {
6980
+ const \u59CB = Math.min(\u4F4D\u7F6E\u306E\u4E0A\u9650, Math.max(0, Number.isFinite(t.startIdx) ? t.startIdx : 0));
6981
+ const \u7D42 = Math.min(\u4F4D\u7F6E\u306E\u4E0A\u9650, Math.max(\u59CB, Number.isFinite(t.endIdx) ? t.endIdx : \u59CB));
6982
+ return { ...t, startIdx: \u59CB, endIdx: \u7D42 };
6983
+ });
6984
+ const \u5BA3\u8A00 = node.ganttAxisMax;
6985
+ const \u5BA3\u8A00\u3057\u305F\u5C3A = typeof \u5BA3\u8A00 === "number" && Number.isFinite(\u5BA3\u8A00) && \u5BA3\u8A00 > 0 ? Math.min(\u4F4D\u7F6E\u306E\u4E0A\u9650, Math.ceil(\u5BA3\u8A00)) : void 0;
6986
+ const maxIdx = \u5BA3\u8A00\u3057\u305F\u5C3A ?? Math.max(
6987
+ 1,
6988
+ Math.ceil(Math.max(...\u53CE\u3081\u305F.flatMap((t) => [t.startIdx + 1, t.endIdx + 1]), 1))
6989
+ );
6838
6990
  const cellW = canvasW / maxIdx;
6991
+ const \u6700\u5F8C\u306E\u76EE\u76DB\u308A = maxIdx - 1;
6992
+ const \u6574\u3048\u305F = \u5BA3\u8A00\u3057\u305F\u5C3A === void 0 ? \u53CE\u3081\u305F : \u53CE\u3081\u305F.map((t) => {
6993
+ const \u59CB = Math.min(t.startIdx, \u6700\u5F8C\u306E\u76EE\u76DB\u308A);
6994
+ const \u7D42 = Math.min(t.endIdx, \u6700\u5F8C\u306E\u76EE\u76DB\u308A);
6995
+ const \u5BC4\u305B\u305F = \u59CB !== t.startIdx || \u7D42 !== t.endIdx;
6996
+ return \u5BC4\u305B\u305F ? { ...t, startIdx: \u59CB, endIdx: \u7D42, clipped: true } : t;
6997
+ });
6998
+ const \u76EE\u76DB\u308A\u306E\u4E0A\u9650 = 200;
6999
+ const \u76EE\u76DB\u308A\u306E\u9593\u9694 = Math.max(1, Math.ceil(maxIdx / \u76EE\u76DB\u308A\u306E\u4E0A\u9650));
7000
+ const \u76EE\u76DB\u308A\u306E\u672C\u6570 = Math.ceil(maxIdx / \u76EE\u76DB\u308A\u306E\u9593\u9694);
6839
7001
  const xAt = (idx) => PAD_LEFT + idx * cellW;
6840
7002
  const yAt = (row) => PAD_TOP + rowGap + row * (rowH + rowGap);
6841
- const gridLabels = Array.from({ length: maxIdx }, (_, i) => {
6842
- const t = tasks.find((tt) => tt.startIdx === i);
6843
- return t?.startLabel ?? String(i);
6844
- });
6845
- const taskById = new Map(tasks.map((t) => [t.id, t]));
6846
- const rowOf = new Map(tasks.map((t, i) => [t.id, i]));
7003
+ const \u540D\u524D = { \u6574\u6570\u306E\u958B\u59CB: /* @__PURE__ */ new Map(), \u6574\u6570\u306E\u7D42\u4E86: /* @__PURE__ */ new Map(), \u7AEF\u6570\u306E\u958B\u59CB: /* @__PURE__ */ new Map(), \u7AEF\u6570\u306E\u7D42\u4E86: /* @__PURE__ */ new Map() };
7004
+ const \u7F6E\u304F = (\u8868, \u4F4D\u7F6E, label) => {
7005
+ if (label !== "" && Number.isFinite(\u4F4D\u7F6E) && !\u8868.has(\u4F4D\u7F6E)) \u8868.set(\u4F4D\u7F6E, label);
7006
+ };
7007
+ for (const t of \u53CE\u3081\u305F) {
7008
+ const \u6574\u6570\u306E\u958B\u59CB = Number.isInteger(t.startIdx);
7009
+ \u7F6E\u304F(\u6574\u6570\u306E\u958B\u59CB ? \u540D\u524D.\u6574\u6570\u306E\u958B\u59CB : \u540D\u524D.\u7AEF\u6570\u306E\u958B\u59CB, Math.round(t.startIdx), t.startLabel);
7010
+ const \u6574\u6570\u306E\u7D42\u4E86 = Number.isInteger(t.endIdx);
7011
+ \u7F6E\u304F(\u6574\u6570\u306E\u7D42\u4E86 ? \u540D\u524D.\u6574\u6570\u306E\u7D42\u4E86 : \u540D\u524D.\u7AEF\u6570\u306E\u7D42\u4E86, Math.round(t.endIdx), t.endLabel);
7012
+ }
7013
+ const \u540D\u524D\u3092\u5F15\u304F = (i) => \u540D\u524D.\u6574\u6570\u306E\u958B\u59CB.get(i) ?? \u540D\u524D.\u6574\u6570\u306E\u7D42\u4E86.get(i) ?? \u540D\u524D.\u7AEF\u6570\u306E\u958B\u59CB.get(i) ?? \u540D\u524D.\u7AEF\u6570\u306E\u7D42\u4E86.get(i) ?? "";
7014
+ const \u4F4D\u7F6E\u306E\u96C6\u5408 = /* @__PURE__ */ new Set();
7015
+ for (let n = 0; n < \u76EE\u76DB\u308A\u306E\u672C\u6570; n += 1) \u4F4D\u7F6E\u306E\u96C6\u5408.add(n * \u76EE\u76DB\u308A\u306E\u9593\u9694);
7016
+ for (const \u8868 of [\u540D\u524D.\u6574\u6570\u306E\u958B\u59CB, \u540D\u524D.\u6574\u6570\u306E\u7D42\u4E86, \u540D\u524D.\u7AEF\u6570\u306E\u958B\u59CB, \u540D\u524D.\u7AEF\u6570\u306E\u7D42\u4E86]) {
7017
+ for (const i of \u8868.keys()) if (i >= 0 && i < maxIdx) \u4F4D\u7F6E\u306E\u96C6\u5408.add(i);
7018
+ }
7019
+ const gridLabels = [...\u4F4D\u7F6E\u306E\u96C6\u5408].sort((a, b) => a - b).map((i) => ({ \u4F4D\u7F6E: i, label: \u540D\u524D\u3092\u5F15\u304F(i) }));
7020
+ const \u5E2F\u306E\u4F59\u767D = Math.min(6, cellW / 2);
7021
+ const \u5E2F\u306E\u5DE6 = (idx) => xAt(idx) + \u5E2F\u306E\u4F59\u767D / 2;
7022
+ const \u5E2F\u306E\u53F3 = (idx) => xAt(idx) + cellW - \u5E2F\u306E\u4F59\u767D / 2;
7023
+ const taskById = new Map(\u6574\u3048\u305F.map((t) => [t.id, t]));
7024
+ const rowOf = new Map(\u6574\u3048\u305F.map((t, i) => [t.id, i]));
6847
7025
  return /* @__PURE__ */ jsxs("g", { transform: `translate(${x0} ${y0})`, children: [
6848
7026
  /* @__PURE__ */ jsx(
6849
7027
  "rect",
@@ -6859,10 +7037,11 @@ function GanttNode({
6859
7037
  strokeWidth: active ? 3 : 1.25
6860
7038
  }
6861
7039
  ),
6862
- gridLabels.map((label, i) => /* @__PURE__ */ jsxs("g", { children: [
7040
+ gridLabels.map(({ \u4F4D\u7F6E: i, label }) => /* @__PURE__ */ jsxs("g", { children: [
6863
7041
  /* @__PURE__ */ jsx(
6864
7042
  "line",
6865
7043
  {
7044
+ "data-cdl-role": "gantt-grid",
6866
7045
  x1: xAt(i),
6867
7046
  y1: PAD_TOP,
6868
7047
  x2: xAt(i),
@@ -6873,9 +7052,10 @@ function GanttNode({
6873
7052
  opacity: 0.5
6874
7053
  }
6875
7054
  ),
6876
- /* @__PURE__ */ jsx(
7055
+ label === "" ? null : /* @__PURE__ */ jsx(
6877
7056
  "text",
6878
7057
  {
7058
+ "data-cdl-role": "gantt-tick",
6879
7059
  x: xAt(i) + cellW / 2,
6880
7060
  y: PAD_TOP + canvasH + 18,
6881
7061
  fontSize: 11,
@@ -6897,7 +7077,7 @@ function GanttNode({
6897
7077
  opacity: 0.5
6898
7078
  }
6899
7079
  ),
6900
- tasks.map((t, row) => /* @__PURE__ */ jsx(
7080
+ \u6574\u3048\u305F.map((t, row) => /* @__PURE__ */ jsx(
6901
7081
  "text",
6902
7082
  {
6903
7083
  x: PAD_LEFT - 12,
@@ -6910,16 +7090,17 @@ function GanttNode({
6910
7090
  },
6911
7091
  `label-${t.id}`
6912
7092
  )),
6913
- tasks.map((t, row) => {
6914
- const bx = xAt(t.startIdx) + 3;
7093
+ \u6574\u3048\u305F.map((t, row) => {
7094
+ const bx = \u5E2F\u306E\u5DE6(t.startIdx);
6915
7095
  const by = yAt(row);
6916
- const bw = Math.max(cellW - 6, (t.endIdx - t.startIdx + 1) * cellW - 6);
7096
+ const bw = Math.max(0, \u5E2F\u306E\u53F3(t.endIdx) - bx);
6917
7097
  return /* @__PURE__ */ jsxs("g", { children: [
6918
7098
  /* @__PURE__ */ jsx(
6919
7099
  "rect",
6920
7100
  {
6921
7101
  "data-cdl-role": "gantt-bar",
6922
7102
  "data-cdl-unresolved": t.unresolved ? "true" : void 0,
7103
+ "data-cdl-clipped": "clipped" in t && t.clipped ? "true" : void 0,
6923
7104
  x: bx,
6924
7105
  y: by,
6925
7106
  width: bw,
@@ -6942,13 +7123,13 @@ function GanttNode({
6942
7123
  )
6943
7124
  ] }, `bar-${t.id}`);
6944
7125
  }),
6945
- tasks.filter((t) => t.dependsOn && taskById.has(t.dependsOn)).map((t) => {
7126
+ \u6574\u3048\u305F.filter((t) => t.dependsOn && taskById.has(t.dependsOn)).map((t) => {
6946
7127
  const parent = taskById.get(t.dependsOn);
6947
7128
  const parentRow = rowOf.get(parent.id);
6948
7129
  const childRow = rowOf.get(t.id);
6949
- const parentBarRight = xAt(parent.endIdx) + cellW - 3;
7130
+ const parentBarRight = \u5E2F\u306E\u53F3(parent.endIdx);
6950
7131
  const parentMidY = yAt(parentRow) + rowH / 2;
6951
- const childBarLeft = xAt(t.startIdx) + 3;
7132
+ const childBarLeft = \u5E2F\u306E\u5DE6(t.startIdx);
6952
7133
  const childMidY = yAt(childRow) + rowH / 2;
6953
7134
  const arrowHeadSize = 8;
6954
7135
  const arrowHeadTipGap = 10;
@@ -6990,12 +7171,59 @@ function toneColor3(tone) {
6990
7171
  if (!tone) return TONE.accent;
6991
7172
  return TONE[tone];
6992
7173
  }
7174
+
7175
+ // src/kinds/box-lines.ts
7176
+ var \u884C\u9001\u308A\u306E\u6BD4 = 1.15;
7177
+ var \u5B57\u306E\u9AD8\u3055\u306E\u6BD4 = 0.72;
7178
+ var \u4E0A\u4E0B\u306E\u4F59\u767D = 2;
7179
+ var \u5DE6\u53F3\u306E\u4F59\u767D = 8;
7180
+ function \u5E45\u3067\u5207\u308B(text, fontSize, \u4F7F\u3048\u308B\u5E45, \u6E2C\u308B = textWidth) {
7181
+ if (\u4F7F\u3048\u308B\u5E45 <= 0) return "";
7182
+ if (\u6E2C\u308B(text, fontSize) <= \u4F7F\u3048\u308B\u5E45) return text;
7183
+ const \u7701\u7565 = "\u2026";
7184
+ const \u7701\u7565\u306E\u5E45 = \u6E2C\u308B(\u7701\u7565, fontSize);
7185
+ if (\u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E45) return "";
7186
+ let \u51FA = "";
7187
+ let \u5E45 = 0;
7188
+ for (const c of \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text)) {
7189
+ const \u5B57\u306E\u5E452 = \u6E2C\u308B(c, fontSize);
7190
+ if (\u5E45 + \u5B57\u306E\u5E452 + \u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E45) break;
7191
+ \u5E45 += \u5B57\u306E\u5E452;
7192
+ \u51FA += c;
7193
+ }
7194
+ return `${\u51FA}${\u7701\u7565}`;
7195
+ }
7196
+ function \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text) {
7197
+ const \u533A\u5207\u308A = Intl.Segmenter;
7198
+ if (typeof \u533A\u5207\u308A !== "function") return [...text];
7199
+ return [...new \u533A\u5207\u308A(void 0, { granularity: "grapheme" }).segment(text)].map((g) => g.segment);
7200
+ }
7201
+ function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u3055) {
7202
+ const \u5019\u88DC = \u884C.filter((r, i) => i === 0 || r.text.trim() !== "");
7203
+ if (\u5019\u88DC.length === 0) return [];
7204
+ const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u3055 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
7205
+ const \u9AD8\u3055 = (rs) => rs.reduce((a, r) => a + r.fontSize * \u884C\u9001\u308A\u306E\u6BD4, 0);
7206
+ const \u6B8B\u3059 = [...\u5019\u88DC];
7207
+ while (\u6B8B\u3059.length > 1 && \u9AD8\u3055(\u6B8B\u3059) > \u4F7F\u3048\u308B\u9AD8\u3055) \u6B8B\u3059.pop();
7208
+ const \u4F7F\u3048\u308B\u5E45 = \u7BB1\u306E\u5E45 - \u5DE6\u53F3\u306E\u4F59\u767D * 2;
7209
+ const \u7DCF\u9AD8 = \u9AD8\u3055(\u6B8B\u3059);
7210
+ let \u7A4D\u307F = -\u7DCF\u9AD8 / 2;
7211
+ return \u6B8B\u3059.map((r) => {
7212
+ const dy = \u7A4D\u307F + (\u884C\u9001\u308A\u306E\u6BD4 + \u5B57\u306E\u9AD8\u3055\u306E\u6BD4) / 2 * r.fontSize;
7213
+ \u7A4D\u307F += r.fontSize * \u884C\u9001\u308A\u306E\u6BD4;
7214
+ return { ...r, text: \u5E45\u3067\u5207\u308B(r.text, r.fontSize, \u4F7F\u3048\u308B\u5E45), dy };
7215
+ });
7216
+ }
6993
7217
  var MIND_TONES = ["accent", "teal", "success", "warning", "info", "error"];
6994
7218
  var MIND_BOX_GAP = 24;
6995
- function MindMapNode({ node, active }) {
7219
+ function MindMapNode({
7220
+ node,
7221
+ active,
7222
+ stateValues = {}
7223
+ }) {
6996
7224
  const x0 = node.cx - node.w / 2;
6997
7225
  const y0 = node.cy - node.h / 2;
6998
- const mindData = node.mindData;
7226
+ const mindData = node.mindData ? resolveMindData(node.mindData, stateValues) : void 0;
6999
7227
  if (!mindData) return /* @__PURE__ */ jsx("g", { transform: `translate(${x0} ${y0})` });
7000
7228
  const PAD = 40;
7001
7229
  const canvasCx = node.w / 2;
@@ -7031,33 +7259,59 @@ function MindMapNode({ node, active }) {
7031
7259
  },
7032
7260
  `edge-${i}`
7033
7261
  )),
7034
- layout2.nodes.map((n) => /* @__PURE__ */ jsxs("g", { children: [
7035
- /* @__PURE__ */ jsx(
7036
- "rect",
7037
- {
7038
- x: n.x - n.w / 2,
7039
- y: n.y - n.h / 2,
7040
- width: n.w,
7041
- height: n.h,
7042
- rx: n.isRoot ? 22 : 10,
7043
- fill: n.isRoot ? toneColor4(n.tone ?? "accent") : "var(--cdl-chip-fill, #f4f6fb)",
7044
- stroke: n.isRoot ? toneColor4(n.tone ?? "accent") : toneColor4(n.tone),
7045
- strokeWidth: n.isRoot ? 2 : 1.75
7046
- }
7047
- ),
7048
- /* @__PURE__ */ jsx(
7049
- "text",
7050
- {
7051
- x: n.x,
7052
- y: n.y + 5,
7053
- fontSize: n.isRoot ? 15 : 13,
7054
- fontWeight: n.isRoot ? 700 : 600,
7055
- textAnchor: "middle",
7056
- fill: n.isRoot ? "var(--cdl-text-on-tone, #ffffff)" : "var(--cdl-chip-text, #1a1f2a)",
7057
- children: n.title
7058
- }
7059
- )
7060
- ] }, `n-${n.id}`))
7262
+ layout2.nodes.map((n) => {
7263
+ const \u884C = \u7BB1\u306B\u7A4D\u3080(
7264
+ [
7265
+ { \u5F79\u5272: "title", text: n.title, fontSize: n.isRoot ? 15 : 13 },
7266
+ { \u5F79\u5272: "subtitle", text: n.subtitle ?? "", fontSize: 9 }
7267
+ ],
7268
+ n.w,
7269
+ n.h
7270
+ );
7271
+ const \u88DC\u8DB3\u3042\u308A = (n.subtitle ?? "").trim() !== "";
7272
+ const \u6587\u5B57\u306E\u8272 = n.isRoot ? "var(--cdl-text-on-tone, #ffffff)" : "var(--cdl-chip-text, #1a1f2a)";
7273
+ return /* @__PURE__ */ jsxs("g", { "data-cdl-unresolved": n.unresolved ? "true" : void 0, children: [
7274
+ /* @__PURE__ */ jsx(
7275
+ "rect",
7276
+ {
7277
+ x: n.x - n.w / 2,
7278
+ y: n.y - n.h / 2,
7279
+ width: n.w,
7280
+ height: n.h,
7281
+ rx: n.isRoot ? 22 : 10,
7282
+ fill: n.isRoot ? toneColor4(n.tone ?? "accent") : "var(--cdl-chip-fill, #f4f6fb)",
7283
+ stroke: n.isRoot ? toneColor4(n.tone ?? "accent") : toneColor4(n.tone),
7284
+ strokeWidth: n.isRoot ? 2 : 1.75
7285
+ }
7286
+ ),
7287
+ \u88DC\u8DB3\u3042\u308A ? \u884C.map((r) => /* @__PURE__ */ jsx(
7288
+ "text",
7289
+ {
7290
+ "data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "mind-node-subtitle" : void 0,
7291
+ x: n.x,
7292
+ y: n.y + r.dy,
7293
+ fontSize: r.fontSize,
7294
+ fontWeight: r.\u5F79\u5272 === "title" ? n.isRoot ? 700 : 600 : 500,
7295
+ textAnchor: "middle",
7296
+ fill: \u6587\u5B57\u306E\u8272,
7297
+ opacity: r.\u5F79\u5272 === "subtitle" ? 0.85 : void 0,
7298
+ children: r.text
7299
+ },
7300
+ r.\u5F79\u5272
7301
+ )) : /* @__PURE__ */ jsx(
7302
+ "text",
7303
+ {
7304
+ x: n.x,
7305
+ y: n.y + 5,
7306
+ fontSize: n.isRoot ? 15 : 13,
7307
+ fontWeight: n.isRoot ? 700 : 600,
7308
+ textAnchor: "middle",
7309
+ fill: \u6587\u5B57\u306E\u8272,
7310
+ children: n.title
7311
+ }
7312
+ )
7313
+ ] }, `n-${n.id}`);
7314
+ })
7061
7315
  ] });
7062
7316
  }
7063
7317
  function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
@@ -7072,7 +7326,8 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
7072
7326
  y: cy,
7073
7327
  w: rootW,
7074
7328
  h: rootH,
7075
- isRoot: true
7329
+ isRoot: true,
7330
+ ...mindData.unresolved ? { unresolved: true } : {}
7076
7331
  });
7077
7332
  const childrenOf = /* @__PURE__ */ new Map();
7078
7333
  for (const br of mindData.branches) {
@@ -7175,7 +7430,18 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
7175
7430
  );
7176
7431
  y = (ys[0] + ys[ys.length - 1]) / 2;
7177
7432
  }
7178
- nodes.push({ id: node.id, title: node.title, x, y, w, h, tone: myTone, isRoot: false });
7433
+ nodes.push({
7434
+ id: node.id,
7435
+ title: node.title,
7436
+ ...node.subtitle !== void 0 ? { subtitle: node.subtitle } : {},
7437
+ x,
7438
+ y,
7439
+ w,
7440
+ h,
7441
+ tone: myTone,
7442
+ isRoot: false,
7443
+ ...node.unresolved ? { unresolved: true } : {}
7444
+ });
7179
7445
  nodePos.set(node.id, { x, y });
7180
7446
  nodeSide.set(node.id, isLeft ? "left" : "right");
7181
7447
  nodeHalfW.set(node.id, w / 2);
@@ -7372,6 +7638,9 @@ function QuadrantNode({
7372
7638
  const PAD_BOTTOM = 56;
7373
7639
  const AXIS_LABEL_FONT = 12;
7374
7640
  const PAD_MIN = 60;
7641
+ const ITEM_FONT = 13;
7642
+ const ITEM_PAD_X = 12;
7643
+ const ITEM_MIN_W = 48;
7375
7644
  const axisLabelPad = (text) => Math.max(PAD_MIN, measureTextWidth(`\u2190 ${text}`, { fontSize: AXIS_LABEL_FONT}) + 12);
7376
7645
  const padBudget = Math.max(0, node.w * 0.5 - PAD_MIN * 2);
7377
7646
  const wantLeft = axisLabelPad(data.xAxis.left) - PAD_MIN;
@@ -7467,6 +7736,12 @@ function QuadrantNode({
7467
7736
  const qxStart = (isLeft ? PAD_LEFT : cx) + 18;
7468
7737
  const qyStart = (isTop ? PAD_TOP : cy) + 44;
7469
7738
  const qHalfW = halfW - 36;
7739
+ const \u67A0\u306E\u4F59\u5730 = qHalfW;
7740
+ if (\u67A0\u306E\u4F59\u5730 <= 0) return null;
7741
+ const \u67A0\u306E\u5E45 = (title) => Math.min(
7742
+ \u67A0\u306E\u4F59\u5730,
7743
+ Math.max(ITEM_MIN_W, measureTextWidth(title, { fontSize: ITEM_FONT}) + ITEM_PAD_X * 2)
7744
+ );
7470
7745
  const qHalfH = halfH - 60;
7471
7746
  const gap = 10;
7472
7747
  const rowH = 34;
@@ -7481,7 +7756,7 @@ function QuadrantNode({
7481
7756
  "data-cdl-unresolved": it.unresolved ? "true" : void 0,
7482
7757
  x: qxStart,
7483
7758
  y: py,
7484
- width: qHalfW,
7759
+ width: \u67A0\u306E\u5E45(it.title),
7485
7760
  height: rowH,
7486
7761
  rx: 6,
7487
7762
  fill: "var(--cdl-node-fill, #ffffff)",
@@ -7489,16 +7764,43 @@ function QuadrantNode({
7489
7764
  strokeWidth: 1.5
7490
7765
  }
7491
7766
  ),
7492
- /* @__PURE__ */ jsx("text", { x: qxStart + 12, y: py + rowH / 2 + 5, fontSize: 13, fontWeight: 600, fill: "var(--cdl-text, #1a1f2a)", children: it.title })
7767
+ /* @__PURE__ */ jsx("text", { x: qxStart + ITEM_PAD_X, y: py + rowH / 2 + 5, fontSize: ITEM_FONT, fontWeight: 600, letterSpacing: 0, fill: "var(--cdl-text, #1a1f2a)", children: it.title })
7493
7768
  ] }, `item-${it.id}`);
7494
7769
  });
7495
7770
  })
7496
7771
  ] });
7497
7772
  }
7498
- function TreeNode({ node, active }) {
7773
+ function \u7BB1\u306E\u6587\u5B57({
7774
+ \u884C,
7775
+ x,
7776
+ \u7BB1\u306E\u9AD8\u3055,
7777
+ fill,
7778
+ \u540D\u524D\u306E\u592A\u3055
7779
+ }) {
7780
+ return \u884C.map((r) => /* @__PURE__ */ jsx(
7781
+ "text",
7782
+ {
7783
+ "data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "tree-node-subtitle" : void 0,
7784
+ x,
7785
+ y: \u7BB1\u306E\u9AD8\u3055 / 2 + r.dy,
7786
+ fontSize: r.fontSize,
7787
+ fontWeight: r.\u5F79\u5272 === "title" ? \u540D\u524D\u306E\u592A\u3055 : 500,
7788
+ textAnchor: "middle",
7789
+ fill,
7790
+ opacity: r.\u5F79\u5272 === "subtitle" ? 0.85 : void 0,
7791
+ children: r.text
7792
+ },
7793
+ r.\u5F79\u5272
7794
+ ));
7795
+ }
7796
+ function TreeNode({
7797
+ node,
7798
+ active,
7799
+ stateValues = {}
7800
+ }) {
7499
7801
  const x0 = node.cx - node.w / 2;
7500
7802
  const y0 = node.cy - node.h / 2;
7501
- const treeNodes = node.treeData ?? [];
7803
+ const treeNodes = resolveTreeData(node.treeData ?? [], stateValues);
7502
7804
  const gradientId = `tree-root-grad-${node.id}`;
7503
7805
  const PAD_TOP = 40;
7504
7806
  const PAD_RIGHT = 24;
@@ -7553,60 +7855,89 @@ function TreeNode({ node, active }) {
7553
7855
  layout2.nodes.map((n) => {
7554
7856
  const accent = depthColors[Math.min(n.depth, depthColors.length - 1)] ?? depthColors[0];
7555
7857
  const isRoot = n.depth === 0;
7556
- return /* @__PURE__ */ jsx("g", { transform: `translate(${PAD_LEFT + n.x - n.w / 2} ${PAD_TOP + n.y - n.h / 2})`, children: isRoot ? /* @__PURE__ */ jsxs(Fragment, { children: [
7557
- /* @__PURE__ */ jsx(
7558
- "rect",
7559
- {
7560
- "data-cdl-role": "tree-node",
7561
- x: 0,
7562
- y: 0,
7563
- width: n.w,
7564
- height: n.h,
7565
- rx: 12,
7566
- fill: `url(#${gradientId})`
7567
- }
7568
- ),
7569
- /* @__PURE__ */ jsx(
7570
- "text",
7571
- {
7572
- x: n.w / 2,
7573
- y: n.h / 2 + 5,
7574
- fontSize: 13,
7575
- fontWeight: 700,
7576
- textAnchor: "middle",
7577
- fill: "var(--cdl-text-on-tone, #ffffff)",
7578
- children: n.title
7579
- }
7580
- )
7581
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7582
- /* @__PURE__ */ jsx(
7583
- "rect",
7584
- {
7585
- "data-cdl-role": "tree-node",
7586
- x: 0,
7587
- y: 0,
7588
- width: n.w,
7589
- height: n.h,
7590
- rx: 9,
7591
- fill: "var(--cdl-chip-fill, #f4f6fb)",
7592
- stroke: accent,
7593
- strokeWidth: 1.5
7594
- }
7595
- ),
7596
- /* @__PURE__ */ jsx("rect", { x: 0, y: 0, width: 4, height: n.h, rx: 2, fill: accent }),
7597
- /* @__PURE__ */ jsx(
7598
- "text",
7599
- {
7600
- x: n.w / 2 + 2,
7601
- y: n.h / 2 + 4,
7602
- fontSize: 12,
7603
- fontWeight: 600,
7604
- textAnchor: "middle",
7605
- fill: "var(--cdl-chip-text, #1a1f2a)",
7606
- children: n.title
7607
- }
7608
- )
7609
- ] }) }, `n-${n.id}`);
7858
+ const \u884C = \u7BB1\u306B\u7A4D\u3080(
7859
+ [
7860
+ { \u5F79\u5272: "title", text: n.title, fontSize: isRoot ? 13 : 12 },
7861
+ { \u5F79\u5272: "subtitle", text: n.subtitle ?? "", fontSize: 9 }
7862
+ ],
7863
+ n.w,
7864
+ n.h
7865
+ );
7866
+ const \u88DC\u8DB3\u3042\u308A = (n.subtitle ?? "").trim() !== "";
7867
+ return /* @__PURE__ */ jsx(
7868
+ "g",
7869
+ {
7870
+ "data-cdl-unresolved": n.unresolved ? "true" : void 0,
7871
+ transform: `translate(${PAD_LEFT + n.x - n.w / 2} ${PAD_TOP + n.y - n.h / 2})`,
7872
+ children: isRoot ? /* @__PURE__ */ jsxs(Fragment, { children: [
7873
+ /* @__PURE__ */ jsx(
7874
+ "rect",
7875
+ {
7876
+ "data-cdl-role": "tree-node",
7877
+ x: 0,
7878
+ y: 0,
7879
+ width: n.w,
7880
+ height: n.h,
7881
+ rx: 12,
7882
+ fill: `url(#${gradientId})`
7883
+ }
7884
+ ),
7885
+ \u88DC\u8DB3\u3042\u308A ? \u7BB1\u306E\u6587\u5B57({
7886
+ \u884C,
7887
+ x: n.w / 2,
7888
+ \u7BB1\u306E\u9AD8\u3055: n.h,
7889
+ fill: "var(--cdl-text-on-tone, #ffffff)",
7890
+ \u540D\u524D\u306E\u592A\u3055: 700
7891
+ }) : /* @__PURE__ */ jsx(
7892
+ "text",
7893
+ {
7894
+ x: n.w / 2,
7895
+ y: n.h / 2 + 5,
7896
+ fontSize: 13,
7897
+ fontWeight: 700,
7898
+ textAnchor: "middle",
7899
+ fill: "var(--cdl-text-on-tone, #ffffff)",
7900
+ children: n.title
7901
+ }
7902
+ )
7903
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7904
+ /* @__PURE__ */ jsx(
7905
+ "rect",
7906
+ {
7907
+ "data-cdl-role": "tree-node",
7908
+ x: 0,
7909
+ y: 0,
7910
+ width: n.w,
7911
+ height: n.h,
7912
+ rx: 9,
7913
+ fill: "var(--cdl-chip-fill, #f4f6fb)",
7914
+ stroke: accent,
7915
+ strokeWidth: 1.5
7916
+ }
7917
+ ),
7918
+ /* @__PURE__ */ jsx("rect", { x: 0, y: 0, width: 4, height: n.h, rx: 2, fill: accent }),
7919
+ \u88DC\u8DB3\u3042\u308A ? \u7BB1\u306E\u6587\u5B57({
7920
+ \u884C,
7921
+ x: n.w / 2 + 2,
7922
+ \u7BB1\u306E\u9AD8\u3055: n.h,
7923
+ fill: "var(--cdl-chip-text, #1a1f2a)",
7924
+ \u540D\u524D\u306E\u592A\u3055: 600
7925
+ }) : /* @__PURE__ */ jsx(
7926
+ "text",
7927
+ {
7928
+ x: n.w / 2 + 2,
7929
+ y: n.h / 2 + 4,
7930
+ fontSize: 12,
7931
+ fontWeight: 600,
7932
+ textAnchor: "middle",
7933
+ fill: "var(--cdl-chip-text, #1a1f2a)",
7934
+ children: n.title
7935
+ }
7936
+ )
7937
+ ] })
7938
+ },
7939
+ `n-${n.id}`
7940
+ );
7610
7941
  })
7611
7942
  ] });
7612
7943
  }
@@ -7669,7 +8000,17 @@ function computeTreeLayout(treeNodes, canvasW, canvasH) {
7669
8000
  }
7670
8001
  const y = depth * depthGap + depthGap / 2;
7671
8002
  posOf.set(n.id, { x, y });
7672
- nodes.push({ id: n.id, title: n.title, x, y, w: nodeW, h: nodeH, depth });
8003
+ nodes.push({
8004
+ id: n.id,
8005
+ title: n.title,
8006
+ ...n.subtitle !== void 0 ? { subtitle: n.subtitle } : {},
8007
+ x,
8008
+ y,
8009
+ w: nodeW,
8010
+ h: nodeH,
8011
+ depth,
8012
+ ...n.unresolved ? { unresolved: true } : {}
8013
+ });
7673
8014
  return x;
7674
8015
  };
7675
8016
  for (const r of roots) if (!placed.has(r.id)) place(r, 0);
@@ -7953,42 +8294,106 @@ var BOTTOM_PAD = 4;
7953
8294
  var ASCENT2 = 0.72;
7954
8295
  var DESCENT2 = 0.25;
7955
8296
  var ART_GAP = 4;
8297
+ var ART_MIN_BAND = 45;
8298
+ var \u843D\u3068\u3057\u3066\u3082\u63CF\u304F\u7A2E\u5225 = {
8299
+ \u80A9\u66F8: /* @__PURE__ */ new Set([
8300
+ // basement 系 = `commonLabel` が自前の帯に置く
8301
+ "shape-file",
8302
+ "shape-folder",
8303
+ "shape-cloud",
8304
+ "shape-cylinder",
8305
+ "shape-hexagon",
8306
+ "shape-diamond",
8307
+ "shape-stack",
8308
+ // software 系 = 固有 layout
8309
+ "shape-window",
8310
+ "shape-terminal",
8311
+ "shape-code-block",
8312
+ "shape-message-bubble",
8313
+ "shape-gear",
8314
+ // hardware 系のうち固有 layout を持つもの
8315
+ "shape-iot-sensor",
8316
+ "shape-robot-arm"
8317
+ ]),
8318
+ \u8AAC\u660E: /* @__PURE__ */ new Set([
8319
+ // basement 系 = `commonLabel` が自前の帯に置く
8320
+ "shape-file",
8321
+ "shape-folder",
8322
+ "shape-cloud",
8323
+ "shape-cylinder",
8324
+ "shape-hexagon",
8325
+ "shape-diamond",
8326
+ "shape-stack",
8327
+ // software 系 = 固有 layout
8328
+ "shape-window",
8329
+ "shape-message-bubble",
8330
+ "shape-gear",
8331
+ // hardware / blockchain 系のうち固有 layout を持つもの
8332
+ "shape-iot-sensor",
8333
+ "shape-robot-arm",
8334
+ "shape-blockchain-block"
8335
+ ])
8336
+ };
8337
+ function droppedLineIsHidden(kind, line) {
8338
+ return kind.startsWith("shape-") && !\u843D\u3068\u3057\u3066\u3082\u63CF\u304F\u7A2E\u5225[line].has(kind);
8339
+ }
7956
8340
  function labelPlan(node) {
7957
8341
  const \u9AD8\u3055 = Math.max(0, node.h);
7958
8342
  const \u5E95 = node.cy + \u9AD8\u3055 / 2;
7959
8343
  const \u5929 = node.cy - \u9AD8\u3055 / 2;
7960
- const \u7A4D\u3080 = (\u540D\u524D\u59272, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D2) => {
7961
- const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(\u540D\u524D\u59272 * SUB_RATIO));
7962
- let y = \u5E95 - \u4E0B\u4F59\u767D2;
7963
- const \u8AAC\u660E = \u8AAC\u660E\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B572 } : null;
7964
- if (\u8AAC\u660E !== null) y -= \u5C0F\u3055\u3044\u5B572 + LINE_GAP;
7965
- const \u540D\u524D = { y, size: \u540D\u524D\u59272 };
7966
- y -= \u540D\u524D\u59272 + LINE_GAP;
7967
- const \u80A9\u66F8 = \u80A9\u66F8\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B572 } : null;
8344
+ const \u7A4D\u3080 = (\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D) => {
8345
+ const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
8346
+ let y = \u5E95 - \u4E0B\u4F59\u767D;
8347
+ const \u8AAC\u660E = \u8AAC\u660E\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B57 } : null;
8348
+ if (\u8AAC\u660E !== null) y -= \u5C0F\u3055\u3044\u5B57 + LINE_GAP;
8349
+ const \u540D\u524D = { y, size: \u540D\u524D\u5927 };
8350
+ y -= \u540D\u524D\u5927 + LINE_GAP;
8351
+ const \u80A9\u66F8 = \u80A9\u66F8\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B57 } : null;
7968
8352
  const \u4E0A\u306E\u884C = \u80A9\u66F8 ?? \u540D\u524D;
7969
8353
  return { \u540D\u524D, \u8AAC\u660E, \u80A9\u66F8, \u4E0A\u7AEF: \u4E0A\u306E\u884C.y - \u4E0A\u306E\u884C.size * ASCENT2 };
7970
8354
  };
7971
8355
  const \u5165\u308B = (\u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2) => \u7A4D\u3080(1, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, 1 * DESCENT2).\u4E0A\u7AEF >= \u5929;
7972
8356
  let \u8AAC\u660E\u3042\u308A = Boolean(node.subtitle);
7973
8357
  let \u80A9\u66F8\u3042\u308A = Boolean(node.eyebrow);
7974
- if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A)) \u80A9\u66F8\u3042\u308A = false;
7975
- if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A)) \u8AAC\u660E\u3042\u308A = false;
7976
- const \u4E0A\u9650 = Math.min(TITLE_MAX, Math.max(1, Math.round(\u9AD8\u3055 * TITLE_RATIO)));
7977
- let \u540D\u524D\u5927 = 0;
7978
- for (let size = \u4E0A\u9650; size >= 1; size--) {
7979
- const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(size * SUB_RATIO));
7980
- const \u4E0B\u306E\u884C\u5927 = \u8AAC\u660E\u3042\u308A ? \u5C0F\u3055\u3044\u5B572 : size;
7981
- if (\u7A4D\u3080(size, \u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A, \u4E0B\u306E\u884C\u5927 * DESCENT2).\u4E0A\u7AEF >= \u5929) {
7982
- \u540D\u524D\u5927 = size;
7983
- break;
7984
- }
8358
+ const \u843D\u3068\u3057\u305F = [];
8359
+ if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A) && \u80A9\u66F8\u3042\u308A) {
8360
+ \u80A9\u66F8\u3042\u308A = false;
8361
+ \u843D\u3068\u3057\u305F.push("\u80A9\u66F8");
8362
+ }
8363
+ if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A) && \u8AAC\u660E\u3042\u308A) {
8364
+ \u8AAC\u660E\u3042\u308A = false;
8365
+ \u843D\u3068\u3057\u305F.push("\u8AAC\u660E");
8366
+ }
8367
+ const \u7D44\u3080 = (\u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2) => {
8368
+ const \u4E0A\u9650 = Math.min(TITLE_MAX, Math.max(1, Math.round(\u9AD8\u3055 * TITLE_RATIO)));
8369
+ let \u540D\u524D\u5927 = 0;
8370
+ for (let size = \u4E0A\u9650; size >= 1; size--) {
8371
+ const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(size * SUB_RATIO));
8372
+ const \u4E0B\u306E\u884C\u5927 = \u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B572 : size;
8373
+ if (\u7A4D\u3080(size, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u306E\u884C\u5927 * DESCENT2).\u4E0A\u7AEF >= \u5929) {
8374
+ \u540D\u524D\u5927 = size;
8375
+ break;
8376
+ }
8377
+ }
8378
+ if (\u540D\u524D\u5927 === 0) \u540D\u524D\u5927 = \u9AD8\u3055 / (ASCENT2 + DESCENT2);
8379
+ const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
8380
+ const \u5F35\u308A\u51FA\u3057 = (\u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B57 : \u540D\u524D\u5927) * DESCENT2;
8381
+ const \u4F59\u308A = Math.max(0, \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u5F35\u308A\u51FA\u3057).\u4E0A\u7AEF - \u5929);
8382
+ const \u4E0B\u4F59\u767D = Math.min(Math.max(BOTTOM_PAD, \u5F35\u308A\u51FA\u3057), \u5F35\u308A\u51FA\u3057 + \u4F59\u308A);
8383
+ return \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D);
8384
+ };
8385
+ const \u7D75\u306E\u5E2F = (\u7D442) => Math.max(0, \u7D442.\u4E0A\u7AEF - ART_GAP - \u5929);
8386
+ let \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
8387
+ if (\u7D75\u306E\u5E2F(\u7D44) < ART_MIN_BAND && \u80A9\u66F8\u3042\u308A) {
8388
+ \u80A9\u66F8\u3042\u308A = false;
8389
+ \u843D\u3068\u3057\u305F.push("\u80A9\u66F8");
8390
+ \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
8391
+ }
8392
+ if (\u7D75\u306E\u5E2F(\u7D44) < ART_MIN_BAND && \u8AAC\u660E\u3042\u308A) {
8393
+ \u8AAC\u660E\u3042\u308A = false;
8394
+ \u843D\u3068\u3057\u305F.push("\u8AAC\u660E");
8395
+ \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
7985
8396
  }
7986
- if (\u540D\u524D\u5927 === 0) \u540D\u524D\u5927 = \u9AD8\u3055 / (ASCENT2 + DESCENT2);
7987
- const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
7988
- const \u5F35\u308A\u51FA\u3057 = (\u8AAC\u660E\u3042\u308A ? \u5C0F\u3055\u3044\u5B57 : \u540D\u524D\u5927) * DESCENT2;
7989
- const \u4F59\u308A = Math.max(0, \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A, \u5F35\u308A\u51FA\u3057).\u4E0A\u7AEF - \u5929);
7990
- const \u4E0B\u4F59\u767D = Math.min(Math.max(BOTTOM_PAD, \u5F35\u308A\u51FA\u3057), \u5F35\u308A\u51FA\u3057 + \u4F59\u308A);
7991
- const \u7D44 = \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A, \u4E0B\u4F59\u767D);
7992
8397
  const \u4E00\u756A\u5C0F\u3055\u3044\u884C = Math.min(
7993
8398
  ...[\u7D44.\u540D\u524D, \u7D44.\u8AAC\u660E, \u7D44.\u80A9\u66F8].filter((l) => l !== null).map((l) => l.size)
7994
8399
  );
@@ -7997,7 +8402,8 @@ function labelPlan(node) {
7997
8402
  \u8AAC\u660E: \u7D44.\u8AAC\u660E,
7998
8403
  \u80A9\u66F8: \u7D44.\u80A9\u66F8,
7999
8404
  top: \u7D44.\u4E0A\u7AEF,
8000
- \u8AAD\u3081\u308B: \u4E00\u756A\u5C0F\u3055\u3044\u884C >= TITLE_MIN
8405
+ \u8AAD\u3081\u308B: \u4E00\u756A\u5C0F\u3055\u3044\u884C >= TITLE_MIN,
8406
+ \u843D\u3068\u3057\u305F
8001
8407
  };
8002
8408
  }
8003
8409
  function shapeRegion(node) {
@@ -10265,6 +10671,15 @@ function ShapeSmartContractNode({ node, active }) {
10265
10671
  bottomLabel2(node, r.cx, r.label)
10266
10672
  ] });
10267
10673
  }
10674
+ var \u5B57\u306E\u5E45 = (text, size) => Math.max(displayWidth(text) * size * MONO_ADVANCE_RATIO, textWidth(text, size));
10675
+ var BLOCK_DEFAULT_FIELDS = [
10676
+ { label: "hash", value: "0xaf31c9d2..." },
10677
+ { label: "prev", value: "0x7b3f92c1..." },
10678
+ { label: "merkle", value: "0xc1892f4a..." },
10679
+ { label: "nonce", value: "82,914" },
10680
+ { label: "tx", value: "142 tx" }
10681
+ ];
10682
+ var BLOCK_DEFAULT_TITLE = "Block #421,873";
10268
10683
  function ShapeBlockchainBlockNode({ node, active }) {
10269
10684
  const frame = commonFrame4(active);
10270
10685
  const r = shapeRegion(node);
@@ -10274,21 +10689,22 @@ function ShapeBlockchainBlockNode({ node, active }) {
10274
10689
  const cy = r.cy;
10275
10690
  const x = cx - bw / 2;
10276
10691
  const y = cy - bh / 2;
10692
+ const \u6E21\u3055\u308C\u305F = (v) => (v ?? "").trim();
10693
+ const \u898B\u51FA\u3057 = \u6E21\u3055\u308C\u305F(node.title) || BLOCK_DEFAULT_TITLE;
10694
+ const fields = BLOCK_DEFAULT_FIELDS.map((f) => ({
10695
+ label: f.label,
10696
+ value: f.label === "hash" ? \u6E21\u3055\u308C\u305F(node.subtitle) || f.value : f.value
10697
+ }));
10698
+ const \u898B\u51FA\u3057\u306E\u5E45 = bw - 14 - 30;
10277
10699
  const art = /* @__PURE__ */ jsxs("g", { children: [
10278
10700
  /* @__PURE__ */ jsx("rect", { x: x + 6, y: y + 6, width: bw, height: bh, rx: 8, fill: frame.stroke, opacity: 0.2, stroke: "none" }),
10279
10701
  /* @__PURE__ */ jsx("rect", { "data-cdl-role": "node-body", x, y, width: bw, height: bh, rx: 8, ...frame }),
10280
10702
  /* @__PURE__ */ jsx("path", { d: `M ${x} ${y + 32} L ${x} ${y + 8} Q ${x} ${y}, ${x + 8} ${y} L ${x + bw - 8} ${y} Q ${x + bw} ${y}, ${x + bw} ${y + 8} L ${x + bw} ${y + 32} Z`, fill: "var(--cdl-tone-accent, #2d6a8f)", fillOpacity: 0.9, stroke: "none" }),
10281
- /* @__PURE__ */ jsx("text", { x: x + 14, y: y + 22, fontSize: 13, fontWeight: 700, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fill: "#ffffff", children: "Block #421,873" }),
10703
+ /* @__PURE__ */ jsx("text", { "data-cdl-role": "blockchain-block-title", x: x + 14, y: y + 22, fontSize: 13, fontWeight: 700, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fill: "#ffffff", children: \u5E45\u3067\u5207\u308B(\u898B\u51FA\u3057, 13, \u898B\u51FA\u3057\u306E\u5E45, \u5B57\u306E\u5E45) }),
10282
10704
  /* @__PURE__ */ jsx("circle", { cx: x + bw - 16, cy: y + 16, r: 5.5, fill: "#7cd88f", stroke: "#ffffff", strokeWidth: 1.5 }),
10283
- [
10284
- { label: "hash", value: "0xaf31c9d2..." },
10285
- { label: "prev", value: "0x7b3f92c1..." },
10286
- { label: "merkle", value: "0xc1892f4a..." },
10287
- { label: "nonce", value: "82,914" },
10288
- { label: "tx", value: "142 tx" }
10289
- ].map((f, i) => /* @__PURE__ */ jsxs("g", { children: [
10705
+ fields.map((f, i) => /* @__PURE__ */ jsxs("g", { children: [
10290
10706
  /* @__PURE__ */ jsx("text", { x: x + 14, y: y + 54 + i * 22, fontSize: 10.5, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fill: "var(--cdl-text-dim, #5a6270)", children: f.label }),
10291
- /* @__PURE__ */ jsx("text", { x: x + bw - 14, y: y + 54 + i * 22, fontSize: 11, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontWeight: 600, textAnchor: "end", fill: "var(--cdl-text, #1a1f2a)", children: f.value }),
10707
+ /* @__PURE__ */ jsx("text", { "data-cdl-role": `blockchain-block-${f.label}`, x: x + bw - 14, y: y + 54 + i * 22, fontSize: 11, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontWeight: 600, textAnchor: "end", fill: "var(--cdl-text, #1a1f2a)", children: \u5E45\u3067\u5207\u308B(f.value, 11, bw - 28 - \u5B57\u306E\u5E45(f.label, 10.5) - 8, \u5B57\u306E\u5E45) }),
10292
10708
  /* @__PURE__ */ jsx("line", { x1: x + 14, y1: y + 60 + i * 22, x2: x + bw - 14, y2: y + 60 + i * 22, stroke: "var(--cdl-divider, #d4d4d8)", strokeWidth: 0.5, opacity: 0.5 })
10293
10709
  ] }, i)),
10294
10710
  /* @__PURE__ */ jsxs("g", { transform: `translate(${cx - 32}, ${y + bh - 26})`, children: [
@@ -11818,9 +12234,10 @@ function CdlNodeView({
11818
12234
  return /* @__PURE__ */ jsx(EventNode, { node: resolvedNode, active, progress });
11819
12235
  case "card":
11820
12236
  return /* @__PURE__ */ jsx(CardNode, { node: resolvedNode, active });
11821
- // 図表 7 種は payload の数と語が `{signal}` を取れるので stateValues を渡す
11822
- // (`render/payload-binding.ts` が描画直前に解決する)。 動かさない 2 種
11823
- // (mind-map / tree-hierarchy) は構造だけを持つため渡さない。
12237
+ // 図表 9 種は payload `{signal}` を取れるので stateValues を渡す
12238
+ // (`render/payload-binding.ts` が描画直前に解決する)。 取れる欄は種別で違い、
12239
+ // 数と語を取る 7 種に対し、mind-map / tree-hierarchy は **名前だけ** を取る (#467)
12240
+ // 親子の繋がりと、描かれない欄 (補足) は解決しない。
11824
12241
  case "chart-line":
11825
12242
  return /* @__PURE__ */ jsx(ChartLineNode, { node: resolvedNode, active, stateValues });
11826
12243
  case "chart-pie":
@@ -11830,13 +12247,13 @@ function CdlNodeView({
11830
12247
  case "gantt-timeline":
11831
12248
  return /* @__PURE__ */ jsx(GanttNode, { node: resolvedNode, active, stateValues });
11832
12249
  case "mind-map":
11833
- return /* @__PURE__ */ jsx(MindMapNode, { node: resolvedNode, active });
12250
+ return /* @__PURE__ */ jsx(MindMapNode, { node: resolvedNode, active, stateValues });
11834
12251
  case "funnel-stages":
11835
12252
  return /* @__PURE__ */ jsx(FunnelNode, { node: resolvedNode, active, stateValues });
11836
12253
  case "quadrant-matrix":
11837
12254
  return /* @__PURE__ */ jsx(QuadrantNode, { node: resolvedNode, active, stateValues });
11838
12255
  case "tree-hierarchy":
11839
- return /* @__PURE__ */ jsx(TreeNode, { node: resolvedNode, active });
12256
+ return /* @__PURE__ */ jsx(TreeNode, { node: resolvedNode, active, stateValues });
11840
12257
  case "journey-map":
11841
12258
  return /* @__PURE__ */ jsx(UserJourneyNode, { node: resolvedNode, active, stateValues });
11842
12259
  case "shape-file":
@@ -11983,6 +12400,29 @@ function CdlNodeView({
11983
12400
  }
11984
12401
  );
11985
12402
  }
12403
+
12404
+ // src/layout/lifeline.ts
12405
+ function lifelineStartYs(nodes) {
12406
+ const topmost = /* @__PURE__ */ new Map();
12407
+ for (const n of nodes) {
12408
+ const cur = topmost.get(n.lane);
12409
+ if (cur === void 0 || n.cy < cur.cy) topmost.set(n.lane, n);
12410
+ }
12411
+ const starts = /* @__PURE__ */ new Map();
12412
+ for (const [laneId, n] of topmost) starts.set(laneId, n.cy + n.h / 2);
12413
+ return starts;
12414
+ }
12415
+ function uniformLifelineEndY(lanes, nodes, starts = lifelineStartYs(nodes)) {
12416
+ const lifelineLanes = lanes.filter((l) => l.lifeline);
12417
+ let deepestStart = Number.NEGATIVE_INFINITY;
12418
+ for (const lane of lifelineLanes) {
12419
+ const start = starts.get(lane.id);
12420
+ if (start !== void 0) deepestStart = Math.max(deepestStart, start);
12421
+ }
12422
+ const footerTops = lifelineFooterNodes(lanes, nodes).map((f) => footerShapeDrawTop(f)).filter((top) => top > deepestStart);
12423
+ if (footerTops.length > 0) return Math.min(...footerTops);
12424
+ return lifelineLanes[0] ? lifelineLanes[0].y + lifelineLanes[0].height : 0;
12425
+ }
11986
12426
  function CdlStage({
11987
12427
  laid,
11988
12428
  currentPhase,
@@ -11993,15 +12433,13 @@ function CdlStage({
11993
12433
  svgRef
11994
12434
  }) {
11995
12435
  const activeSet = new Set(currentPhase?.activate ?? []);
11996
- const lifelineLanes = laid.lanes.filter((l) => l.lifeline);
11997
- const { footerTops, footerDropById } = useMemo(() => {
11998
- const footers = lifelineFooterNodes(laid.lanes, laid.nodes);
12436
+ const { lifelineStarts, uniformFooterTop } = useMemo(() => {
12437
+ const starts = lifelineStartYs(laid.nodes);
11999
12438
  return {
12000
- footerTops: footers.map((f) => f.cy - f.h / 2),
12001
- footerDropById: footerShapeDropsOf(footers)
12439
+ lifelineStarts: starts,
12440
+ uniformFooterTop: uniformLifelineEndY(laid.lanes, laid.nodes, starts)
12002
12441
  };
12003
12442
  }, [laid]);
12004
- const uniformFooterTop = footerTops.length > 0 ? Math.min(...footerTops) : lifelineLanes[0] ? lifelineLanes[0].y + lifelineLanes[0].height : 0;
12005
12443
  const diagramScale = laid.diagramScale ?? 1;
12006
12444
  return /* @__PURE__ */ jsxs("div", { className: compact ? "px-3 py-3" : "px-6 py-6", style: compact ? void 0 : { minHeight: 460 }, children: [
12007
12445
  /* @__PURE__ */ jsxs(
@@ -12088,11 +12526,8 @@ function CdlStage({
12088
12526
  }
12089
12527
  ),
12090
12528
  lane.lifeline && (() => {
12091
- const laneNodes = laid.nodes.filter((n) => n.lane === lane.id);
12092
- if (laneNodes.length === 0) return null;
12093
- const sortedByCy = laneNodes.slice().sort((a, b) => a.cy - b.cy);
12094
- const header = sortedByCy[0];
12095
- const y1 = header.cy + header.h / 2;
12529
+ const y1 = lifelineStarts.get(lane.id);
12530
+ if (y1 === void 0) return null;
12096
12531
  const y2 = uniformFooterTop;
12097
12532
  if (y2 <= y1) return null;
12098
12533
  return /* @__PURE__ */ jsx(
@@ -12139,8 +12574,7 @@ function CdlStage({
12139
12574
  currentPhaseId: currentPhase?.id
12140
12575
  }
12141
12576
  );
12142
- const dy = footerDropById.get(node.id);
12143
- return dy === void 0 ? /* @__PURE__ */ jsx("g", { children: view }, node.id) : /* @__PURE__ */ jsx("g", { transform: `translate(0, ${dy})`, children: view }, node.id);
12577
+ return /* @__PURE__ */ jsx("g", { children: view }, node.id);
12144
12578
  }),
12145
12579
  laid.edges.filter((edge) => Boolean(edge.dThrough)).map((edge) => /* @__PURE__ */ jsx(CdlEdgeGlowView, { edge, active: activeSet.has(edge.id) }, `glow-${edge.id}`)),
12146
12580
  laid.edges.map((edge) => /* @__PURE__ */ jsx(
@@ -21022,6 +21456,7 @@ function emptyCounts() {
21022
21456
  "validate-performance-budget": 0,
21023
21457
  "node-inside-viewbox": 0,
21024
21458
  "node-inside-lane": 0,
21459
+ "shape-label-dropped": 0,
21025
21460
  "edge-inside-viewbox": 0,
21026
21461
  "lane-label-inside-viewbox": 0,
21027
21462
  "lane-label-overlap": 0,
@@ -21675,6 +22110,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
21675
22110
  for (const n of laid.nodes) {
21676
22111
  if (n.id.endsWith("-spacer")) continue;
21677
22112
  if (!rendersTitleText(n.kind)) continue;
22113
+ if (fitsOwnTitleWidth(n.kind)) continue;
21678
22114
  if (!isRenderedNode(n)) continue;
21679
22115
  const titleTrimmed = n.title?.trim() ?? "";
21680
22116
  if (!titleTrimmed) continue;
@@ -21931,6 +22367,15 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
21931
22367
  );
21932
22368
  }
21933
22369
  }
22370
+ for (const n of laid.nodes) {
22371
+ const \u843D\u3068\u3057\u305F = labelPlan(n).\u843D\u3068\u3057\u305F.filter((line) => droppedLineIsHidden(n.kind, line));
22372
+ if (\u843D\u3068\u3057\u305F.length === 0) continue;
22373
+ push(
22374
+ "shape-label-dropped",
22375
+ `node "${n.id}" (${n.kind}, ${n.w.toFixed(0)}x${n.h.toFixed(0)}) \u306F\u66F8\u3044\u305F ${\u843D\u3068\u3057\u305F.join(" / ")} \u304C\u63CF\u304B\u308C\u306A\u3044\u3002 \u7BB1\u3092\u9AD8\u304F\u3059\u308B\u304B\u3001 \u305D\u306E\u884C\u3092\u6D88\u3059`,
22376
+ "warn"
22377
+ );
22378
+ }
21934
22379
  for (const e of laid.edges) {
21935
22380
  const segs = flattenPathSegments(extractPathSegments(e.d));
21936
22381
  if (segs.length === 0) continue;
@@ -23120,14 +23565,7 @@ function CdlDiagramView({ diagram, laid: laidProp, hideHeader = false, hideMiniP
23120
23565
  );
23121
23566
  const stateValues = useMemo(() => {
23122
23567
  if (!isInteractive) return baseStateValues;
23123
- const merged = { ...baseStateValues };
23124
- for (const key of Object.keys(interactive.stateOverrides)) {
23125
- const v = interactive.stateOverrides[key];
23126
- if (typeof v === "number" || typeof v === "string" || typeof v === "boolean") {
23127
- merged[key] = String(v);
23128
- }
23129
- }
23130
- return merged;
23568
+ return mergeStateValues(baseStateValues, interactive.stateOverrides);
23131
23569
  }, [isInteractive, baseStateValues, interactive.stateOverrides]);
23132
23570
  return /* @__PURE__ */ jsxs(
23133
23571
  "div",