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