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