@cardenelabs/cdl 0.7.0 → 0.10.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 (45) hide show
  1. package/CHANGELOG.md +446 -0
  2. package/SPEC.md +42 -18
  3. package/dist/index.cjs +793 -347
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +73 -14
  6. package/dist/index.d.ts +73 -14
  7. package/dist/index.js +793 -347
  8. package/dist/index.js.map +1 -1
  9. package/dist/react.cjs +658 -236
  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 +658 -236
  14. package/dist/react.js.map +1 -1
  15. package/dist/{render-DquCvgOB.d.cts → render-CH1Qn3Jv.d.cts} +47 -2
  16. package/dist/{render-DquCvgOB.d.ts → render-CH1Qn3Jv.d.ts} +47 -2
  17. package/package.json +6 -3
  18. package/src/builder.ts +13 -1
  19. package/src/kinds/box-lines.ts +120 -0
  20. package/src/kinds/chart-line.tsx +94 -25
  21. package/src/kinds/gantt.tsx +152 -24
  22. package/src/kinds/mind-map.tsx +50 -12
  23. package/src/kinds/quadrant.tsx +28 -2
  24. package/src/kinds/shape-blockchain.tsx +65 -12
  25. package/src/kinds/shape-region.tsx +152 -34
  26. package/src/kinds/tree.tsx +92 -20
  27. package/src/layout/collisions.ts +10 -2
  28. package/src/layout/footer-shape.ts +86 -24
  29. package/src/layout/lifeline.ts +80 -0
  30. package/src/layout/spec.ts +21 -2
  31. package/src/layout/text-width.ts +92 -4
  32. package/src/layout/viewbox.ts +0 -8
  33. package/src/layout.ts +8 -1
  34. package/src/presets.ts +120 -22
  35. package/src/render/header.tsx +3 -1
  36. package/src/render/nodes.tsx +15 -1
  37. package/src/render/payload-binding.ts +31 -8
  38. package/src/render/stage.tsx +21 -34
  39. package/src/render/template-fields.ts +212 -0
  40. package/src/render/utils.ts +32 -2
  41. package/src/render.tsx +2 -9
  42. package/src/types.ts +47 -2
  43. package/src/validate.ts +45 -13
  44. package/src/visual-validate.ts +34 -1
  45. package/src/layout/label-shift.ts +0 -28
package/dist/index.js CHANGED
@@ -9361,6 +9361,10 @@ function makePhaseBuilder(acc) {
9361
9361
  acc.activate.push(...ids);
9362
9362
  return api;
9363
9363
  },
9364
+ draw(...ids) {
9365
+ acc.draw.push(...ids);
9366
+ return api;
9367
+ },
9364
9368
  tween(stateId, from, to) {
9365
9369
  acc.tweens.push({ stateId, from, to });
9366
9370
  return api;
@@ -11440,7 +11444,7 @@ function diagram(id, options) {
11440
11444
  }
11441
11445
  },
11442
11446
  phase(phaseId, opts, build) {
11443
- const acc = { activate: [], tweens: [], sets: [] };
11447
+ const acc = { activate: [], draw: [], tweens: [], sets: [] };
11444
11448
  build(makePhaseBuilder(acc));
11445
11449
  phases.push({
11446
11450
  id: phaseId,
@@ -11448,6 +11452,8 @@ function diagram(id, options) {
11448
11452
  title: opts.title,
11449
11453
  body: opts.body,
11450
11454
  activate: acc.activate,
11455
+ // 空なら欄ごと置かない。 置くと `draw` を使わない図の JSON の形が変わる
11456
+ ...acc.draw.length > 0 ? { draw: acc.draw } : {},
11451
11457
  tweens: acc.tweens,
11452
11458
  sets: acc.sets,
11453
11459
  badge: acc.badge
@@ -11603,7 +11609,35 @@ function isCJK(code) {
11603
11609
  function isHalfwidthKana(code) {
11604
11610
  return code >= 65377 && code <= 65500;
11605
11611
  }
11612
+ var EMOJI_ADVANCE_EM = 1.05;
11613
+ var MONO_EMOJI_ADVANCE_EM = 1.16;
11614
+ var WIDE_SYMBOL_ADVANCE_EM = 0.95;
11615
+ function isEmoji(code) {
11616
+ return code >= 126976 && code <= 129791 || // 絵文字の主要面
11617
+ code >= 9728 && code <= 10175 || // 記号と絵文字 (♻ ✅ ❤ 等)
11618
+ code >= 127462 && code <= 127487;
11619
+ }
11620
+ function isEmojiGrapheme(grapheme, firstCode) {
11621
+ return isEmoji(firstCode) || grapheme.includes("\uFE0F");
11622
+ }
11623
+ function isWideSymbol(code) {
11624
+ return code >= 8592 && code <= 8703 || // 矢印
11625
+ code >= 9472 && code <= 9599 || // 罫線
11626
+ code >= 9632 && code <= 9727 || // 幾何図形
11627
+ code >= 11008 && code <= 11263;
11628
+ }
11629
+ var CLUSTER_JOINER_RE = /\u200d|\ufe0f|[\u{1f000}-\u{1faff}]|[\u{2600}-\u{27bf}]/u;
11630
+ var \u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B;
11631
+ function segmentGraphemes(text) {
11632
+ if (typeof Intl === "undefined" || typeof Intl.Segmenter !== "function") {
11633
+ return [...text];
11634
+ }
11635
+ \u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B ??= new Intl.Segmenter(void 0, { granularity: "grapheme" });
11636
+ return [...\u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B.segment(text)].map((s) => s.segment);
11637
+ }
11606
11638
  function defaultAdvanceEm(ch, code) {
11639
+ if (isEmoji(code)) return EMOJI_ADVANCE_EM;
11640
+ if (isWideSymbol(code)) return WIDE_SYMBOL_ADVANCE_EM;
11607
11641
  if (isCJK(code)) return 1.08;
11608
11642
  if (isHalfwidthKana(code)) return 0.72;
11609
11643
  if (ch >= "a" && ch <= "z") return 0.73;
@@ -11617,19 +11651,23 @@ function measureTextWidth(text, opts = {}) {
11617
11651
  const fontFamily = opts.fontFamily ?? "sans";
11618
11652
  let advanceEmSum = 0;
11619
11653
  let charCount = 0;
11620
- for (const ch of text) {
11654
+ const \u6587\u5B57\u5217 = CLUSTER_JOINER_RE.test(text) ? segmentGraphemes(text) : [...text];
11655
+ for (const ch of \u6587\u5B57\u5217) {
11621
11656
  charCount++;
11657
+ const code = ch.codePointAt(0) ?? 0;
11658
+ if (isEmojiGrapheme(ch, code)) {
11659
+ advanceEmSum += fontFamily === "mono" ? MONO_EMOJI_ADVANCE_EM : EMOJI_ADVANCE_EM;
11660
+ continue;
11661
+ }
11622
11662
  if (fontFamily === "mono") {
11623
- const code2 = ch.codePointAt(0) ?? 0;
11624
- advanceEmSum += isCJK(code2) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM;
11663
+ advanceEmSum += isCJK(code) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM;
11625
11664
  continue;
11626
11665
  }
11627
- const code = ch.codePointAt(0) ?? 0;
11628
11666
  if (isCJK(code)) {
11629
11667
  advanceEmSum += 1.08;
11630
11668
  continue;
11631
11669
  }
11632
- const table = INTER_BOLD_ADVANCE_EM[ch];
11670
+ const table = ch.length === 1 ? INTER_BOLD_ADVANCE_EM[ch] : void 0;
11633
11671
  advanceEmSum += table !== void 0 ? table : defaultAdvanceEm(ch, code);
11634
11672
  }
11635
11673
  const w = advanceEmSum * fontSize + letterSpacing * charCount;
@@ -11685,13 +11723,15 @@ var KINDS_WITHOUT_TITLE_TEXT = /* @__PURE__ */ new Set([
11685
11723
  "funnel-stages",
11686
11724
  "quadrant-matrix",
11687
11725
  "tree-hierarchy",
11688
- "journey-map",
11689
- // 形の中に自前の文字を置く (title は使わない)
11690
- "shape-blockchain-block"
11726
+ "journey-map"
11691
11727
  ]);
11692
11728
  function rendersTitleText(kind) {
11693
11729
  return !KINDS_WITHOUT_TITLE_TEXT.has(kind ?? "");
11694
11730
  }
11731
+ var KINDS_FITTING_OWN_TITLE = /* @__PURE__ */ new Set(["shape-blockchain-block"]);
11732
+ function fitsOwnTitleWidth(kind) {
11733
+ return KINDS_FITTING_OWN_TITLE.has(kind ?? "");
11734
+ }
11695
11735
  var KINDS_WITH_ROW_TEXT = /* @__PURE__ */ new Set([
11696
11736
  // 専用の表組み (StorageNode)
11697
11737
  "storage",
@@ -11893,6 +11933,70 @@ function buildDiagramAltText(topic, phase) {
11893
11933
  return parts.join(" ");
11894
11934
  }
11895
11935
 
11936
+ // src/layout/footer-shape.ts
11937
+ var SHAPE_DRAW_UP_EXTENT = {
11938
+ "shape-robot-arm": 201,
11939
+ // 実測 上 129
11940
+ "shape-iot-sensor": 120,
11941
+ // 48
11942
+ "shape-credit-card": 113,
11943
+ // 40.8
11944
+ "shape-exchange": 107,
11945
+ // 35
11946
+ "shape-storefront": 104,
11947
+ // 32
11948
+ "shape-cdn-edge": 103,
11949
+ // 30.8
11950
+ "shape-payment-provider": 101,
11951
+ // 29
11952
+ "shape-gear": 96,
11953
+ // 23.9
11954
+ "shape-rpc-node": 94,
11955
+ // 22
11956
+ "shape-wallet": 84
11957
+ // 12.1
11958
+ };
11959
+ function lifelineFooterNodes(lanes, nodes) {
11960
+ const \u6570 = /* @__PURE__ */ new Map();
11961
+ for (const n of nodes) \u6570.set(n.lane, (\u6570.get(n.lane) ?? 0) + 1);
11962
+ const lifelineLanes = /* @__PURE__ */ new Set();
11963
+ for (const lane of lanes) {
11964
+ if (lane.lifeline) lifelineLanes.add(lane.id);
11965
+ }
11966
+ return nodes.filter(
11967
+ (n) => n.role === "lifeline-footer" && lifelineLanes.has(n.lane) && (\u6570.get(n.lane) ?? 0) >= 2
11968
+ );
11969
+ }
11970
+ function footerShapeDropY(kind, h) {
11971
+ const extent = SHAPE_DRAW_UP_EXTENT[kind];
11972
+ if (extent === void 0) return 0;
11973
+ if (!Number.isFinite(h) || h <= 0) return 0;
11974
+ return Math.max(0, extent - h);
11975
+ }
11976
+ function footerShapeDrops(lanes, nodes) {
11977
+ return footerShapeDropsOf(lifelineFooterNodes(lanes, nodes));
11978
+ }
11979
+ function footerShapeDropsOf(footers) {
11980
+ const drops = /* @__PURE__ */ new Map();
11981
+ for (const footer of footers) {
11982
+ const dy = footerShapeDropY(footer.kind, footer.h);
11983
+ if (dy > 0) drops.set(footer.id, dy);
11984
+ }
11985
+ return drops;
11986
+ }
11987
+ function applyFooterShapeDrops(lanes, nodes) {
11988
+ const drops = footerShapeDrops(lanes, nodes);
11989
+ if (drops.size === 0) return nodes;
11990
+ return nodes.map((n) => {
11991
+ if (n.posX !== void 0 && n.posY !== void 0) return n;
11992
+ const dy = drops.get(n.id);
11993
+ return dy === void 0 ? n : { ...n, cy: n.cy + dy };
11994
+ });
11995
+ }
11996
+ function footerShapeDrawTop(node) {
11997
+ return node.cy - node.h / 2 - footerShapeDropY(node.kind, node.h);
11998
+ }
11999
+
11896
12000
  // src/layout/collisions.ts
11897
12001
  var LANE_LABEL_CLEARANCE_MARGIN = 2;
11898
12002
  function collectBBoxes(lanes, nodes, edges) {
@@ -11908,14 +12012,16 @@ function collectBBoxes(lanes, nodes, edges) {
11908
12012
  h: 28
11909
12013
  });
11910
12014
  }
12015
+ const footerDraw = footerShapeDrops(lanes, nodes);
11911
12016
  for (const n of nodes) {
12017
+ const up = footerDraw.get(n.id) ?? 0;
11912
12018
  out.push({
11913
12019
  kind: "node",
11914
12020
  id: n.id,
11915
12021
  x: n.cx - n.w / 2,
11916
- y: n.cy - n.h / 2,
12022
+ y: n.cy - n.h / 2 - up,
11917
12023
  w: n.w,
11918
- h: n.h
12024
+ h: n.h + up
11919
12025
  });
11920
12026
  }
11921
12027
  for (const e of edges) {
@@ -14898,67 +15004,6 @@ function layoutNodes(diag, lanes) {
14898
15004
  return out;
14899
15005
  }
14900
15006
 
14901
- // src/layout/footer-shape.ts
14902
- var SHAPE_DRAW_UP_EXTENT = {
14903
- "shape-robot-arm": 201,
14904
- // 実測 上 129
14905
- "shape-iot-sensor": 120,
14906
- // 48
14907
- "shape-credit-card": 113,
14908
- // 40.8
14909
- "shape-exchange": 107,
14910
- // 35
14911
- "shape-storefront": 104,
14912
- // 32
14913
- "shape-cdn-edge": 103,
14914
- // 30.8
14915
- "shape-payment-provider": 101,
14916
- // 29
14917
- "shape-gear": 96,
14918
- // 23.9
14919
- "shape-rpc-node": 94,
14920
- // 22
14921
- "shape-wallet": 84
14922
- // 12.1
14923
- };
14924
- function lifelineFooterNodes(lanes, nodes) {
14925
- const byLane = /* @__PURE__ */ new Map();
14926
- for (const n of nodes) {
14927
- const inside = byLane.get(n.lane);
14928
- if (inside) inside.push(n);
14929
- else byLane.set(n.lane, [n]);
14930
- }
14931
- const footers = [];
14932
- for (const lane of lanes) {
14933
- if (!lane.lifeline) continue;
14934
- const inside = byLane.get(lane.id);
14935
- if (inside === void 0 || inside.length < 2) continue;
14936
- let footer = inside[0];
14937
- for (const n of inside) {
14938
- if (n.cy >= footer.cy) footer = n;
14939
- }
14940
- footers.push(footer);
14941
- }
14942
- return footers;
14943
- }
14944
- function footerShapeDropY(kind, h) {
14945
- const extent = SHAPE_DRAW_UP_EXTENT[kind];
14946
- if (extent === void 0) return 0;
14947
- if (!Number.isFinite(h) || h <= 0) return 0;
14948
- return Math.max(0, extent - h);
14949
- }
14950
- function footerShapeDrops(lanes, nodes) {
14951
- return footerShapeDropsOf(lifelineFooterNodes(lanes, nodes));
14952
- }
14953
- function footerShapeDropsOf(footers) {
14954
- const drops = /* @__PURE__ */ new Map();
14955
- for (const footer of footers) {
14956
- const dy = footerShapeDropY(footer.kind, footer.h);
14957
- if (dy > 0) drops.set(footer.id, dy);
14958
- }
14959
- return drops;
14960
- }
14961
-
14962
15007
  // src/layout/viewbox.ts
14963
15008
  function computeViewBox(lanes, nodes, edges, bboxes, viewport) {
14964
15009
  let maxX = 0;
@@ -14979,11 +15024,6 @@ function computeViewBox(lanes, nodes, edges, bboxes, viewport) {
14979
15024
  maxX = Math.max(maxX, n.cx + n.w / 2);
14980
15025
  maxY = Math.max(maxY, n.cy + n.h / 2);
14981
15026
  }
14982
- const footerDrops = footerShapeDrops(lanes, nodes);
14983
- for (const n of nodes) {
14984
- const dy = footerDrops.get(n.id);
14985
- if (dy !== void 0) maxY = Math.max(maxY, n.cy + n.h / 2 + dy);
14986
- }
14987
15027
  if (!Number.isFinite(minX)) minX = 0;
14988
15028
  if (!Number.isFinite(minY)) minY = 0;
14989
15029
  const x = minX - VIEW_PAD;
@@ -15061,7 +15101,7 @@ function applyRowLevelNodeShifts(nodes, lanes, nodeShifts) {
15061
15101
  }
15062
15102
  function layout(diag) {
15063
15103
  const lanes = layoutLanes(diag);
15064
- const rawNodes = layoutNodes(diag, lanes);
15104
+ const rawNodes = applyFooterShapeDrops(lanes, layoutNodes(diag, lanes));
15065
15105
  const expandedLanes = expandLanesForNodes(lanes, rawNodes);
15066
15106
  const gapExpandedLanes = expandLaneGapsForEdgeLabels(expandedLanes, rawNodes, diag.edges);
15067
15107
  const nodes = rawNodes.map((n) => {
@@ -15580,7 +15620,7 @@ function templateRefIds(text) {
15580
15620
  return out;
15581
15621
  }
15582
15622
  function computeStateValues(laid, phaseIdx, progress) {
15583
- const values = {};
15623
+ const values = /* @__PURE__ */ Object.create(null);
15584
15624
  for (const s of laid.states) values[s.id] = s.initial;
15585
15625
  for (let i = 0; i < laid.phases.length; i++) {
15586
15626
  const phase = laid.phases[i];
@@ -15598,10 +15638,20 @@ function computeStateValues(laid, phaseIdx, progress) {
15598
15638
  }
15599
15639
  }
15600
15640
  }
15601
- const out = {};
15641
+ const out = /* @__PURE__ */ Object.create(null);
15602
15642
  for (const [k, v] of Object.entries(values)) out[k] = String(v);
15603
15643
  return withDerivedValues(out, laid.derived);
15604
15644
  }
15645
+ function mergeStateValues(base, overrides) {
15646
+ const merged = Object.assign(/* @__PURE__ */ Object.create(null), base);
15647
+ for (const key of Object.keys(overrides)) {
15648
+ const v = overrides[key];
15649
+ if (typeof v === "number" || typeof v === "string" || typeof v === "boolean") {
15650
+ merged[key] = String(v);
15651
+ }
15652
+ }
15653
+ return merged;
15654
+ }
15605
15655
  function interpolate(template, values) {
15606
15656
  return template.replace(TEMPLATE_REF_RE, (_, id, accessor) => {
15607
15657
  const raw = Object.hasOwn(values, id) ? values[id] : void 0;
@@ -15751,6 +15801,65 @@ function pathSubpath(d, progress) {
15751
15801
  return d;
15752
15802
  }
15753
15803
 
15804
+ // src/render/template-fields.ts
15805
+ var TEXT_FIELDS = ["title", "eyebrow", "subtitle", "value", "wBind", "hBind", "visibleIf"];
15806
+ var LIST_FIELDS = ["rows"];
15807
+ var NUMERIC_FIELDS = ["opacity", "renderOffsetX", "renderOffsetY"];
15808
+ var SHAPE_TEMPLATE_FIELDS = ["source", "radius", "fillProgress", "angle", "level", "rotation", "fill"];
15809
+ function shapeTexts(shape) {
15810
+ if (!shape) return [];
15811
+ const out = [];
15812
+ const \u4E2D\u8EAB = shape;
15813
+ for (const f of SHAPE_TEMPLATE_FIELDS) {
15814
+ const v = \u4E2D\u8EAB[f];
15815
+ if (typeof v === "string" && v) out.push(v);
15816
+ }
15817
+ return out;
15818
+ }
15819
+ function payloadTexts(node) {
15820
+ const out = [];
15821
+ const \u8DB3\u3059 = (v) => {
15822
+ if (typeof v === "string" && v) out.push(v);
15823
+ };
15824
+ for (const d of node.chartData ?? []) \u8DB3\u3059(d.value);
15825
+ for (const s of node.funnelData ?? []) \u8DB3\u3059(s.count);
15826
+ for (const t of node.ganttData ?? []) {
15827
+ \u8DB3\u3059(t.startIdx);
15828
+ \u8DB3\u3059(t.endIdx);
15829
+ }
15830
+ for (const i of node.quadrantData?.items ?? []) \u8DB3\u3059(i.quadrant);
15831
+ for (const s of node.journeyData ?? []) \u8DB3\u3059(s.emotion);
15832
+ for (const n of node.treeData ?? []) {
15833
+ \u8DB3\u3059(n.title);
15834
+ \u8DB3\u3059(n.subtitle);
15835
+ }
15836
+ if (node.mindData) {
15837
+ \u8DB3\u3059(node.mindData.rootTitle);
15838
+ for (const b of node.mindData.branches) {
15839
+ \u8DB3\u3059(b.title);
15840
+ \u8DB3\u3059(b.subtitle);
15841
+ }
15842
+ }
15843
+ return out;
15844
+ }
15845
+ function nodeTemplateTexts(node) {
15846
+ const out = [];
15847
+ for (const f of TEXT_FIELDS) {
15848
+ const v = node[f];
15849
+ if (typeof v === "string" && v) out.push(v);
15850
+ }
15851
+ for (const f of LIST_FIELDS) {
15852
+ for (const v of node[f] ?? []) if (v) out.push(v);
15853
+ }
15854
+ for (const f of NUMERIC_FIELDS) {
15855
+ const v = node[f];
15856
+ if (typeof v === "string" && v) out.push(v);
15857
+ }
15858
+ out.push(...shapeTexts(node.shape));
15859
+ out.push(...payloadTexts(node));
15860
+ return out;
15861
+ }
15862
+
15754
15863
  // src/validate.ts
15755
15864
  var TONES2 = new Set(TONES);
15756
15865
  var KINDS = new Set(NODE_KINDS);
@@ -15809,8 +15918,14 @@ function validate(diag) {
15809
15918
  const nodeIds = new Set(diag.nodes.map((n) => n.id));
15810
15919
  const edgeIds = new Set(diag.edges.map((e) => e.id));
15811
15920
  const stateIds = new Set(diag.states.map((s) => s.id));
15812
- const readableIds = /* @__PURE__ */ new Set([...stateIds, ...(diag.derived ?? []).map((d) => d.id)]);
15813
- const suggest = (target, candidates) => {
15921
+ const readableIds = /* @__PURE__ */ new Set([
15922
+ ...stateIds,
15923
+ ...(diag.derived ?? []).map((d) => d.id),
15924
+ ...(diag.inputs ?? []).map((i) => i.id),
15925
+ ...(diag.formulas ?? []).map((f) => f.id),
15926
+ ...(diag.scrollTriggers ?? []).map((t) => t.id)
15927
+ ]);
15928
+ const suggest = (target, candidates, candidateKind = "lane") => {
15814
15929
  const list = [...candidates];
15815
15930
  if (list.length === 0) return "";
15816
15931
  let best = "";
@@ -15822,7 +15937,7 @@ function validate(diag) {
15822
15937
  best = c;
15823
15938
  }
15824
15939
  }
15825
- return bestD <= 2 ? ` (\u3082\u3057\u304B\u3057\u3066 "${best}"?)` : ` (\u5B9A\u7FA9\u6E08 lane: ${list.slice(0, 5).join(", ")}${list.length > 5 ? "..." : ""})`;
15940
+ return bestD <= 2 ? ` (\u3082\u3057\u304B\u3057\u3066 "${best}"?)` : ` (\u5B9A\u7FA9\u6E08 ${candidateKind}: ${list.slice(0, 5).join(", ")}${list.length > 5 ? "..." : ""})`;
15826
15941
  };
15827
15942
  for (const n of diag.nodes) {
15828
15943
  if (!laneIds.has(n.lane)) {
@@ -15835,13 +15950,13 @@ function validate(diag) {
15835
15950
  for (const e of diag.edges) {
15836
15951
  if (!nodeIds.has(e.from)) {
15837
15952
  errors.push(
15838
- `[cdl] unknown-ref: edge "${e.id}" \u306E from "${e.from}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.from, nodeIds)}
15953
+ `[cdl] unknown-ref: edge "${e.id}" \u306E from "${e.from}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.from, nodeIds, "node")}
15839
15954
  \u2192 \u4FEE\u6B63\u4F8B: .node("${e.from}", { lane: "...", stack: 0, kind: "actor", title: "..." }) \u3092 edge \u5BA3\u8A00\u524D\u306B\u8FFD\u52A0`
15840
15955
  );
15841
15956
  }
15842
15957
  if (!nodeIds.has(e.to)) {
15843
15958
  errors.push(
15844
- `[cdl] unknown-ref: edge "${e.id}" \u306E to "${e.to}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.to, nodeIds)}
15959
+ `[cdl] unknown-ref: edge "${e.id}" \u306E to "${e.to}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.to, nodeIds, "node")}
15845
15960
  \u2192 \u4FEE\u6B63\u4F8B: .node("${e.to}", { lane: "...", stack: 0, kind: "...", title: "..." }) \u3092 edge \u5BA3\u8A00\u524D\u306B\u8FFD\u52A0`
15846
15961
  );
15847
15962
  }
@@ -15858,6 +15973,16 @@ function validate(diag) {
15858
15973
  errors.push(`[cdl] unknown-ref: phase "${p.id}" \u306E activate "${id}" \u306F node \u3067\u3082 edge \u3067\u3082\u306A\u3044 (typo \u306E\u53EF\u80FD\u6027)`);
15859
15974
  }
15860
15975
  }
15976
+ for (const id of p.draw ?? []) {
15977
+ if (!nodeIds.has(id)) {
15978
+ errors.push(`[cdl] unknown-ref: phase "${p.id}" \u306E draw "${id}" \u306F node \u3067\u306F\u306A\u3044 (typo \u306E\u53EF\u80FD\u6027)${suggest(id, nodeIds, "node")}`);
15979
+ continue;
15980
+ }
15981
+ const kind = diag.nodes.find((n) => n.id === id)?.kind;
15982
+ if (kind !== "chart-line") {
15983
+ warnings.push(`phase "${p.id}" \u306E draw "${id}" \u306F kind "${kind}" \u3067\u3001 \u5DE6\u304B\u3089\u63CF\u304F\u52D5\u304D\u3092\u6301\u305F\u306A\u3044 (\u5BFE\u8C61\u306F chart-line)`);
15984
+ }
15985
+ }
15861
15986
  for (const t of p.tweens) {
15862
15987
  if (!stateIds.has(t.stateId)) {
15863
15988
  errors.push(`[cdl] unknown-ref: phase "${p.id}" tween \u5BFE\u8C61 state "${t.stateId}" \u672A\u5B9A\u7FA9`);
@@ -15876,10 +16001,7 @@ function validate(diag) {
15876
16001
  }
15877
16002
  }
15878
16003
  for (const n of diag.nodes) {
15879
- const checks = [];
15880
- if (n.value) checks.push(n.value);
15881
- if (n.rows) checks.push(...n.rows);
15882
- for (const text of checks) {
16004
+ for (const text of nodeTemplateTexts(n)) {
15883
16005
  for (const id of templateRefIds(text)) {
15884
16006
  if (!readableIds.has(id)) {
15885
16007
  warnings.push(`node "${n.id}" \u304C\u672A\u5B9A\u7FA9 state "${id}" \u3092\u53C2\u7167`);
@@ -15907,8 +16029,7 @@ function validate(diag) {
15907
16029
  for (const s of p.sets) stateUsed.add(s.stateId);
15908
16030
  }
15909
16031
  for (const n of diag.nodes) {
15910
- const texts2 = [n.value, ...n.rows ?? []].filter(Boolean);
15911
- for (const text of texts2) {
16032
+ for (const text of nodeTemplateTexts(n)) {
15912
16033
  for (const id of templateRefIds(text)) stateUsed.add(id);
15913
16034
  }
15914
16035
  }
@@ -15988,6 +16109,187 @@ function compile(diag) {
15988
16109
  validate(diag);
15989
16110
  return layout(diag);
15990
16111
  }
16112
+ var TITLE_MAX = 18;
16113
+ var TITLE_MIN = 9;
16114
+ var TITLE_RATIO = 0.17;
16115
+ var SUB_RATIO = 0.72;
16116
+ var LINE_GAP = 3;
16117
+ var BOTTOM_PAD = 4;
16118
+ var ASCENT = 0.72;
16119
+ var DESCENT = 0.25;
16120
+ var ART_GAP = 4;
16121
+ var ART_MIN_BAND = 45;
16122
+ var \u843D\u3068\u3057\u3066\u3082\u63CF\u304F\u7A2E\u5225 = {
16123
+ \u80A9\u66F8: /* @__PURE__ */ new Set([
16124
+ // basement 系 = `commonLabel` が自前の帯に置く
16125
+ "shape-file",
16126
+ "shape-folder",
16127
+ "shape-cloud",
16128
+ "shape-cylinder",
16129
+ "shape-hexagon",
16130
+ "shape-diamond",
16131
+ "shape-stack",
16132
+ // software 系 = 固有 layout
16133
+ "shape-window",
16134
+ "shape-terminal",
16135
+ "shape-code-block",
16136
+ "shape-message-bubble",
16137
+ "shape-gear",
16138
+ // hardware 系のうち固有 layout を持つもの
16139
+ "shape-iot-sensor",
16140
+ "shape-robot-arm"
16141
+ ]),
16142
+ \u8AAC\u660E: /* @__PURE__ */ new Set([
16143
+ // basement 系 = `commonLabel` が自前の帯に置く
16144
+ "shape-file",
16145
+ "shape-folder",
16146
+ "shape-cloud",
16147
+ "shape-cylinder",
16148
+ "shape-hexagon",
16149
+ "shape-diamond",
16150
+ "shape-stack",
16151
+ // software 系 = 固有 layout
16152
+ "shape-window",
16153
+ "shape-message-bubble",
16154
+ "shape-gear",
16155
+ // hardware / blockchain 系のうち固有 layout を持つもの
16156
+ "shape-iot-sensor",
16157
+ "shape-robot-arm",
16158
+ "shape-blockchain-block"
16159
+ ])
16160
+ };
16161
+ function droppedLineIsHidden(kind, line) {
16162
+ return kind.startsWith("shape-") && !\u843D\u3068\u3057\u3066\u3082\u63CF\u304F\u7A2E\u5225[line].has(kind);
16163
+ }
16164
+ function labelPlan(node) {
16165
+ const \u9AD8\u3055 = Math.max(0, node.h);
16166
+ const \u5E95 = node.cy + \u9AD8\u3055 / 2;
16167
+ const \u5929 = node.cy - \u9AD8\u3055 / 2;
16168
+ const \u7A4D\u3080 = (\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D) => {
16169
+ const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
16170
+ let y = \u5E95 - \u4E0B\u4F59\u767D;
16171
+ const \u8AAC\u660E = \u8AAC\u660E\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B57 } : null;
16172
+ if (\u8AAC\u660E !== null) y -= \u5C0F\u3055\u3044\u5B57 + LINE_GAP;
16173
+ const \u540D\u524D = { y, size: \u540D\u524D\u5927 };
16174
+ y -= \u540D\u524D\u5927 + LINE_GAP;
16175
+ const \u80A9\u66F8 = \u80A9\u66F8\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B57 } : null;
16176
+ const \u4E0A\u306E\u884C = \u80A9\u66F8 ?? \u540D\u524D;
16177
+ return { \u540D\u524D, \u8AAC\u660E, \u80A9\u66F8, \u4E0A\u7AEF: \u4E0A\u306E\u884C.y - \u4E0A\u306E\u884C.size * ASCENT };
16178
+ };
16179
+ const \u5165\u308B = (\u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2) => \u7A4D\u3080(1, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, 1 * DESCENT).\u4E0A\u7AEF >= \u5929;
16180
+ let \u8AAC\u660E\u3042\u308A = Boolean(node.subtitle);
16181
+ let \u80A9\u66F8\u3042\u308A = Boolean(node.eyebrow);
16182
+ const \u843D\u3068\u3057\u305F = [];
16183
+ if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A) && \u80A9\u66F8\u3042\u308A) {
16184
+ \u80A9\u66F8\u3042\u308A = false;
16185
+ \u843D\u3068\u3057\u305F.push("\u80A9\u66F8");
16186
+ }
16187
+ if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A) && \u8AAC\u660E\u3042\u308A) {
16188
+ \u8AAC\u660E\u3042\u308A = false;
16189
+ \u843D\u3068\u3057\u305F.push("\u8AAC\u660E");
16190
+ }
16191
+ const \u7D44\u3080 = (\u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2) => {
16192
+ const \u4E0A\u9650 = Math.min(TITLE_MAX, Math.max(1, Math.round(\u9AD8\u3055 * TITLE_RATIO)));
16193
+ let \u540D\u524D\u5927 = 0;
16194
+ for (let size = \u4E0A\u9650; size >= 1; size--) {
16195
+ const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(size * SUB_RATIO));
16196
+ const \u4E0B\u306E\u884C\u5927 = \u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B572 : size;
16197
+ if (\u7A4D\u3080(size, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u306E\u884C\u5927 * DESCENT).\u4E0A\u7AEF >= \u5929) {
16198
+ \u540D\u524D\u5927 = size;
16199
+ break;
16200
+ }
16201
+ }
16202
+ if (\u540D\u524D\u5927 === 0) \u540D\u524D\u5927 = \u9AD8\u3055 / (ASCENT + DESCENT);
16203
+ const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
16204
+ const \u5F35\u308A\u51FA\u3057 = (\u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B57 : \u540D\u524D\u5927) * DESCENT;
16205
+ 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);
16206
+ const \u4E0B\u4F59\u767D = Math.min(Math.max(BOTTOM_PAD, \u5F35\u308A\u51FA\u3057), \u5F35\u308A\u51FA\u3057 + \u4F59\u308A);
16207
+ return \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D);
16208
+ };
16209
+ const \u7D75\u306E\u5E2F = (\u7D442) => Math.max(0, \u7D442.\u4E0A\u7AEF - ART_GAP - \u5929);
16210
+ let \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
16211
+ if (\u7D75\u306E\u5E2F(\u7D44) < ART_MIN_BAND && \u80A9\u66F8\u3042\u308A) {
16212
+ \u80A9\u66F8\u3042\u308A = false;
16213
+ \u843D\u3068\u3057\u305F.push("\u80A9\u66F8");
16214
+ \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
16215
+ }
16216
+ if (\u7D75\u306E\u5E2F(\u7D44) < ART_MIN_BAND && \u8AAC\u660E\u3042\u308A) {
16217
+ \u8AAC\u660E\u3042\u308A = false;
16218
+ \u843D\u3068\u3057\u305F.push("\u8AAC\u660E");
16219
+ \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
16220
+ }
16221
+ const \u4E00\u756A\u5C0F\u3055\u3044\u884C = Math.min(
16222
+ ...[\u7D44.\u540D\u524D, \u7D44.\u8AAC\u660E, \u7D44.\u80A9\u66F8].filter((l) => l !== null).map((l) => l.size)
16223
+ );
16224
+ return {
16225
+ \u540D\u524D: \u7D44.\u540D\u524D,
16226
+ \u8AAC\u660E: \u7D44.\u8AAC\u660E,
16227
+ \u80A9\u66F8: \u7D44.\u80A9\u66F8,
16228
+ top: \u7D44.\u4E0A\u7AEF,
16229
+ \u8AAD\u3081\u308B: \u4E00\u756A\u5C0F\u3055\u3044\u884C >= TITLE_MIN,
16230
+ \u843D\u3068\u3057\u305F
16231
+ };
16232
+ }
16233
+ function shapeRegion(node) {
16234
+ const label = labelPlan(node);
16235
+ const \u5929 = node.cy - node.h / 2;
16236
+ const availH = Math.max(0, label.top - ART_GAP - \u5929);
16237
+ return {
16238
+ cx: node.cx,
16239
+ cy: \u5929 + availH / 2,
16240
+ availW: node.w,
16241
+ availH,
16242
+ labelY: label.\u540D\u524D.y,
16243
+ label
16244
+ };
16245
+ }
16246
+ var SHADOW_GAP = 8;
16247
+ var FRAME_HALF = 1.5;
16248
+ function bodyBand(node, opt) {
16249
+ const \u5F71 = Math.max(0, opt.\u5F71ry);
16250
+ const \u5916 = Math.max(0, opt.\u5916 ?? FRAME_HALF);
16251
+ const \u4E0B\u4F59\u767D = Math.max(SHADOW_GAP + \u5F71, \u5916);
16252
+ const \u7BB1w = Math.max(0, node.w);
16253
+ const \u7BB1h = Math.max(0, node.h);
16254
+ const \u7E26\u4F59\u767D = \u5916 + \u4E0B\u4F59\u767D;
16255
+ const ky = \u7E26\u4F59\u767D > \u7BB1h && \u7E26\u4F59\u767D > 0 ? \u7BB1h / \u7E26\u4F59\u767D : 1;
16256
+ const \u6A2A\u4F59\u767D = \u5916 * 2;
16257
+ const kx = \u6A2A\u4F59\u767D > \u7BB1w && \u6A2A\u4F59\u767D > 0 ? \u7BB1w / \u6A2A\u4F59\u767D : 1;
16258
+ const x = node.cx - \u7BB1w / 2 + \u5916 * kx;
16259
+ const y = node.cy - \u7BB1h / 2 + \u5916 * ky;
16260
+ const w = Math.max(0, \u7BB1w - \u6A2A\u4F59\u767D * kx);
16261
+ const h = Math.max(0, \u7BB1h - \u7E26\u4F59\u767D * ky);
16262
+ return { x, y, w, h, cx: x + w / 2, cy: y + h / 2, \u53F3: x + w, \u5E95: y + h };
16263
+ }
16264
+ function fitLabel(band, block, pos) {
16265
+ const \u7E26 = block.\u4E0A + block.\u4E0B;
16266
+ const \u6A2A = Math.max(0, block.\u5E45);
16267
+ if (!(\u7E26 > 0)) return { k: 1, x: pos.x, y: pos.y };
16268
+ if (!(band.h > 0) || !(band.w > 0)) return { k: 0, x: band.x + band.w / 2, y: band.y };
16269
+ const k = Math.min(1, band.h / \u7E26, \u6A2A > 0 ? band.w / \u6A2A : 1);
16270
+ const \u534A = \u6A2A * k / 2;
16271
+ return {
16272
+ k,
16273
+ x: Math.max(band.x + \u534A, Math.min(pos.x, band.x + band.w - \u534A)),
16274
+ y: Math.max(band.y + block.\u4E0A * k, Math.min(pos.y, band.y + band.h - block.\u4E0B * k))
16275
+ };
16276
+ }
16277
+ function fitArt(region, extent, art) {
16278
+ const \u7E26 = extent.\u4E0A + extent.\u4E0B;
16279
+ const \u6A2A = extent.\u5DE6 + extent.\u53F3;
16280
+ if (!Number.isFinite(\u7E26) || !Number.isFinite(\u6A2A) || \u7E26 <= 0 || \u6A2A <= 0) return art;
16281
+ if (!Number.isFinite(region.availH) || !Number.isFinite(region.availW) || region.availH <= 0 || region.availW <= 0) {
16282
+ return art;
16283
+ }
16284
+ const s = Math.min(1, region.availH / \u7E26, region.availW / \u6A2A);
16285
+ if (!Number.isFinite(s) || s <= 0) return art;
16286
+ const \u7D75cx = region.cx + (extent.\u53F3 - extent.\u5DE6) / 2;
16287
+ const \u7D75cy = region.cy + (extent.\u4E0B - extent.\u4E0A) / 2;
16288
+ const dx = region.cx - s * \u7D75cx;
16289
+ const dy = region.cy - s * \u7D75cy;
16290
+ if (s >= 1 && dx === 0 && dy === 0) return art;
16291
+ return /* @__PURE__ */ jsx("g", { transform: `translate(${dx} ${dy}) scale(${s})`, children: art });
16292
+ }
15991
16293
 
15992
16294
  // src/layout/geometry.ts
15993
16295
  function pointRectEdgeDistance(px, py, rect) {
@@ -16154,6 +16456,7 @@ function emptyCounts() {
16154
16456
  "validate-performance-budget": 0,
16155
16457
  "node-inside-viewbox": 0,
16156
16458
  "node-inside-lane": 0,
16459
+ "shape-label-dropped": 0,
16157
16460
  "edge-inside-viewbox": 0,
16158
16461
  "lane-label-inside-viewbox": 0,
16159
16462
  "lane-label-overlap": 0,
@@ -16844,6 +17147,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
16844
17147
  for (const n of laid.nodes) {
16845
17148
  if (n.id.endsWith("-spacer")) continue;
16846
17149
  if (!rendersTitleText(n.kind)) continue;
17150
+ if (fitsOwnTitleWidth(n.kind)) continue;
16847
17151
  if (!isRenderedNode(n)) continue;
16848
17152
  const titleTrimmed = n.title?.trim() ?? "";
16849
17153
  if (!titleTrimmed) continue;
@@ -17100,6 +17404,15 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
17100
17404
  );
17101
17405
  }
17102
17406
  }
17407
+ for (const n of laid.nodes) {
17408
+ const \u843D\u3068\u3057\u305F = labelPlan(n).\u843D\u3068\u3057\u305F.filter((line) => droppedLineIsHidden(n.kind, line));
17409
+ if (\u843D\u3068\u3057\u305F.length === 0) continue;
17410
+ push(
17411
+ "shape-label-dropped",
17412
+ `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`,
17413
+ "warn"
17414
+ );
17415
+ }
17103
17416
  for (const e of laid.edges) {
17104
17417
  const segs = flattenPathSegments(extractPathSegments(e.d));
17105
17418
  if (segs.length === 0) continue;
@@ -18344,6 +18657,7 @@ function validateMetaAxes(totalCounts, diagrams = [], durations = [], reports =
18344
18657
  "validate-performance-budget",
18345
18658
  "node-inside-viewbox",
18346
18659
  "node-inside-lane",
18660
+ "shape-label-dropped",
18347
18661
  "edge-inside-viewbox",
18348
18662
  "lane-label-inside-viewbox",
18349
18663
  "lane-label-overlap",
@@ -18412,6 +18726,7 @@ function validateMetaAxes(totalCounts, diagrams = [], durations = [], reports =
18412
18726
  "validate-performance-budget",
18413
18727
  "node-inside-viewbox",
18414
18728
  "node-inside-lane",
18729
+ "shape-label-dropped",
18415
18730
  "edge-inside-viewbox",
18416
18731
  "lane-label-inside-viewbox",
18417
18732
  "lane-label-overlap",
@@ -18438,7 +18753,7 @@ function validateMetaAxes(totalCounts, diagrams = [], durations = [], reports =
18438
18753
  });
18439
18754
  }
18440
18755
  }
18441
- const EXPECTED_AXIS_COUNT = 66;
18756
+ const EXPECTED_AXIS_COUNT = 67;
18442
18757
  if (allAxes.length !== EXPECTED_AXIS_COUNT) {
18443
18758
  out.push({
18444
18759
  axis: "axis-documentation-completeness",
@@ -19650,7 +19965,7 @@ function StateDiffCard({
19650
19965
  ] }) }),
19651
19966
  /* @__PURE__ */ jsx("tbody", { style: { color: "var(--cdl-text, #1a1f2a)" }, children: states.map((s) => {
19652
19967
  const initial = String(s.initial);
19653
- const current = stateValues[s.id] ?? initial;
19968
+ const current = Object.hasOwn(stateValues, s.id) ? stateValues[s.id] : initial;
19654
19969
  const changed = initial !== current;
19655
19970
  return /* @__PURE__ */ jsxs("tr", { children: [
19656
19971
  /* @__PURE__ */ jsx("td", { className: "py-1 text-left text-[12px]", children: s.id }),
@@ -19939,14 +20254,14 @@ function fitTextSize(text, maxWidth, targetSize, minSize) {
19939
20254
  var COMPACT_MAX_H = 100;
19940
20255
  var COMPACT_PADDING_X = 16;
19941
20256
  var MIN_SIZE = 11;
19942
- var ASCENT = 0.72;
19943
- var DESCENT = 0.25;
19944
- var MIN_BAND_H = MIN_SIZE * (ASCENT + DESCENT);
20257
+ var ASCENT2 = 0.72;
20258
+ var DESCENT2 = 0.25;
20259
+ var MIN_BAND_H = MIN_SIZE * (ASCENT2 + DESCENT2);
19945
20260
  var EYEBROW_BASELINE = 38;
19946
20261
  var EYEBROW_SIZE = 18;
19947
20262
  var EYEBROW_GAP = 8;
19948
20263
  var BOTTOM_INSET = 4;
19949
- var eyebrowBottom = () => EYEBROW_BASELINE + EYEBROW_SIZE * DESCENT;
20264
+ var eyebrowBottom = () => EYEBROW_BASELINE + EYEBROW_SIZE * DESCENT2;
19950
20265
  var titleBandTop = (hasEyebrow) => eyebrowBottom() + EYEBROW_GAP ;
19951
20266
  var isCompactBox = (h) => h < COMPACT_MAX_H;
19952
20267
  function titlePlacement(node, \u901A\u5E38, opts = {}) {
@@ -19965,10 +20280,10 @@ function titlePlacement(node, \u901A\u5E38, opts = {}) {
19965
20280
  \u901A\u5E38.size,
19966
20281
  MIN_SIZE
19967
20282
  );
19968
- const \u5E2F\u3067 = Math.floor(\u5E2F / (ASCENT + DESCENT));
20283
+ const \u5E2F\u3067 = Math.floor(\u5E2F / (ASCENT2 + DESCENT2));
19969
20284
  const size = Math.max(MIN_SIZE, Math.min(\u5E45\u3067, \u5E2F\u3067));
19970
- const \u5B57\u9AD8 = size * (ASCENT + DESCENT);
19971
- const y = \u5B57\u9AD8 <= \u5E2F ? \u4E0A + \u5E2F / 2 + size * (ASCENT - DESCENT) / 2 : \u4E0A > 0 ? \u4E0A + size * ASCENT : (\u9AD8\u3055 - \u5B57\u9AD8) / 2 + size * ASCENT;
20285
+ const \u5B57\u9AD8 = size * (ASCENT2 + DESCENT2);
20286
+ const y = \u5B57\u9AD8 <= \u5E2F ? \u4E0A + \u5E2F / 2 + size * (ASCENT2 - DESCENT2) / 2 : \u4E0A > 0 ? \u4E0A + size * ASCENT2 : (\u9AD8\u3055 - \u5B57\u9AD8) / 2 + size * ASCENT2;
19972
20287
  return { x: node.w / 2, y, size, anchor: "middle" };
19973
20288
  }
19974
20289
  function ActorNode({ node, active, value }) {
@@ -20932,21 +21247,32 @@ function resolveBoundText(raw, values) {
20932
21247
  return hasUnresolvedRef(resolved) ? { value: resolved, ok: false } : { value: resolved, ok: true };
20933
21248
  }
20934
21249
  function resolveTreeData(nodes, values) {
20935
- if (!nodes.some((n) => n.title.includes("{"))) return nodes;
21250
+ const \u8AAD\u3080 = nodes.some((n) => n.title.includes("{") || (n.subtitle?.includes("{") ?? false));
21251
+ if (!\u8AAD\u3080) return nodes;
20936
21252
  return nodes.map((n) => {
20937
21253
  const title = resolveBoundText(n.title, values);
20938
- const \u89E3\u6C7A\u5F8C = { ...n, title: title.value };
20939
- return title.ok ? \u89E3\u6C7A\u5F8C : { ...\u89E3\u6C7A\u5F8C, unresolved: true };
21254
+ const subtitle = n.subtitle === void 0 ? void 0 : resolveBoundText(n.subtitle, values);
21255
+ const \u89E3\u6C7A\u5F8C = {
21256
+ ...n,
21257
+ title: title.value,
21258
+ ...subtitle ? { subtitle: subtitle.value } : {}
21259
+ };
21260
+ return title.ok && (subtitle?.ok ?? true) ? \u89E3\u6C7A\u5F8C : { ...\u89E3\u6C7A\u5F8C, unresolved: true };
20940
21261
  });
20941
21262
  }
20942
21263
  function resolveMindData(data, values) {
20943
- const \u8AAD\u3080 = data.rootTitle.includes("{") || data.branches.some((b) => b.title.includes("{"));
21264
+ const \u8AAD\u3080 = data.rootTitle.includes("{") || data.branches.some((b) => b.title.includes("{") || (b.subtitle?.includes("{") ?? false));
20944
21265
  if (!\u8AAD\u3080) return data;
20945
21266
  const root = resolveBoundText(data.rootTitle, values);
20946
21267
  const branches = data.branches.map((b) => {
20947
21268
  const title = resolveBoundText(b.title, values);
20948
- const \u89E3\u6C7A\u5F8C2 = { ...b, title: title.value };
20949
- return title.ok ? \u89E3\u6C7A\u5F8C2 : { ...\u89E3\u6C7A\u5F8C2, unresolved: true };
21269
+ const subtitle = b.subtitle === void 0 ? void 0 : resolveBoundText(b.subtitle, values);
21270
+ const \u89E3\u6C7A\u5F8C2 = {
21271
+ ...b,
21272
+ title: title.value,
21273
+ ...subtitle ? { subtitle: subtitle.value } : {}
21274
+ };
21275
+ return title.ok && (subtitle?.ok ?? true) ? \u89E3\u6C7A\u5F8C2 : { ...\u89E3\u6C7A\u5F8C2, unresolved: true };
20950
21276
  });
20951
21277
  const \u89E3\u6C7A\u5F8C = { ...data, rootTitle: root.value, branches };
20952
21278
  return root.ok ? \u89E3\u6C7A\u5F8C : { ...\u89E3\u6C7A\u5F8C, unresolved: true };
@@ -20954,7 +21280,9 @@ function resolveMindData(data, values) {
20954
21280
  function ChartLineNode({
20955
21281
  node,
20956
21282
  active,
20957
- stateValues = {}
21283
+ stateValues = {},
21284
+ drawing = false,
21285
+ progress = 1
20958
21286
  }) {
20959
21287
  const x0 = node.cx - node.w / 2;
20960
21288
  const y0 = node.cy - node.h / 2;
@@ -20975,6 +21303,24 @@ function ChartLineNode({
20975
21303
  const xAt = (idx) => PAD_LEFT + (data.length <= 1 ? canvasW / 2 : canvasW * idx / (data.length - 1));
20976
21304
  const yAt = (v) => plotTop + plotH - (v - vMin) / vRange * plotH;
20977
21305
  const points = data.map((d, idx) => `${xAt(idx)},${yAt(d.value)}`).join(" ");
21306
+ const \u70B9\u307E\u3067\u306E\u9577\u3055 = [];
21307
+ let \u7DDA\u306E\u5168\u9577 = 0;
21308
+ let \u524D\u306E\u70B9;
21309
+ for (const [idx, datum] of data.entries()) {
21310
+ const \u4ECA\u306E\u70B9 = { x: xAt(idx), y: yAt(datum.value) };
21311
+ if (\u524D\u306E\u70B9) {
21312
+ \u7DDA\u306E\u5168\u9577 += Math.hypot(\u4ECA\u306E\u70B9.x - \u524D\u306E\u70B9.x, \u4ECA\u306E\u70B9.y - \u524D\u306E\u70B9.y);
21313
+ }
21314
+ \u70B9\u307E\u3067\u306E\u9577\u3055.push(\u7DDA\u306E\u5168\u9577);
21315
+ \u524D\u306E\u70B9 = \u4ECA\u306E\u70B9;
21316
+ }
21317
+ const \u4F38\u3073 = drawing ? Math.min(1, Math.max(0, Number.isFinite(progress) ? progress : 1)) : 1;
21318
+ const \u7DDA\u306E\u5148\u304C\u5C4A\u3044\u305F = (idx) => {
21319
+ if (!drawing) return true;
21320
+ if (data.length <= 1) return true;
21321
+ if (\u7DDA\u306E\u5168\u9577 === 0) return true;
21322
+ return \u4F38\u3073 >= (\u70B9\u307E\u3067\u306E\u9577\u3055[idx] ?? 0) / \u7DDA\u306E\u5168\u9577;
21323
+ };
20978
21324
  const gridCount = 4;
20979
21325
  const gridTicks = Array.from({ length: gridCount + 1 }, (_, i) => {
20980
21326
  const v = vMin + vRange * i / gridCount;
@@ -21052,7 +21398,8 @@ function ChartLineNode({
21052
21398
  stroke: "var(--cdl-tone-accent, #2d6a8f)",
21053
21399
  strokeWidth: 2.5,
21054
21400
  strokeLinejoin: "round",
21055
- strokeLinecap: "round"
21401
+ strokeLinecap: "round",
21402
+ ...drawing ? { pathLength: 1, strokeDasharray: 1, strokeDashoffset: 1 - \u4F38\u3073 } : {}
21056
21403
  }
21057
21404
  ),
21058
21405
  data.map((d, idx) => {
@@ -21063,40 +21410,43 @@ function ChartLineNode({
21063
21410
  const isValley = (prev === void 0 || d.value <= prev) && (next === void 0 || d.value <= next);
21064
21411
  const labelAbove = !isValley;
21065
21412
  const labelY = labelAbove ? cy - 12 : cy + 18;
21413
+ const \u51FA\u3059 = \u7DDA\u306E\u5148\u304C\u5C4A\u3044\u305F(idx);
21066
21414
  return /* @__PURE__ */ jsxs("g", { "data-cdl-unresolved": d.unresolved ? "true" : void 0, children: [
21067
- /* @__PURE__ */ jsx(
21068
- "circle",
21069
- {
21070
- cx,
21071
- cy,
21072
- r: 5,
21073
- fill: "var(--cdl-node-fill, #ffffff)",
21074
- stroke: "var(--cdl-tone-accent, #2d6a8f)",
21075
- strokeWidth: 2.5
21076
- }
21077
- ),
21078
- /* @__PURE__ */ jsx(
21079
- "circle",
21080
- {
21081
- cx,
21082
- cy,
21083
- r: 2.5,
21084
- fill: "var(--cdl-tone-accent, #2d6a8f)"
21085
- }
21086
- ),
21087
- /* @__PURE__ */ jsx(
21088
- "text",
21089
- {
21090
- "data-cdl-role": "chart-line-value",
21091
- x: cx,
21092
- y: labelY,
21093
- fontSize: 11,
21094
- fontWeight: 600,
21095
- textAnchor: "middle",
21096
- fill: "var(--cdl-text, #1a1f2a)",
21097
- children: d.value.toLocaleString()
21098
- }
21099
- ),
21415
+ \u51FA\u3059 && /* @__PURE__ */ jsxs(Fragment, { children: [
21416
+ /* @__PURE__ */ jsx(
21417
+ "circle",
21418
+ {
21419
+ cx,
21420
+ cy,
21421
+ r: 5,
21422
+ fill: "var(--cdl-node-fill, #ffffff)",
21423
+ stroke: "var(--cdl-tone-accent, #2d6a8f)",
21424
+ strokeWidth: 2.5
21425
+ }
21426
+ ),
21427
+ /* @__PURE__ */ jsx(
21428
+ "circle",
21429
+ {
21430
+ cx,
21431
+ cy,
21432
+ r: 2.5,
21433
+ fill: "var(--cdl-tone-accent, #2d6a8f)"
21434
+ }
21435
+ ),
21436
+ /* @__PURE__ */ jsx(
21437
+ "text",
21438
+ {
21439
+ "data-cdl-role": "chart-line-value",
21440
+ x: cx,
21441
+ y: labelY,
21442
+ fontSize: 11,
21443
+ fontWeight: 600,
21444
+ textAnchor: "middle",
21445
+ fill: "var(--cdl-text, #1a1f2a)",
21446
+ children: d.value.toLocaleString()
21447
+ }
21448
+ )
21449
+ ] }),
21100
21450
  /* @__PURE__ */ jsx(
21101
21451
  "text",
21102
21452
  {
@@ -21357,16 +21707,53 @@ function GanttNode({
21357
21707
  const rowGap = 20;
21358
21708
  const rowCount = tasks.length || 1;
21359
21709
  const rowH = Math.max(28, (canvasH - rowGap * (rowCount + 1)) / rowCount);
21360
- const maxIdx = Math.max(1, Math.ceil(Math.max(...tasks.map((t) => t.endIdx + 1), 1)));
21710
+ const \u4F4D\u7F6E\u306E\u4E0A\u9650 = 1e6;
21711
+ const \u53CE\u3081\u305F = tasks.map((t) => {
21712
+ const \u59CB = Math.min(\u4F4D\u7F6E\u306E\u4E0A\u9650, Math.max(0, Number.isFinite(t.startIdx) ? t.startIdx : 0));
21713
+ const \u7D42 = Math.min(\u4F4D\u7F6E\u306E\u4E0A\u9650, Math.max(\u59CB, Number.isFinite(t.endIdx) ? t.endIdx : \u59CB));
21714
+ return { ...t, startIdx: \u59CB, endIdx: \u7D42 };
21715
+ });
21716
+ const \u5BA3\u8A00 = node.ganttAxisMax;
21717
+ 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;
21718
+ const maxIdx = \u5BA3\u8A00\u3057\u305F\u5C3A ?? Math.max(
21719
+ 1,
21720
+ Math.ceil(Math.max(...\u53CE\u3081\u305F.flatMap((t) => [t.startIdx + 1, t.endIdx + 1]), 1))
21721
+ );
21361
21722
  const cellW = canvasW / maxIdx;
21723
+ const \u6700\u5F8C\u306E\u76EE\u76DB\u308A = maxIdx - 1;
21724
+ const \u6574\u3048\u305F = \u5BA3\u8A00\u3057\u305F\u5C3A === void 0 ? \u53CE\u3081\u305F : \u53CE\u3081\u305F.map((t) => {
21725
+ const \u59CB = Math.min(t.startIdx, \u6700\u5F8C\u306E\u76EE\u76DB\u308A);
21726
+ const \u7D42 = Math.min(t.endIdx, \u6700\u5F8C\u306E\u76EE\u76DB\u308A);
21727
+ const \u5BC4\u305B\u305F = \u59CB !== t.startIdx || \u7D42 !== t.endIdx;
21728
+ return \u5BC4\u305B\u305F ? { ...t, startIdx: \u59CB, endIdx: \u7D42, clipped: true } : t;
21729
+ });
21730
+ const \u76EE\u76DB\u308A\u306E\u4E0A\u9650 = 200;
21731
+ const \u76EE\u76DB\u308A\u306E\u9593\u9694 = Math.max(1, Math.ceil(maxIdx / \u76EE\u76DB\u308A\u306E\u4E0A\u9650));
21732
+ const \u76EE\u76DB\u308A\u306E\u672C\u6570 = Math.ceil(maxIdx / \u76EE\u76DB\u308A\u306E\u9593\u9694);
21362
21733
  const xAt = (idx) => PAD_LEFT + idx * cellW;
21363
21734
  const yAt = (row) => PAD_TOP + rowGap + row * (rowH + rowGap);
21364
- const gridLabels = Array.from({ length: maxIdx }, (_, i) => {
21365
- const t = tasks.find((tt) => tt.startIdx === i);
21366
- return t?.startLabel ?? String(i);
21367
- });
21368
- const taskById = new Map(tasks.map((t) => [t.id, t]));
21369
- const rowOf = new Map(tasks.map((t, i) => [t.id, i]));
21735
+ 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() };
21736
+ const \u7F6E\u304F = (\u8868, \u4F4D\u7F6E, label) => {
21737
+ if (label !== "" && Number.isFinite(\u4F4D\u7F6E) && !\u8868.has(\u4F4D\u7F6E)) \u8868.set(\u4F4D\u7F6E, label);
21738
+ };
21739
+ for (const t of \u53CE\u3081\u305F) {
21740
+ const \u6574\u6570\u306E\u958B\u59CB = Number.isInteger(t.startIdx);
21741
+ \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);
21742
+ const \u6574\u6570\u306E\u7D42\u4E86 = Number.isInteger(t.endIdx);
21743
+ \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);
21744
+ }
21745
+ 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) ?? "";
21746
+ const \u4F4D\u7F6E\u306E\u96C6\u5408 = /* @__PURE__ */ new Set();
21747
+ 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);
21748
+ 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]) {
21749
+ for (const i of \u8868.keys()) if (i >= 0 && i < maxIdx) \u4F4D\u7F6E\u306E\u96C6\u5408.add(i);
21750
+ }
21751
+ const gridLabels = [...\u4F4D\u7F6E\u306E\u96C6\u5408].sort((a, b) => a - b).map((i) => ({ \u4F4D\u7F6E: i, label: \u540D\u524D\u3092\u5F15\u304F(i) }));
21752
+ const \u5E2F\u306E\u4F59\u767D = Math.min(6, cellW / 2);
21753
+ const \u5E2F\u306E\u5DE6 = (idx) => xAt(idx) + \u5E2F\u306E\u4F59\u767D / 2;
21754
+ const \u5E2F\u306E\u53F3 = (idx) => xAt(idx) + cellW - \u5E2F\u306E\u4F59\u767D / 2;
21755
+ const taskById = new Map(\u6574\u3048\u305F.map((t) => [t.id, t]));
21756
+ const rowOf = new Map(\u6574\u3048\u305F.map((t, i) => [t.id, i]));
21370
21757
  return /* @__PURE__ */ jsxs("g", { transform: `translate(${x0} ${y0})`, children: [
21371
21758
  /* @__PURE__ */ jsx(
21372
21759
  "rect",
@@ -21382,10 +21769,11 @@ function GanttNode({
21382
21769
  strokeWidth: active ? 3 : 1.25
21383
21770
  }
21384
21771
  ),
21385
- gridLabels.map((label, i) => /* @__PURE__ */ jsxs("g", { children: [
21772
+ gridLabels.map(({ \u4F4D\u7F6E: i, label }) => /* @__PURE__ */ jsxs("g", { children: [
21386
21773
  /* @__PURE__ */ jsx(
21387
21774
  "line",
21388
21775
  {
21776
+ "data-cdl-role": "gantt-grid",
21389
21777
  x1: xAt(i),
21390
21778
  y1: PAD_TOP,
21391
21779
  x2: xAt(i),
@@ -21396,9 +21784,10 @@ function GanttNode({
21396
21784
  opacity: 0.5
21397
21785
  }
21398
21786
  ),
21399
- /* @__PURE__ */ jsx(
21787
+ label === "" ? null : /* @__PURE__ */ jsx(
21400
21788
  "text",
21401
21789
  {
21790
+ "data-cdl-role": "gantt-tick",
21402
21791
  x: xAt(i) + cellW / 2,
21403
21792
  y: PAD_TOP + canvasH + 18,
21404
21793
  fontSize: 11,
@@ -21420,7 +21809,7 @@ function GanttNode({
21420
21809
  opacity: 0.5
21421
21810
  }
21422
21811
  ),
21423
- tasks.map((t, row) => /* @__PURE__ */ jsx(
21812
+ \u6574\u3048\u305F.map((t, row) => /* @__PURE__ */ jsx(
21424
21813
  "text",
21425
21814
  {
21426
21815
  x: PAD_LEFT - 12,
@@ -21433,16 +21822,17 @@ function GanttNode({
21433
21822
  },
21434
21823
  `label-${t.id}`
21435
21824
  )),
21436
- tasks.map((t, row) => {
21437
- const bx = xAt(t.startIdx) + 3;
21825
+ \u6574\u3048\u305F.map((t, row) => {
21826
+ const bx = \u5E2F\u306E\u5DE6(t.startIdx);
21438
21827
  const by = yAt(row);
21439
- const bw = Math.max(cellW - 6, (t.endIdx - t.startIdx + 1) * cellW - 6);
21828
+ const bw = Math.max(0, \u5E2F\u306E\u53F3(t.endIdx) - bx);
21440
21829
  return /* @__PURE__ */ jsxs("g", { children: [
21441
21830
  /* @__PURE__ */ jsx(
21442
21831
  "rect",
21443
21832
  {
21444
21833
  "data-cdl-role": "gantt-bar",
21445
21834
  "data-cdl-unresolved": t.unresolved ? "true" : void 0,
21835
+ "data-cdl-clipped": "clipped" in t && t.clipped ? "true" : void 0,
21446
21836
  x: bx,
21447
21837
  y: by,
21448
21838
  width: bw,
@@ -21465,13 +21855,13 @@ function GanttNode({
21465
21855
  )
21466
21856
  ] }, `bar-${t.id}`);
21467
21857
  }),
21468
- tasks.filter((t) => t.dependsOn && taskById.has(t.dependsOn)).map((t) => {
21858
+ \u6574\u3048\u305F.filter((t) => t.dependsOn && taskById.has(t.dependsOn)).map((t) => {
21469
21859
  const parent = taskById.get(t.dependsOn);
21470
21860
  const parentRow = rowOf.get(parent.id);
21471
21861
  const childRow = rowOf.get(t.id);
21472
- const parentBarRight = xAt(parent.endIdx) + cellW - 3;
21862
+ const parentBarRight = \u5E2F\u306E\u53F3(parent.endIdx);
21473
21863
  const parentMidY = yAt(parentRow) + rowH / 2;
21474
- const childBarLeft = xAt(t.startIdx) + 3;
21864
+ const childBarLeft = \u5E2F\u306E\u5DE6(t.startIdx);
21475
21865
  const childMidY = yAt(childRow) + rowH / 2;
21476
21866
  const arrowHeadSize = 8;
21477
21867
  const arrowHeadTipGap = 10;
@@ -21513,6 +21903,49 @@ function toneColor3(tone) {
21513
21903
  if (!tone) return TONE.accent;
21514
21904
  return TONE[tone];
21515
21905
  }
21906
+
21907
+ // src/kinds/box-lines.ts
21908
+ var \u884C\u9001\u308A\u306E\u6BD4 = 1.15;
21909
+ var \u5B57\u306E\u9AD8\u3055\u306E\u6BD4 = 0.72;
21910
+ var \u4E0A\u4E0B\u306E\u4F59\u767D = 2;
21911
+ var \u5DE6\u53F3\u306E\u4F59\u767D = 8;
21912
+ function \u5E45\u3067\u5207\u308B(text, fontSize, \u4F7F\u3048\u308B\u5E45, \u6E2C\u308B = textWidth) {
21913
+ if (\u4F7F\u3048\u308B\u5E45 <= 0) return "";
21914
+ if (\u6E2C\u308B(text, fontSize) <= \u4F7F\u3048\u308B\u5E45) return text;
21915
+ const \u7701\u7565 = "\u2026";
21916
+ const \u7701\u7565\u306E\u5E45 = \u6E2C\u308B(\u7701\u7565, fontSize);
21917
+ if (\u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E45) return "";
21918
+ let \u51FA = "";
21919
+ let \u5E45 = 0;
21920
+ for (const c of \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text)) {
21921
+ const \u5B57\u306E\u5E452 = \u6E2C\u308B(c, fontSize);
21922
+ if (\u5E45 + \u5B57\u306E\u5E452 + \u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E45) break;
21923
+ \u5E45 += \u5B57\u306E\u5E452;
21924
+ \u51FA += c;
21925
+ }
21926
+ return `${\u51FA}${\u7701\u7565}`;
21927
+ }
21928
+ function \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text) {
21929
+ const \u533A\u5207\u308A = Intl.Segmenter;
21930
+ if (typeof \u533A\u5207\u308A !== "function") return [...text];
21931
+ return [...new \u533A\u5207\u308A(void 0, { granularity: "grapheme" }).segment(text)].map((g) => g.segment);
21932
+ }
21933
+ function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u3055) {
21934
+ const \u5019\u88DC = \u884C.filter((r, i) => i === 0 || r.text.trim() !== "");
21935
+ if (\u5019\u88DC.length === 0) return [];
21936
+ const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u3055 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
21937
+ const \u9AD8\u3055 = (rs) => rs.reduce((a, r) => a + r.fontSize * \u884C\u9001\u308A\u306E\u6BD4, 0);
21938
+ const \u6B8B\u3059 = [...\u5019\u88DC];
21939
+ while (\u6B8B\u3059.length > 1 && \u9AD8\u3055(\u6B8B\u3059) > \u4F7F\u3048\u308B\u9AD8\u3055) \u6B8B\u3059.pop();
21940
+ const \u4F7F\u3048\u308B\u5E45 = \u7BB1\u306E\u5E45 - \u5DE6\u53F3\u306E\u4F59\u767D * 2;
21941
+ const \u7DCF\u9AD8 = \u9AD8\u3055(\u6B8B\u3059);
21942
+ let \u7A4D\u307F = -\u7DCF\u9AD8 / 2;
21943
+ return \u6B8B\u3059.map((r) => {
21944
+ const dy = \u7A4D\u307F + (\u884C\u9001\u308A\u306E\u6BD4 + \u5B57\u306E\u9AD8\u3055\u306E\u6BD4) / 2 * r.fontSize;
21945
+ \u7A4D\u307F += r.fontSize * \u884C\u9001\u308A\u306E\u6BD4;
21946
+ return { ...r, text: \u5E45\u3067\u5207\u308B(r.text, r.fontSize, \u4F7F\u3048\u308B\u5E45), dy };
21947
+ });
21948
+ }
21516
21949
  var MIND_TONES = ["accent", "teal", "success", "warning", "info", "error"];
21517
21950
  var MIND_BOX_GAP = 24;
21518
21951
  function MindMapNode({
@@ -21558,33 +21991,59 @@ function MindMapNode({
21558
21991
  },
21559
21992
  `edge-${i}`
21560
21993
  )),
21561
- layout2.nodes.map((n) => /* @__PURE__ */ jsxs("g", { "data-cdl-unresolved": n.unresolved ? "true" : void 0, children: [
21562
- /* @__PURE__ */ jsx(
21563
- "rect",
21564
- {
21565
- x: n.x - n.w / 2,
21566
- y: n.y - n.h / 2,
21567
- width: n.w,
21568
- height: n.h,
21569
- rx: n.isRoot ? 22 : 10,
21570
- fill: n.isRoot ? toneColor4(n.tone ?? "accent") : "var(--cdl-chip-fill, #f4f6fb)",
21571
- stroke: n.isRoot ? toneColor4(n.tone ?? "accent") : toneColor4(n.tone),
21572
- strokeWidth: n.isRoot ? 2 : 1.75
21573
- }
21574
- ),
21575
- /* @__PURE__ */ jsx(
21576
- "text",
21577
- {
21578
- x: n.x,
21579
- y: n.y + 5,
21580
- fontSize: n.isRoot ? 15 : 13,
21581
- fontWeight: n.isRoot ? 700 : 600,
21582
- textAnchor: "middle",
21583
- fill: n.isRoot ? "var(--cdl-text-on-tone, #ffffff)" : "var(--cdl-chip-text, #1a1f2a)",
21584
- children: n.title
21585
- }
21586
- )
21587
- ] }, `n-${n.id}`))
21994
+ layout2.nodes.map((n) => {
21995
+ const \u884C = \u7BB1\u306B\u7A4D\u3080(
21996
+ [
21997
+ { \u5F79\u5272: "title", text: n.title, fontSize: n.isRoot ? 15 : 13 },
21998
+ { \u5F79\u5272: "subtitle", text: n.subtitle ?? "", fontSize: 9 }
21999
+ ],
22000
+ n.w,
22001
+ n.h
22002
+ );
22003
+ const \u88DC\u8DB3\u3042\u308A = (n.subtitle ?? "").trim() !== "";
22004
+ const \u6587\u5B57\u306E\u8272 = n.isRoot ? "var(--cdl-text-on-tone, #ffffff)" : "var(--cdl-chip-text, #1a1f2a)";
22005
+ return /* @__PURE__ */ jsxs("g", { "data-cdl-unresolved": n.unresolved ? "true" : void 0, children: [
22006
+ /* @__PURE__ */ jsx(
22007
+ "rect",
22008
+ {
22009
+ x: n.x - n.w / 2,
22010
+ y: n.y - n.h / 2,
22011
+ width: n.w,
22012
+ height: n.h,
22013
+ rx: n.isRoot ? 22 : 10,
22014
+ fill: n.isRoot ? toneColor4(n.tone ?? "accent") : "var(--cdl-chip-fill, #f4f6fb)",
22015
+ stroke: n.isRoot ? toneColor4(n.tone ?? "accent") : toneColor4(n.tone),
22016
+ strokeWidth: n.isRoot ? 2 : 1.75
22017
+ }
22018
+ ),
22019
+ \u88DC\u8DB3\u3042\u308A ? \u884C.map((r) => /* @__PURE__ */ jsx(
22020
+ "text",
22021
+ {
22022
+ "data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "mind-node-subtitle" : void 0,
22023
+ x: n.x,
22024
+ y: n.y + r.dy,
22025
+ fontSize: r.fontSize,
22026
+ fontWeight: r.\u5F79\u5272 === "title" ? n.isRoot ? 700 : 600 : 500,
22027
+ textAnchor: "middle",
22028
+ fill: \u6587\u5B57\u306E\u8272,
22029
+ opacity: r.\u5F79\u5272 === "subtitle" ? 0.85 : void 0,
22030
+ children: r.text
22031
+ },
22032
+ r.\u5F79\u5272
22033
+ )) : /* @__PURE__ */ jsx(
22034
+ "text",
22035
+ {
22036
+ x: n.x,
22037
+ y: n.y + 5,
22038
+ fontSize: n.isRoot ? 15 : 13,
22039
+ fontWeight: n.isRoot ? 700 : 600,
22040
+ textAnchor: "middle",
22041
+ fill: \u6587\u5B57\u306E\u8272,
22042
+ children: n.title
22043
+ }
22044
+ )
22045
+ ] }, `n-${n.id}`);
22046
+ })
21588
22047
  ] });
21589
22048
  }
21590
22049
  function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
@@ -21706,6 +22165,7 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
21706
22165
  nodes.push({
21707
22166
  id: node.id,
21708
22167
  title: node.title,
22168
+ ...node.subtitle !== void 0 ? { subtitle: node.subtitle } : {},
21709
22169
  x,
21710
22170
  y,
21711
22171
  w,
@@ -21910,6 +22370,9 @@ function QuadrantNode({
21910
22370
  const PAD_BOTTOM = 56;
21911
22371
  const AXIS_LABEL_FONT = 12;
21912
22372
  const PAD_MIN = 60;
22373
+ const ITEM_FONT = 13;
22374
+ const ITEM_PAD_X = 12;
22375
+ const ITEM_MIN_W = 48;
21913
22376
  const axisLabelPad = (text) => Math.max(PAD_MIN, measureTextWidth(`\u2190 ${text}`, { fontSize: AXIS_LABEL_FONT}) + 12);
21914
22377
  const padBudget = Math.max(0, node.w * 0.5 - PAD_MIN * 2);
21915
22378
  const wantLeft = axisLabelPad(data.xAxis.left) - PAD_MIN;
@@ -22005,6 +22468,12 @@ function QuadrantNode({
22005
22468
  const qxStart = (isLeft ? PAD_LEFT : cx) + 18;
22006
22469
  const qyStart = (isTop ? PAD_TOP : cy) + 44;
22007
22470
  const qHalfW = halfW - 36;
22471
+ const \u67A0\u306E\u4F59\u5730 = qHalfW;
22472
+ if (\u67A0\u306E\u4F59\u5730 <= 0) return null;
22473
+ const \u67A0\u306E\u5E45 = (title) => Math.min(
22474
+ \u67A0\u306E\u4F59\u5730,
22475
+ Math.max(ITEM_MIN_W, measureTextWidth(title, { fontSize: ITEM_FONT}) + ITEM_PAD_X * 2)
22476
+ );
22008
22477
  const qHalfH = halfH - 60;
22009
22478
  const gap = 10;
22010
22479
  const rowH = 34;
@@ -22019,7 +22488,7 @@ function QuadrantNode({
22019
22488
  "data-cdl-unresolved": it.unresolved ? "true" : void 0,
22020
22489
  x: qxStart,
22021
22490
  y: py,
22022
- width: qHalfW,
22491
+ width: \u67A0\u306E\u5E45(it.title),
22023
22492
  height: rowH,
22024
22493
  rx: 6,
22025
22494
  fill: "var(--cdl-node-fill, #ffffff)",
@@ -22027,12 +22496,35 @@ function QuadrantNode({
22027
22496
  strokeWidth: 1.5
22028
22497
  }
22029
22498
  ),
22030
- /* @__PURE__ */ jsx("text", { x: qxStart + 12, y: py + rowH / 2 + 5, fontSize: 13, fontWeight: 600, fill: "var(--cdl-text, #1a1f2a)", children: it.title })
22499
+ /* @__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 })
22031
22500
  ] }, `item-${it.id}`);
22032
22501
  });
22033
22502
  })
22034
22503
  ] });
22035
22504
  }
22505
+ function \u7BB1\u306E\u6587\u5B57({
22506
+ \u884C,
22507
+ x,
22508
+ \u7BB1\u306E\u9AD8\u3055,
22509
+ fill,
22510
+ \u540D\u524D\u306E\u592A\u3055
22511
+ }) {
22512
+ return \u884C.map((r) => /* @__PURE__ */ jsx(
22513
+ "text",
22514
+ {
22515
+ "data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "tree-node-subtitle" : void 0,
22516
+ x,
22517
+ y: \u7BB1\u306E\u9AD8\u3055 / 2 + r.dy,
22518
+ fontSize: r.fontSize,
22519
+ fontWeight: r.\u5F79\u5272 === "title" ? \u540D\u524D\u306E\u592A\u3055 : 500,
22520
+ textAnchor: "middle",
22521
+ fill,
22522
+ opacity: r.\u5F79\u5272 === "subtitle" ? 0.85 : void 0,
22523
+ children: r.text
22524
+ },
22525
+ r.\u5F79\u5272
22526
+ ));
22527
+ }
22036
22528
  function TreeNode({
22037
22529
  node,
22038
22530
  active,
@@ -22095,6 +22587,15 @@ function TreeNode({
22095
22587
  layout2.nodes.map((n) => {
22096
22588
  const accent = depthColors[Math.min(n.depth, depthColors.length - 1)] ?? depthColors[0];
22097
22589
  const isRoot = n.depth === 0;
22590
+ const \u884C = \u7BB1\u306B\u7A4D\u3080(
22591
+ [
22592
+ { \u5F79\u5272: "title", text: n.title, fontSize: isRoot ? 13 : 12 },
22593
+ { \u5F79\u5272: "subtitle", text: n.subtitle ?? "", fontSize: 9 }
22594
+ ],
22595
+ n.w,
22596
+ n.h
22597
+ );
22598
+ const \u88DC\u8DB3\u3042\u308A = (n.subtitle ?? "").trim() !== "";
22098
22599
  return /* @__PURE__ */ jsx(
22099
22600
  "g",
22100
22601
  {
@@ -22113,7 +22614,13 @@ function TreeNode({
22113
22614
  fill: `url(#${gradientId})`
22114
22615
  }
22115
22616
  ),
22116
- /* @__PURE__ */ jsx(
22617
+ \u88DC\u8DB3\u3042\u308A ? \u7BB1\u306E\u6587\u5B57({
22618
+ \u884C,
22619
+ x: n.w / 2,
22620
+ \u7BB1\u306E\u9AD8\u3055: n.h,
22621
+ fill: "var(--cdl-text-on-tone, #ffffff)",
22622
+ \u540D\u524D\u306E\u592A\u3055: 700
22623
+ }) : /* @__PURE__ */ jsx(
22117
22624
  "text",
22118
22625
  {
22119
22626
  x: n.w / 2,
@@ -22141,7 +22648,13 @@ function TreeNode({
22141
22648
  }
22142
22649
  ),
22143
22650
  /* @__PURE__ */ jsx("rect", { x: 0, y: 0, width: 4, height: n.h, rx: 2, fill: accent }),
22144
- /* @__PURE__ */ jsx(
22651
+ \u88DC\u8DB3\u3042\u308A ? \u7BB1\u306E\u6587\u5B57({
22652
+ \u884C,
22653
+ x: n.w / 2 + 2,
22654
+ \u7BB1\u306E\u9AD8\u3055: n.h,
22655
+ fill: "var(--cdl-chip-text, #1a1f2a)",
22656
+ \u540D\u524D\u306E\u592A\u3055: 600
22657
+ }) : /* @__PURE__ */ jsx(
22145
22658
  "text",
22146
22659
  {
22147
22660
  x: n.w / 2 + 2,
@@ -22222,6 +22735,7 @@ function computeTreeLayout(treeNodes, canvasW, canvasH) {
22222
22735
  nodes.push({
22223
22736
  id: n.id,
22224
22737
  title: n.title,
22738
+ ...n.subtitle !== void 0 ? { subtitle: n.subtitle } : {},
22225
22739
  x,
22226
22740
  y,
22227
22741
  w: nodeW,
@@ -22503,122 +23017,6 @@ function UserJourneyNode({
22503
23017
  ))
22504
23018
  ] });
22505
23019
  }
22506
- var TITLE_MAX = 18;
22507
- var TITLE_MIN = 9;
22508
- var TITLE_RATIO = 0.17;
22509
- var SUB_RATIO = 0.72;
22510
- var LINE_GAP = 3;
22511
- var BOTTOM_PAD = 4;
22512
- var ASCENT2 = 0.72;
22513
- var DESCENT2 = 0.25;
22514
- var ART_GAP = 4;
22515
- function labelPlan(node) {
22516
- const \u9AD8\u3055 = Math.max(0, node.h);
22517
- const \u5E95 = node.cy + \u9AD8\u3055 / 2;
22518
- const \u5929 = node.cy - \u9AD8\u3055 / 2;
22519
- const \u7A4D\u3080 = (\u540D\u524D\u59272, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D2) => {
22520
- const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(\u540D\u524D\u59272 * SUB_RATIO));
22521
- let y = \u5E95 - \u4E0B\u4F59\u767D2;
22522
- const \u8AAC\u660E = \u8AAC\u660E\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B572 } : null;
22523
- if (\u8AAC\u660E !== null) y -= \u5C0F\u3055\u3044\u5B572 + LINE_GAP;
22524
- const \u540D\u524D = { y, size: \u540D\u524D\u59272 };
22525
- y -= \u540D\u524D\u59272 + LINE_GAP;
22526
- const \u80A9\u66F8 = \u80A9\u66F8\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B572 } : null;
22527
- const \u4E0A\u306E\u884C = \u80A9\u66F8 ?? \u540D\u524D;
22528
- return { \u540D\u524D, \u8AAC\u660E, \u80A9\u66F8, \u4E0A\u7AEF: \u4E0A\u306E\u884C.y - \u4E0A\u306E\u884C.size * ASCENT2 };
22529
- };
22530
- 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;
22531
- let \u8AAC\u660E\u3042\u308A = Boolean(node.subtitle);
22532
- let \u80A9\u66F8\u3042\u308A = Boolean(node.eyebrow);
22533
- if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A)) \u80A9\u66F8\u3042\u308A = false;
22534
- if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A)) \u8AAC\u660E\u3042\u308A = false;
22535
- const \u4E0A\u9650 = Math.min(TITLE_MAX, Math.max(1, Math.round(\u9AD8\u3055 * TITLE_RATIO)));
22536
- let \u540D\u524D\u5927 = 0;
22537
- for (let size = \u4E0A\u9650; size >= 1; size--) {
22538
- const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(size * SUB_RATIO));
22539
- const \u4E0B\u306E\u884C\u5927 = \u8AAC\u660E\u3042\u308A ? \u5C0F\u3055\u3044\u5B572 : size;
22540
- if (\u7A4D\u3080(size, \u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A, \u4E0B\u306E\u884C\u5927 * DESCENT2).\u4E0A\u7AEF >= \u5929) {
22541
- \u540D\u524D\u5927 = size;
22542
- break;
22543
- }
22544
- }
22545
- if (\u540D\u524D\u5927 === 0) \u540D\u524D\u5927 = \u9AD8\u3055 / (ASCENT2 + DESCENT2);
22546
- const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
22547
- const \u5F35\u308A\u51FA\u3057 = (\u8AAC\u660E\u3042\u308A ? \u5C0F\u3055\u3044\u5B57 : \u540D\u524D\u5927) * DESCENT2;
22548
- 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);
22549
- const \u4E0B\u4F59\u767D = Math.min(Math.max(BOTTOM_PAD, \u5F35\u308A\u51FA\u3057), \u5F35\u308A\u51FA\u3057 + \u4F59\u308A);
22550
- const \u7D44 = \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A, \u4E0B\u4F59\u767D);
22551
- const \u4E00\u756A\u5C0F\u3055\u3044\u884C = Math.min(
22552
- ...[\u7D44.\u540D\u524D, \u7D44.\u8AAC\u660E, \u7D44.\u80A9\u66F8].filter((l) => l !== null).map((l) => l.size)
22553
- );
22554
- return {
22555
- \u540D\u524D: \u7D44.\u540D\u524D,
22556
- \u8AAC\u660E: \u7D44.\u8AAC\u660E,
22557
- \u80A9\u66F8: \u7D44.\u80A9\u66F8,
22558
- top: \u7D44.\u4E0A\u7AEF,
22559
- \u8AAD\u3081\u308B: \u4E00\u756A\u5C0F\u3055\u3044\u884C >= TITLE_MIN
22560
- };
22561
- }
22562
- function shapeRegion(node) {
22563
- const label = labelPlan(node);
22564
- const \u5929 = node.cy - node.h / 2;
22565
- const availH = Math.max(0, label.top - ART_GAP - \u5929);
22566
- return {
22567
- cx: node.cx,
22568
- cy: \u5929 + availH / 2,
22569
- availW: node.w,
22570
- availH,
22571
- labelY: label.\u540D\u524D.y,
22572
- label
22573
- };
22574
- }
22575
- var SHADOW_GAP = 8;
22576
- var FRAME_HALF = 1.5;
22577
- function bodyBand(node, opt) {
22578
- const \u5F71 = Math.max(0, opt.\u5F71ry);
22579
- const \u5916 = Math.max(0, opt.\u5916 ?? FRAME_HALF);
22580
- const \u4E0B\u4F59\u767D = Math.max(SHADOW_GAP + \u5F71, \u5916);
22581
- const \u7BB1w = Math.max(0, node.w);
22582
- const \u7BB1h = Math.max(0, node.h);
22583
- const \u7E26\u4F59\u767D = \u5916 + \u4E0B\u4F59\u767D;
22584
- const ky = \u7E26\u4F59\u767D > \u7BB1h && \u7E26\u4F59\u767D > 0 ? \u7BB1h / \u7E26\u4F59\u767D : 1;
22585
- const \u6A2A\u4F59\u767D = \u5916 * 2;
22586
- const kx = \u6A2A\u4F59\u767D > \u7BB1w && \u6A2A\u4F59\u767D > 0 ? \u7BB1w / \u6A2A\u4F59\u767D : 1;
22587
- const x = node.cx - \u7BB1w / 2 + \u5916 * kx;
22588
- const y = node.cy - \u7BB1h / 2 + \u5916 * ky;
22589
- const w = Math.max(0, \u7BB1w - \u6A2A\u4F59\u767D * kx);
22590
- const h = Math.max(0, \u7BB1h - \u7E26\u4F59\u767D * ky);
22591
- return { x, y, w, h, cx: x + w / 2, cy: y + h / 2, \u53F3: x + w, \u5E95: y + h };
22592
- }
22593
- function fitLabel(band, block, pos) {
22594
- const \u7E26 = block.\u4E0A + block.\u4E0B;
22595
- const \u6A2A = Math.max(0, block.\u5E45);
22596
- if (!(\u7E26 > 0)) return { k: 1, x: pos.x, y: pos.y };
22597
- if (!(band.h > 0) || !(band.w > 0)) return { k: 0, x: band.x + band.w / 2, y: band.y };
22598
- const k = Math.min(1, band.h / \u7E26, \u6A2A > 0 ? band.w / \u6A2A : 1);
22599
- const \u534A = \u6A2A * k / 2;
22600
- return {
22601
- k,
22602
- x: Math.max(band.x + \u534A, Math.min(pos.x, band.x + band.w - \u534A)),
22603
- y: Math.max(band.y + block.\u4E0A * k, Math.min(pos.y, band.y + band.h - block.\u4E0B * k))
22604
- };
22605
- }
22606
- function fitArt(region, extent, art) {
22607
- const \u7E26 = extent.\u4E0A + extent.\u4E0B;
22608
- const \u6A2A = extent.\u5DE6 + extent.\u53F3;
22609
- if (!Number.isFinite(\u7E26) || !Number.isFinite(\u6A2A) || \u7E26 <= 0 || \u6A2A <= 0) return art;
22610
- if (!Number.isFinite(region.availH) || !Number.isFinite(region.availW) || region.availH <= 0 || region.availW <= 0) {
22611
- return art;
22612
- }
22613
- const s = Math.min(1, region.availH / \u7E26, region.availW / \u6A2A);
22614
- if (!Number.isFinite(s) || s <= 0) return art;
22615
- const \u7D75cx = region.cx + (extent.\u53F3 - extent.\u5DE6) / 2;
22616
- const \u7D75cy = region.cy + (extent.\u4E0B - extent.\u4E0A) / 2;
22617
- const dx = region.cx - s * \u7D75cx;
22618
- const dy = region.cy - s * \u7D75cy;
22619
- if (s >= 1 && dx === 0 && dy === 0) return art;
22620
- return /* @__PURE__ */ jsx("g", { transform: `translate(${dx} ${dy}) scale(${s})`, children: art });
22621
- }
22622
23020
  var BASEMENT_FILL = "#dde8f0";
22623
23021
  var commonFrame = (active) => ({
22624
23022
  fill: BASEMENT_FILL,
@@ -22633,8 +23031,8 @@ var EYEBROW_TRACKING = 2;
22633
23031
  var SUB_SIZE = 11;
22634
23032
  var SUB_GAP = 4;
22635
23033
  function labelBlock(node, pos, size, band) {
22636
- const \u4E0A = node.eyebrow ? size + EYEBROW_GAP2 + EYEBROW_SIZE2 * ASCENT2 : size * ASCENT2;
22637
- const \u4E0B = node.subtitle ? size + SUB_GAP + SUB_SIZE * DESCENT2 : size * DESCENT2;
23034
+ const \u4E0A = node.eyebrow ? size + EYEBROW_GAP2 + EYEBROW_SIZE2 * ASCENT : size * ASCENT;
23035
+ const \u4E0B = node.subtitle ? size + SUB_GAP + SUB_SIZE * DESCENT : size * DESCENT;
22638
23036
  const \u5E45 = Math.max(
22639
23037
  textWidth(node.title ?? "", size),
22640
23038
  node.eyebrow ? textWidth(node.eyebrow, EYEBROW_SIZE2, EYEBROW_TRACKING) : 0,
@@ -24824,6 +25222,15 @@ function ShapeSmartContractNode({ node, active }) {
24824
25222
  bottomLabel2(node, r.cx, r.label)
24825
25223
  ] });
24826
25224
  }
25225
+ var \u5B57\u306E\u5E45 = (text, size) => Math.max(displayWidth(text) * size * MONO_ADVANCE_RATIO, textWidth(text, size));
25226
+ var BLOCK_DEFAULT_FIELDS = [
25227
+ { label: "hash", value: "0xaf31c9d2..." },
25228
+ { label: "prev", value: "0x7b3f92c1..." },
25229
+ { label: "merkle", value: "0xc1892f4a..." },
25230
+ { label: "nonce", value: "82,914" },
25231
+ { label: "tx", value: "142 tx" }
25232
+ ];
25233
+ var BLOCK_DEFAULT_TITLE = "Block #421,873";
24827
25234
  function ShapeBlockchainBlockNode({ node, active }) {
24828
25235
  const frame = commonFrame4(active);
24829
25236
  const r = shapeRegion(node);
@@ -24833,21 +25240,22 @@ function ShapeBlockchainBlockNode({ node, active }) {
24833
25240
  const cy = r.cy;
24834
25241
  const x = cx - bw / 2;
24835
25242
  const y = cy - bh / 2;
25243
+ const \u6E21\u3055\u308C\u305F = (v) => (v ?? "").trim();
25244
+ const \u898B\u51FA\u3057 = \u6E21\u3055\u308C\u305F(node.title) || BLOCK_DEFAULT_TITLE;
25245
+ const fields = BLOCK_DEFAULT_FIELDS.map((f) => ({
25246
+ label: f.label,
25247
+ value: f.label === "hash" ? \u6E21\u3055\u308C\u305F(node.subtitle) || f.value : f.value
25248
+ }));
25249
+ const \u898B\u51FA\u3057\u306E\u5E45 = bw - 14 - 30;
24836
25250
  const art = /* @__PURE__ */ jsxs("g", { children: [
24837
25251
  /* @__PURE__ */ jsx("rect", { x: x + 6, y: y + 6, width: bw, height: bh, rx: 8, fill: frame.stroke, opacity: 0.2, stroke: "none" }),
24838
25252
  /* @__PURE__ */ jsx("rect", { "data-cdl-role": "node-body", x, y, width: bw, height: bh, rx: 8, ...frame }),
24839
25253
  /* @__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" }),
24840
- /* @__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" }),
25254
+ /* @__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) }),
24841
25255
  /* @__PURE__ */ jsx("circle", { cx: x + bw - 16, cy: y + 16, r: 5.5, fill: "#7cd88f", stroke: "#ffffff", strokeWidth: 1.5 }),
24842
- [
24843
- { label: "hash", value: "0xaf31c9d2..." },
24844
- { label: "prev", value: "0x7b3f92c1..." },
24845
- { label: "merkle", value: "0xc1892f4a..." },
24846
- { label: "nonce", value: "82,914" },
24847
- { label: "tx", value: "142 tx" }
24848
- ].map((f, i) => /* @__PURE__ */ jsxs("g", { children: [
25256
+ fields.map((f, i) => /* @__PURE__ */ jsxs("g", { children: [
24849
25257
  /* @__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 }),
24850
- /* @__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 }),
25258
+ /* @__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) }),
24851
25259
  /* @__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 })
24852
25260
  ] }, i)),
24853
25261
  /* @__PURE__ */ jsxs("g", { transform: `translate(${cx - 32}, ${y + bh - 26})`, children: [
@@ -26333,6 +26741,7 @@ function ShapeCustomerServiceNode({ node, active }) {
26333
26741
  function CdlNodeView({
26334
26742
  node,
26335
26743
  active,
26744
+ drawing = false,
26336
26745
  progress,
26337
26746
  stateValues,
26338
26747
  currentPhaseId
@@ -26382,7 +26791,16 @@ function CdlNodeView({
26382
26791
  // 数と語を取る 7 種に対し、mind-map / tree-hierarchy は **名前だけ** を取る (#467)。
26383
26792
  // 親子の繋がりと、描かれない欄 (補足) は解決しない。
26384
26793
  case "chart-line":
26385
- return /* @__PURE__ */ jsx(ChartLineNode, { node: resolvedNode, active, stateValues });
26794
+ return /* @__PURE__ */ jsx(
26795
+ ChartLineNode,
26796
+ {
26797
+ node: resolvedNode,
26798
+ active,
26799
+ stateValues,
26800
+ drawing,
26801
+ progress
26802
+ }
26803
+ );
26386
26804
  case "chart-pie":
26387
26805
  return /* @__PURE__ */ jsx(ChartPieNode, { node: resolvedNode, active, stateValues });
26388
26806
  case "chart-bar":
@@ -26543,6 +26961,29 @@ function CdlNodeView({
26543
26961
  }
26544
26962
  );
26545
26963
  }
26964
+
26965
+ // src/layout/lifeline.ts
26966
+ function lifelineStartYs(nodes) {
26967
+ const topmost = /* @__PURE__ */ new Map();
26968
+ for (const n of nodes) {
26969
+ const cur = topmost.get(n.lane);
26970
+ if (cur === void 0 || n.cy < cur.cy) topmost.set(n.lane, n);
26971
+ }
26972
+ const starts = /* @__PURE__ */ new Map();
26973
+ for (const [laneId, n] of topmost) starts.set(laneId, n.cy + n.h / 2);
26974
+ return starts;
26975
+ }
26976
+ function uniformLifelineEndY(lanes, nodes, starts = lifelineStartYs(nodes)) {
26977
+ const lifelineLanes = lanes.filter((l) => l.lifeline);
26978
+ let deepestStart = Number.NEGATIVE_INFINITY;
26979
+ for (const lane of lifelineLanes) {
26980
+ const start = starts.get(lane.id);
26981
+ if (start !== void 0) deepestStart = Math.max(deepestStart, start);
26982
+ }
26983
+ const footerTops = lifelineFooterNodes(lanes, nodes).map((f) => footerShapeDrawTop(f)).filter((top) => top > deepestStart);
26984
+ if (footerTops.length > 0) return Math.min(...footerTops);
26985
+ return lifelineLanes[0] ? lifelineLanes[0].y + lifelineLanes[0].height : 0;
26986
+ }
26546
26987
  function CdlStage({
26547
26988
  laid,
26548
26989
  currentPhase,
@@ -26553,15 +26994,14 @@ function CdlStage({
26553
26994
  svgRef
26554
26995
  }) {
26555
26996
  const activeSet = new Set(currentPhase?.activate ?? []);
26556
- const lifelineLanes = laid.lanes.filter((l) => l.lifeline);
26557
- const { footerTops, footerDropById } = useMemo(() => {
26558
- const footers = lifelineFooterNodes(laid.lanes, laid.nodes);
26997
+ const drawSet = new Set(currentPhase?.draw ?? []);
26998
+ const { lifelineStarts, uniformFooterTop } = useMemo(() => {
26999
+ const starts = lifelineStartYs(laid.nodes);
26559
27000
  return {
26560
- footerTops: footers.map((f) => f.cy - f.h / 2),
26561
- footerDropById: footerShapeDropsOf(footers)
27001
+ lifelineStarts: starts,
27002
+ uniformFooterTop: uniformLifelineEndY(laid.lanes, laid.nodes, starts)
26562
27003
  };
26563
27004
  }, [laid]);
26564
- const uniformFooterTop = footerTops.length > 0 ? Math.min(...footerTops) : lifelineLanes[0] ? lifelineLanes[0].y + lifelineLanes[0].height : 0;
26565
27005
  const diagramScale = laid.diagramScale ?? 1;
26566
27006
  return /* @__PURE__ */ jsxs("div", { className: compact ? "px-3 py-3" : "px-6 py-6", style: compact ? void 0 : { minHeight: 460 }, children: [
26567
27007
  /* @__PURE__ */ jsxs(
@@ -26648,11 +27088,8 @@ function CdlStage({
26648
27088
  }
26649
27089
  ),
26650
27090
  lane.lifeline && (() => {
26651
- const laneNodes = laid.nodes.filter((n) => n.lane === lane.id);
26652
- if (laneNodes.length === 0) return null;
26653
- const sortedByCy = laneNodes.slice().sort((a, b) => a.cy - b.cy);
26654
- const header = sortedByCy[0];
26655
- const y1 = header.cy + header.h / 2;
27091
+ const y1 = lifelineStarts.get(lane.id);
27092
+ if (y1 === void 0) return null;
26656
27093
  const y2 = uniformFooterTop;
26657
27094
  if (y2 <= y1) return null;
26658
27095
  return /* @__PURE__ */ jsx(
@@ -26694,13 +27131,13 @@ function CdlStage({
26694
27131
  {
26695
27132
  node,
26696
27133
  active: activeSet.has(node.id),
27134
+ drawing: drawSet.has(node.id),
26697
27135
  progress,
26698
27136
  stateValues,
26699
27137
  currentPhaseId: currentPhase?.id
26700
27138
  }
26701
27139
  );
26702
- const dy = footerDropById.get(node.id);
26703
- return dy === void 0 ? /* @__PURE__ */ jsx("g", { children: view }, node.id) : /* @__PURE__ */ jsx("g", { transform: `translate(0, ${dy})`, children: view }, node.id);
27140
+ return /* @__PURE__ */ jsx("g", { children: view }, node.id);
26704
27141
  }),
26705
27142
  laid.edges.filter((edge) => Boolean(edge.dThrough)).map((edge) => /* @__PURE__ */ jsx(CdlEdgeGlowView, { edge, active: activeSet.has(edge.id) }, `glow-${edge.id}`)),
26706
27143
  laid.edges.map((edge) => /* @__PURE__ */ jsx(
@@ -26923,14 +27360,7 @@ function CdlDiagramView({ diagram: diagram2, laid: laidProp, hideHeader = false,
26923
27360
  );
26924
27361
  const stateValues = useMemo(() => {
26925
27362
  if (!isInteractive) return baseStateValues;
26926
- const merged = { ...baseStateValues };
26927
- for (const key of Object.keys(interactive.stateOverrides)) {
26928
- const v = interactive.stateOverrides[key];
26929
- if (typeof v === "number" || typeof v === "string" || typeof v === "boolean") {
26930
- merged[key] = String(v);
26931
- }
26932
- }
26933
- return merged;
27363
+ return mergeStateValues(baseStateValues, interactive.stateOverrides);
26934
27364
  }, [isInteractive, baseStateValues, interactive.stateOverrides]);
26935
27365
  return /* @__PURE__ */ jsxs(
26936
27366
  "div",
@@ -27172,6 +27602,7 @@ function bboxDiffWorld(predicted, actual) {
27172
27602
  }
27173
27603
 
27174
27604
  // src/presets.ts
27605
+ var \u53C2\u7167\u305D\u306E\u3082\u306E = (v) => /^\{[A-Za-z_][\s\S]*\}$/.test(v);
27175
27606
  var GRID_UNIT = 16;
27176
27607
  function gridAlignedLaneW(canvasW) {
27177
27608
  const padPerSide = Math.ceil(LANE_PAD_MIN / GRID_UNIT) * GRID_UNIT;
@@ -27239,6 +27670,7 @@ function flow(preset) {
27239
27670
  b.lane("flow", { width: w, ...preset.laneLabel ? { label: preset.laneLabel } : {} });
27240
27671
  const tone = preset.defaultTone ?? "accent";
27241
27672
  const style = preset.defaultStyle ?? "dotted-flow";
27673
+ const autoChain = preset.autoChain ?? true;
27242
27674
  let prevId = null;
27243
27675
  let stackIdx = 0;
27244
27676
  const phaseActivate = [];
@@ -27253,7 +27685,7 @@ function flow(preset) {
27253
27685
  ...node.subtitle ? { subtitle: node.subtitle } : {}
27254
27686
  });
27255
27687
  phaseActivate.push(node.id);
27256
- if (prevId !== null) {
27688
+ if (autoChain && prevId !== null) {
27257
27689
  const edgeId = `e-${prevId}-${node.id}`;
27258
27690
  b.edge(prevId, node.id, {
27259
27691
  id: edgeId,
@@ -27266,6 +27698,17 @@ function flow(preset) {
27266
27698
  prevId = node.id;
27267
27699
  return api;
27268
27700
  },
27701
+ edge(from, to, opts) {
27702
+ const edgeId = opts?.id ?? `e-${from}-${to}`;
27703
+ b.edge(from, to, {
27704
+ id: edgeId,
27705
+ label: opts?.label ?? "\u2192",
27706
+ tone: opts?.tone ?? tone,
27707
+ style: opts?.style ?? style
27708
+ });
27709
+ phaseActivate.push(edgeId);
27710
+ return api;
27711
+ },
27269
27712
  build() {
27270
27713
  b.phase(
27271
27714
  "flow",
@@ -27329,7 +27772,7 @@ function sequence(preset) {
27329
27772
  const laneId = actorIds.get(label) ?? slugify(label);
27330
27773
  const footerId = `${laneId}-footer`;
27331
27774
  const actorW = Math.max(140, label.length * 22 + 52);
27332
- b.node(footerId, { lane: laneId, stack: footerStack, kind: "card", title: label, w: actorW, h: 72 });
27775
+ b.node(footerId, { lane: laneId, stack: footerStack, kind: "card", title: label, w: actorW, h: 72, role: "lifeline-footer" });
27333
27776
  phaseActivate.push(footerId);
27334
27777
  });
27335
27778
  b.phase(
@@ -27652,8 +28095,7 @@ function tree(preset) {
27652
28095
  id: n.id,
27653
28096
  title: n.title,
27654
28097
  parent: n.parent,
27655
- subtitle: n.subtitle,
27656
- eyebrow: n.eyebrow
28098
+ subtitle: n.subtitle
27657
28099
  }))
27658
28100
  });
27659
28101
  b.phase(
@@ -27887,9 +28329,11 @@ function gantt(preset) {
27887
28329
  build() {
27888
28330
  const labelSeq = [];
27889
28331
  for (const t of tasks) {
27890
- if (!labelSeq.includes(t.start)) labelSeq.push(t.start);
27891
- if (!labelSeq.includes(t.end)) labelSeq.push(t.end);
28332
+ if (!\u53C2\u7167\u305D\u306E\u3082\u306E(t.start) && !labelSeq.includes(t.start)) labelSeq.push(t.start);
28333
+ if (!\u53C2\u7167\u305D\u306E\u3082\u306E(t.end) && !labelSeq.includes(t.end)) labelSeq.push(t.end);
27892
28334
  }
28335
+ const \u4F4D\u7F6E = (v) => \u53C2\u7167\u305D\u306E\u3082\u306E(v) ? v : labelSeq.indexOf(v);
28336
+ const \u540D\u672D = (v) => \u53C2\u7167\u305D\u306E\u3082\u306E(v) ? "" : v;
27893
28337
  b.lane("gantt", { width: canvasW });
27894
28338
  const nodeId = `${preset.id}-gantt`;
27895
28339
  b.node(nodeId, {
@@ -27900,13 +28344,15 @@ function gantt(preset) {
27900
28344
  eyebrow: "gantt",
27901
28345
  w: canvasW,
27902
28346
  h: canvasH,
28347
+ // 宣言していない図には欄自体を載せない = 自動で決める経路をそのまま通す
28348
+ ...preset.axisMax !== void 0 ? { ganttAxisMax: preset.axisMax } : {},
27903
28349
  ganttData: tasks.map((t) => ({
27904
28350
  id: t.id,
27905
28351
  title: t.title,
27906
- startIdx: labelSeq.indexOf(t.start),
27907
- endIdx: labelSeq.indexOf(t.end),
27908
- startLabel: t.start,
27909
- endLabel: t.end,
28352
+ startIdx: \u4F4D\u7F6E(t.start),
28353
+ endIdx: \u4F4D\u7F6E(t.end),
28354
+ startLabel: \u540D\u672D(t.start),
28355
+ endLabel: \u540D\u672D(t.end),
27910
28356
  owner: t.owner,
27911
28357
  dependsOn: t.dependsOn,
27912
28358
  tone