@cardenelabs/cdl 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +401 -0
  2. package/SPEC.md +32 -17
  3. package/dist/index.cjs +700 -306
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +68 -14
  6. package/dist/index.d.ts +68 -14
  7. package/dist/index.js +700 -306
  8. package/dist/index.js.map +1 -1
  9. package/dist/react.cjs +572 -196
  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 +572 -196
  14. package/dist/react.js.map +1 -1
  15. package/dist/{render-DquCvgOB.d.cts → render-hmFRAabt.d.cts} +33 -2
  16. package/dist/{render-DquCvgOB.d.ts → render-hmFRAabt.d.ts} +33 -2
  17. package/package.json +6 -3
  18. package/src/kinds/box-lines.ts +120 -0
  19. package/src/kinds/gantt.tsx +152 -24
  20. package/src/kinds/mind-map.tsx +50 -12
  21. package/src/kinds/quadrant.tsx +28 -2
  22. package/src/kinds/shape-blockchain.tsx +65 -12
  23. package/src/kinds/shape-region.tsx +152 -34
  24. package/src/kinds/tree.tsx +92 -20
  25. package/src/layout/collisions.ts +10 -2
  26. package/src/layout/footer-shape.ts +86 -24
  27. package/src/layout/lifeline.ts +80 -0
  28. package/src/layout/spec.ts +21 -2
  29. package/src/layout/text-width.ts +92 -4
  30. package/src/layout/viewbox.ts +0 -8
  31. package/src/layout.ts +8 -1
  32. package/src/presets.ts +120 -22
  33. package/src/render/header.tsx +3 -1
  34. package/src/render/payload-binding.ts +31 -8
  35. package/src/render/stage.tsx +17 -34
  36. package/src/render/template-fields.ts +212 -0
  37. package/src/render/utils.ts +32 -2
  38. package/src/render.tsx +2 -9
  39. package/src/types.ts +33 -2
  40. package/src/validate.ts +27 -9
  41. package/src/visual-validate.ts +34 -1
  42. package/src/layout/label-shift.ts +0 -28
package/dist/index.js CHANGED
@@ -11603,7 +11603,35 @@ function isCJK(code) {
11603
11603
  function isHalfwidthKana(code) {
11604
11604
  return code >= 65377 && code <= 65500;
11605
11605
  }
11606
+ var EMOJI_ADVANCE_EM = 1.05;
11607
+ var MONO_EMOJI_ADVANCE_EM = 1.16;
11608
+ var WIDE_SYMBOL_ADVANCE_EM = 0.95;
11609
+ function isEmoji(code) {
11610
+ return code >= 126976 && code <= 129791 || // 絵文字の主要面
11611
+ code >= 9728 && code <= 10175 || // 記号と絵文字 (♻ ✅ ❤ 等)
11612
+ code >= 127462 && code <= 127487;
11613
+ }
11614
+ function isEmojiGrapheme(grapheme, firstCode) {
11615
+ return isEmoji(firstCode) || grapheme.includes("\uFE0F");
11616
+ }
11617
+ function isWideSymbol(code) {
11618
+ return code >= 8592 && code <= 8703 || // 矢印
11619
+ code >= 9472 && code <= 9599 || // 罫線
11620
+ code >= 9632 && code <= 9727 || // 幾何図形
11621
+ code >= 11008 && code <= 11263;
11622
+ }
11623
+ var CLUSTER_JOINER_RE = /\u200d|\ufe0f|[\u{1f000}-\u{1faff}]|[\u{2600}-\u{27bf}]/u;
11624
+ var \u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B;
11625
+ function segmentGraphemes(text) {
11626
+ if (typeof Intl === "undefined" || typeof Intl.Segmenter !== "function") {
11627
+ return [...text];
11628
+ }
11629
+ \u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B ??= new Intl.Segmenter(void 0, { granularity: "grapheme" });
11630
+ return [...\u66F8\u8A18\u7D20\u3067\u5206\u3051\u308B.segment(text)].map((s) => s.segment);
11631
+ }
11606
11632
  function defaultAdvanceEm(ch, code) {
11633
+ if (isEmoji(code)) return EMOJI_ADVANCE_EM;
11634
+ if (isWideSymbol(code)) return WIDE_SYMBOL_ADVANCE_EM;
11607
11635
  if (isCJK(code)) return 1.08;
11608
11636
  if (isHalfwidthKana(code)) return 0.72;
11609
11637
  if (ch >= "a" && ch <= "z") return 0.73;
@@ -11617,19 +11645,23 @@ function measureTextWidth(text, opts = {}) {
11617
11645
  const fontFamily = opts.fontFamily ?? "sans";
11618
11646
  let advanceEmSum = 0;
11619
11647
  let charCount = 0;
11620
- for (const ch of text) {
11648
+ const \u6587\u5B57\u5217 = CLUSTER_JOINER_RE.test(text) ? segmentGraphemes(text) : [...text];
11649
+ for (const ch of \u6587\u5B57\u5217) {
11621
11650
  charCount++;
11651
+ const code = ch.codePointAt(0) ?? 0;
11652
+ if (isEmojiGrapheme(ch, code)) {
11653
+ advanceEmSum += fontFamily === "mono" ? MONO_EMOJI_ADVANCE_EM : EMOJI_ADVANCE_EM;
11654
+ continue;
11655
+ }
11622
11656
  if (fontFamily === "mono") {
11623
- const code2 = ch.codePointAt(0) ?? 0;
11624
- advanceEmSum += isCJK(code2) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM;
11657
+ advanceEmSum += isCJK(code) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM;
11625
11658
  continue;
11626
11659
  }
11627
- const code = ch.codePointAt(0) ?? 0;
11628
11660
  if (isCJK(code)) {
11629
11661
  advanceEmSum += 1.08;
11630
11662
  continue;
11631
11663
  }
11632
- const table = INTER_BOLD_ADVANCE_EM[ch];
11664
+ const table = ch.length === 1 ? INTER_BOLD_ADVANCE_EM[ch] : void 0;
11633
11665
  advanceEmSum += table !== void 0 ? table : defaultAdvanceEm(ch, code);
11634
11666
  }
11635
11667
  const w = advanceEmSum * fontSize + letterSpacing * charCount;
@@ -11685,13 +11717,15 @@ var KINDS_WITHOUT_TITLE_TEXT = /* @__PURE__ */ new Set([
11685
11717
  "funnel-stages",
11686
11718
  "quadrant-matrix",
11687
11719
  "tree-hierarchy",
11688
- "journey-map",
11689
- // 形の中に自前の文字を置く (title は使わない)
11690
- "shape-blockchain-block"
11720
+ "journey-map"
11691
11721
  ]);
11692
11722
  function rendersTitleText(kind) {
11693
11723
  return !KINDS_WITHOUT_TITLE_TEXT.has(kind ?? "");
11694
11724
  }
11725
+ var KINDS_FITTING_OWN_TITLE = /* @__PURE__ */ new Set(["shape-blockchain-block"]);
11726
+ function fitsOwnTitleWidth(kind) {
11727
+ return KINDS_FITTING_OWN_TITLE.has(kind ?? "");
11728
+ }
11695
11729
  var KINDS_WITH_ROW_TEXT = /* @__PURE__ */ new Set([
11696
11730
  // 専用の表組み (StorageNode)
11697
11731
  "storage",
@@ -11893,6 +11927,70 @@ function buildDiagramAltText(topic, phase) {
11893
11927
  return parts.join(" ");
11894
11928
  }
11895
11929
 
11930
+ // src/layout/footer-shape.ts
11931
+ var SHAPE_DRAW_UP_EXTENT = {
11932
+ "shape-robot-arm": 201,
11933
+ // 実測 上 129
11934
+ "shape-iot-sensor": 120,
11935
+ // 48
11936
+ "shape-credit-card": 113,
11937
+ // 40.8
11938
+ "shape-exchange": 107,
11939
+ // 35
11940
+ "shape-storefront": 104,
11941
+ // 32
11942
+ "shape-cdn-edge": 103,
11943
+ // 30.8
11944
+ "shape-payment-provider": 101,
11945
+ // 29
11946
+ "shape-gear": 96,
11947
+ // 23.9
11948
+ "shape-rpc-node": 94,
11949
+ // 22
11950
+ "shape-wallet": 84
11951
+ // 12.1
11952
+ };
11953
+ function lifelineFooterNodes(lanes, nodes) {
11954
+ const \u6570 = /* @__PURE__ */ new Map();
11955
+ for (const n of nodes) \u6570.set(n.lane, (\u6570.get(n.lane) ?? 0) + 1);
11956
+ const lifelineLanes = /* @__PURE__ */ new Set();
11957
+ for (const lane of lanes) {
11958
+ if (lane.lifeline) lifelineLanes.add(lane.id);
11959
+ }
11960
+ return nodes.filter(
11961
+ (n) => n.role === "lifeline-footer" && lifelineLanes.has(n.lane) && (\u6570.get(n.lane) ?? 0) >= 2
11962
+ );
11963
+ }
11964
+ function footerShapeDropY(kind, h) {
11965
+ const extent = SHAPE_DRAW_UP_EXTENT[kind];
11966
+ if (extent === void 0) return 0;
11967
+ if (!Number.isFinite(h) || h <= 0) return 0;
11968
+ return Math.max(0, extent - h);
11969
+ }
11970
+ function footerShapeDrops(lanes, nodes) {
11971
+ return footerShapeDropsOf(lifelineFooterNodes(lanes, nodes));
11972
+ }
11973
+ function footerShapeDropsOf(footers) {
11974
+ const drops = /* @__PURE__ */ new Map();
11975
+ for (const footer of footers) {
11976
+ const dy = footerShapeDropY(footer.kind, footer.h);
11977
+ if (dy > 0) drops.set(footer.id, dy);
11978
+ }
11979
+ return drops;
11980
+ }
11981
+ function applyFooterShapeDrops(lanes, nodes) {
11982
+ const drops = footerShapeDrops(lanes, nodes);
11983
+ if (drops.size === 0) return nodes;
11984
+ return nodes.map((n) => {
11985
+ if (n.posX !== void 0 && n.posY !== void 0) return n;
11986
+ const dy = drops.get(n.id);
11987
+ return dy === void 0 ? n : { ...n, cy: n.cy + dy };
11988
+ });
11989
+ }
11990
+ function footerShapeDrawTop(node) {
11991
+ return node.cy - node.h / 2 - footerShapeDropY(node.kind, node.h);
11992
+ }
11993
+
11896
11994
  // src/layout/collisions.ts
11897
11995
  var LANE_LABEL_CLEARANCE_MARGIN = 2;
11898
11996
  function collectBBoxes(lanes, nodes, edges) {
@@ -11908,14 +12006,16 @@ function collectBBoxes(lanes, nodes, edges) {
11908
12006
  h: 28
11909
12007
  });
11910
12008
  }
12009
+ const footerDraw = footerShapeDrops(lanes, nodes);
11911
12010
  for (const n of nodes) {
12011
+ const up = footerDraw.get(n.id) ?? 0;
11912
12012
  out.push({
11913
12013
  kind: "node",
11914
12014
  id: n.id,
11915
12015
  x: n.cx - n.w / 2,
11916
- y: n.cy - n.h / 2,
12016
+ y: n.cy - n.h / 2 - up,
11917
12017
  w: n.w,
11918
- h: n.h
12018
+ h: n.h + up
11919
12019
  });
11920
12020
  }
11921
12021
  for (const e of edges) {
@@ -14898,67 +14998,6 @@ function layoutNodes(diag, lanes) {
14898
14998
  return out;
14899
14999
  }
14900
15000
 
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
15001
  // src/layout/viewbox.ts
14963
15002
  function computeViewBox(lanes, nodes, edges, bboxes, viewport) {
14964
15003
  let maxX = 0;
@@ -14979,11 +15018,6 @@ function computeViewBox(lanes, nodes, edges, bboxes, viewport) {
14979
15018
  maxX = Math.max(maxX, n.cx + n.w / 2);
14980
15019
  maxY = Math.max(maxY, n.cy + n.h / 2);
14981
15020
  }
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
15021
  if (!Number.isFinite(minX)) minX = 0;
14988
15022
  if (!Number.isFinite(minY)) minY = 0;
14989
15023
  const x = minX - VIEW_PAD;
@@ -15061,7 +15095,7 @@ function applyRowLevelNodeShifts(nodes, lanes, nodeShifts) {
15061
15095
  }
15062
15096
  function layout(diag) {
15063
15097
  const lanes = layoutLanes(diag);
15064
- const rawNodes = layoutNodes(diag, lanes);
15098
+ const rawNodes = applyFooterShapeDrops(lanes, layoutNodes(diag, lanes));
15065
15099
  const expandedLanes = expandLanesForNodes(lanes, rawNodes);
15066
15100
  const gapExpandedLanes = expandLaneGapsForEdgeLabels(expandedLanes, rawNodes, diag.edges);
15067
15101
  const nodes = rawNodes.map((n) => {
@@ -15580,7 +15614,7 @@ function templateRefIds(text) {
15580
15614
  return out;
15581
15615
  }
15582
15616
  function computeStateValues(laid, phaseIdx, progress) {
15583
- const values = {};
15617
+ const values = /* @__PURE__ */ Object.create(null);
15584
15618
  for (const s of laid.states) values[s.id] = s.initial;
15585
15619
  for (let i = 0; i < laid.phases.length; i++) {
15586
15620
  const phase = laid.phases[i];
@@ -15598,10 +15632,20 @@ function computeStateValues(laid, phaseIdx, progress) {
15598
15632
  }
15599
15633
  }
15600
15634
  }
15601
- const out = {};
15635
+ const out = /* @__PURE__ */ Object.create(null);
15602
15636
  for (const [k, v] of Object.entries(values)) out[k] = String(v);
15603
15637
  return withDerivedValues(out, laid.derived);
15604
15638
  }
15639
+ function mergeStateValues(base, overrides) {
15640
+ const merged = Object.assign(/* @__PURE__ */ Object.create(null), base);
15641
+ for (const key of Object.keys(overrides)) {
15642
+ const v = overrides[key];
15643
+ if (typeof v === "number" || typeof v === "string" || typeof v === "boolean") {
15644
+ merged[key] = String(v);
15645
+ }
15646
+ }
15647
+ return merged;
15648
+ }
15605
15649
  function interpolate(template, values) {
15606
15650
  return template.replace(TEMPLATE_REF_RE, (_, id, accessor) => {
15607
15651
  const raw = Object.hasOwn(values, id) ? values[id] : void 0;
@@ -15751,6 +15795,65 @@ function pathSubpath(d, progress) {
15751
15795
  return d;
15752
15796
  }
15753
15797
 
15798
+ // src/render/template-fields.ts
15799
+ var TEXT_FIELDS = ["title", "eyebrow", "subtitle", "value", "wBind", "hBind", "visibleIf"];
15800
+ var LIST_FIELDS = ["rows"];
15801
+ var NUMERIC_FIELDS = ["opacity", "renderOffsetX", "renderOffsetY"];
15802
+ var SHAPE_TEMPLATE_FIELDS = ["source", "radius", "fillProgress", "angle", "level", "rotation", "fill"];
15803
+ function shapeTexts(shape) {
15804
+ if (!shape) return [];
15805
+ const out = [];
15806
+ const \u4E2D\u8EAB = shape;
15807
+ for (const f of SHAPE_TEMPLATE_FIELDS) {
15808
+ const v = \u4E2D\u8EAB[f];
15809
+ if (typeof v === "string" && v) out.push(v);
15810
+ }
15811
+ return out;
15812
+ }
15813
+ function payloadTexts(node) {
15814
+ const out = [];
15815
+ const \u8DB3\u3059 = (v) => {
15816
+ if (typeof v === "string" && v) out.push(v);
15817
+ };
15818
+ for (const d of node.chartData ?? []) \u8DB3\u3059(d.value);
15819
+ for (const s of node.funnelData ?? []) \u8DB3\u3059(s.count);
15820
+ for (const t of node.ganttData ?? []) {
15821
+ \u8DB3\u3059(t.startIdx);
15822
+ \u8DB3\u3059(t.endIdx);
15823
+ }
15824
+ for (const i of node.quadrantData?.items ?? []) \u8DB3\u3059(i.quadrant);
15825
+ for (const s of node.journeyData ?? []) \u8DB3\u3059(s.emotion);
15826
+ for (const n of node.treeData ?? []) {
15827
+ \u8DB3\u3059(n.title);
15828
+ \u8DB3\u3059(n.subtitle);
15829
+ }
15830
+ if (node.mindData) {
15831
+ \u8DB3\u3059(node.mindData.rootTitle);
15832
+ for (const b of node.mindData.branches) {
15833
+ \u8DB3\u3059(b.title);
15834
+ \u8DB3\u3059(b.subtitle);
15835
+ }
15836
+ }
15837
+ return out;
15838
+ }
15839
+ function nodeTemplateTexts(node) {
15840
+ const out = [];
15841
+ for (const f of TEXT_FIELDS) {
15842
+ const v = node[f];
15843
+ if (typeof v === "string" && v) out.push(v);
15844
+ }
15845
+ for (const f of LIST_FIELDS) {
15846
+ for (const v of node[f] ?? []) if (v) out.push(v);
15847
+ }
15848
+ for (const f of NUMERIC_FIELDS) {
15849
+ const v = node[f];
15850
+ if (typeof v === "string" && v) out.push(v);
15851
+ }
15852
+ out.push(...shapeTexts(node.shape));
15853
+ out.push(...payloadTexts(node));
15854
+ return out;
15855
+ }
15856
+
15754
15857
  // src/validate.ts
15755
15858
  var TONES2 = new Set(TONES);
15756
15859
  var KINDS = new Set(NODE_KINDS);
@@ -15809,7 +15912,13 @@ function validate(diag) {
15809
15912
  const nodeIds = new Set(diag.nodes.map((n) => n.id));
15810
15913
  const edgeIds = new Set(diag.edges.map((e) => e.id));
15811
15914
  const stateIds = new Set(diag.states.map((s) => s.id));
15812
- const readableIds = /* @__PURE__ */ new Set([...stateIds, ...(diag.derived ?? []).map((d) => d.id)]);
15915
+ const readableIds = /* @__PURE__ */ new Set([
15916
+ ...stateIds,
15917
+ ...(diag.derived ?? []).map((d) => d.id),
15918
+ ...(diag.inputs ?? []).map((i) => i.id),
15919
+ ...(diag.formulas ?? []).map((f) => f.id),
15920
+ ...(diag.scrollTriggers ?? []).map((t) => t.id)
15921
+ ]);
15813
15922
  const suggest = (target, candidates) => {
15814
15923
  const list = [...candidates];
15815
15924
  if (list.length === 0) return "";
@@ -15876,10 +15985,7 @@ function validate(diag) {
15876
15985
  }
15877
15986
  }
15878
15987
  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) {
15988
+ for (const text of nodeTemplateTexts(n)) {
15883
15989
  for (const id of templateRefIds(text)) {
15884
15990
  if (!readableIds.has(id)) {
15885
15991
  warnings.push(`node "${n.id}" \u304C\u672A\u5B9A\u7FA9 state "${id}" \u3092\u53C2\u7167`);
@@ -15907,8 +16013,7 @@ function validate(diag) {
15907
16013
  for (const s of p.sets) stateUsed.add(s.stateId);
15908
16014
  }
15909
16015
  for (const n of diag.nodes) {
15910
- const texts2 = [n.value, ...n.rows ?? []].filter(Boolean);
15911
- for (const text of texts2) {
16016
+ for (const text of nodeTemplateTexts(n)) {
15912
16017
  for (const id of templateRefIds(text)) stateUsed.add(id);
15913
16018
  }
15914
16019
  }
@@ -15988,6 +16093,187 @@ function compile(diag) {
15988
16093
  validate(diag);
15989
16094
  return layout(diag);
15990
16095
  }
16096
+ var TITLE_MAX = 18;
16097
+ var TITLE_MIN = 9;
16098
+ var TITLE_RATIO = 0.17;
16099
+ var SUB_RATIO = 0.72;
16100
+ var LINE_GAP = 3;
16101
+ var BOTTOM_PAD = 4;
16102
+ var ASCENT = 0.72;
16103
+ var DESCENT = 0.25;
16104
+ var ART_GAP = 4;
16105
+ var ART_MIN_BAND = 45;
16106
+ var \u843D\u3068\u3057\u3066\u3082\u63CF\u304F\u7A2E\u5225 = {
16107
+ \u80A9\u66F8: /* @__PURE__ */ new Set([
16108
+ // basement 系 = `commonLabel` が自前の帯に置く
16109
+ "shape-file",
16110
+ "shape-folder",
16111
+ "shape-cloud",
16112
+ "shape-cylinder",
16113
+ "shape-hexagon",
16114
+ "shape-diamond",
16115
+ "shape-stack",
16116
+ // software 系 = 固有 layout
16117
+ "shape-window",
16118
+ "shape-terminal",
16119
+ "shape-code-block",
16120
+ "shape-message-bubble",
16121
+ "shape-gear",
16122
+ // hardware 系のうち固有 layout を持つもの
16123
+ "shape-iot-sensor",
16124
+ "shape-robot-arm"
16125
+ ]),
16126
+ \u8AAC\u660E: /* @__PURE__ */ new Set([
16127
+ // basement 系 = `commonLabel` が自前の帯に置く
16128
+ "shape-file",
16129
+ "shape-folder",
16130
+ "shape-cloud",
16131
+ "shape-cylinder",
16132
+ "shape-hexagon",
16133
+ "shape-diamond",
16134
+ "shape-stack",
16135
+ // software 系 = 固有 layout
16136
+ "shape-window",
16137
+ "shape-message-bubble",
16138
+ "shape-gear",
16139
+ // hardware / blockchain 系のうち固有 layout を持つもの
16140
+ "shape-iot-sensor",
16141
+ "shape-robot-arm",
16142
+ "shape-blockchain-block"
16143
+ ])
16144
+ };
16145
+ function droppedLineIsHidden(kind, line) {
16146
+ return kind.startsWith("shape-") && !\u843D\u3068\u3057\u3066\u3082\u63CF\u304F\u7A2E\u5225[line].has(kind);
16147
+ }
16148
+ function labelPlan(node) {
16149
+ const \u9AD8\u3055 = Math.max(0, node.h);
16150
+ const \u5E95 = node.cy + \u9AD8\u3055 / 2;
16151
+ const \u5929 = node.cy - \u9AD8\u3055 / 2;
16152
+ const \u7A4D\u3080 = (\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D) => {
16153
+ const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
16154
+ let y = \u5E95 - \u4E0B\u4F59\u767D;
16155
+ const \u8AAC\u660E = \u8AAC\u660E\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B57 } : null;
16156
+ if (\u8AAC\u660E !== null) y -= \u5C0F\u3055\u3044\u5B57 + LINE_GAP;
16157
+ const \u540D\u524D = { y, size: \u540D\u524D\u5927 };
16158
+ y -= \u540D\u524D\u5927 + LINE_GAP;
16159
+ const \u80A9\u66F8 = \u80A9\u66F8\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B57 } : null;
16160
+ const \u4E0A\u306E\u884C = \u80A9\u66F8 ?? \u540D\u524D;
16161
+ return { \u540D\u524D, \u8AAC\u660E, \u80A9\u66F8, \u4E0A\u7AEF: \u4E0A\u306E\u884C.y - \u4E0A\u306E\u884C.size * ASCENT };
16162
+ };
16163
+ 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;
16164
+ let \u8AAC\u660E\u3042\u308A = Boolean(node.subtitle);
16165
+ let \u80A9\u66F8\u3042\u308A = Boolean(node.eyebrow);
16166
+ const \u843D\u3068\u3057\u305F = [];
16167
+ if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A) && \u80A9\u66F8\u3042\u308A) {
16168
+ \u80A9\u66F8\u3042\u308A = false;
16169
+ \u843D\u3068\u3057\u305F.push("\u80A9\u66F8");
16170
+ }
16171
+ if (!\u5165\u308B(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A) && \u8AAC\u660E\u3042\u308A) {
16172
+ \u8AAC\u660E\u3042\u308A = false;
16173
+ \u843D\u3068\u3057\u305F.push("\u8AAC\u660E");
16174
+ }
16175
+ const \u7D44\u3080 = (\u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2) => {
16176
+ const \u4E0A\u9650 = Math.min(TITLE_MAX, Math.max(1, Math.round(\u9AD8\u3055 * TITLE_RATIO)));
16177
+ let \u540D\u524D\u5927 = 0;
16178
+ for (let size = \u4E0A\u9650; size >= 1; size--) {
16179
+ const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(size * SUB_RATIO));
16180
+ const \u4E0B\u306E\u884C\u5927 = \u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B572 : size;
16181
+ if (\u7A4D\u3080(size, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u306E\u884C\u5927 * DESCENT).\u4E0A\u7AEF >= \u5929) {
16182
+ \u540D\u524D\u5927 = size;
16183
+ break;
16184
+ }
16185
+ }
16186
+ if (\u540D\u524D\u5927 === 0) \u540D\u524D\u5927 = \u9AD8\u3055 / (ASCENT + DESCENT);
16187
+ const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
16188
+ const \u5F35\u308A\u51FA\u3057 = (\u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B57 : \u540D\u524D\u5927) * DESCENT;
16189
+ 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);
16190
+ const \u4E0B\u4F59\u767D = Math.min(Math.max(BOTTOM_PAD, \u5F35\u308A\u51FA\u3057), \u5F35\u308A\u51FA\u3057 + \u4F59\u308A);
16191
+ return \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D);
16192
+ };
16193
+ const \u7D75\u306E\u5E2F = (\u7D442) => Math.max(0, \u7D442.\u4E0A\u7AEF - ART_GAP - \u5929);
16194
+ let \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
16195
+ if (\u7D75\u306E\u5E2F(\u7D44) < ART_MIN_BAND && \u80A9\u66F8\u3042\u308A) {
16196
+ \u80A9\u66F8\u3042\u308A = false;
16197
+ \u843D\u3068\u3057\u305F.push("\u80A9\u66F8");
16198
+ \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
16199
+ }
16200
+ if (\u7D75\u306E\u5E2F(\u7D44) < ART_MIN_BAND && \u8AAC\u660E\u3042\u308A) {
16201
+ \u8AAC\u660E\u3042\u308A = false;
16202
+ \u843D\u3068\u3057\u305F.push("\u8AAC\u660E");
16203
+ \u7D44 = \u7D44\u3080(\u8AAC\u660E\u3042\u308A, \u80A9\u66F8\u3042\u308A);
16204
+ }
16205
+ const \u4E00\u756A\u5C0F\u3055\u3044\u884C = Math.min(
16206
+ ...[\u7D44.\u540D\u524D, \u7D44.\u8AAC\u660E, \u7D44.\u80A9\u66F8].filter((l) => l !== null).map((l) => l.size)
16207
+ );
16208
+ return {
16209
+ \u540D\u524D: \u7D44.\u540D\u524D,
16210
+ \u8AAC\u660E: \u7D44.\u8AAC\u660E,
16211
+ \u80A9\u66F8: \u7D44.\u80A9\u66F8,
16212
+ top: \u7D44.\u4E0A\u7AEF,
16213
+ \u8AAD\u3081\u308B: \u4E00\u756A\u5C0F\u3055\u3044\u884C >= TITLE_MIN,
16214
+ \u843D\u3068\u3057\u305F
16215
+ };
16216
+ }
16217
+ function shapeRegion(node) {
16218
+ const label = labelPlan(node);
16219
+ const \u5929 = node.cy - node.h / 2;
16220
+ const availH = Math.max(0, label.top - ART_GAP - \u5929);
16221
+ return {
16222
+ cx: node.cx,
16223
+ cy: \u5929 + availH / 2,
16224
+ availW: node.w,
16225
+ availH,
16226
+ labelY: label.\u540D\u524D.y,
16227
+ label
16228
+ };
16229
+ }
16230
+ var SHADOW_GAP = 8;
16231
+ var FRAME_HALF = 1.5;
16232
+ function bodyBand(node, opt) {
16233
+ const \u5F71 = Math.max(0, opt.\u5F71ry);
16234
+ const \u5916 = Math.max(0, opt.\u5916 ?? FRAME_HALF);
16235
+ const \u4E0B\u4F59\u767D = Math.max(SHADOW_GAP + \u5F71, \u5916);
16236
+ const \u7BB1w = Math.max(0, node.w);
16237
+ const \u7BB1h = Math.max(0, node.h);
16238
+ const \u7E26\u4F59\u767D = \u5916 + \u4E0B\u4F59\u767D;
16239
+ const ky = \u7E26\u4F59\u767D > \u7BB1h && \u7E26\u4F59\u767D > 0 ? \u7BB1h / \u7E26\u4F59\u767D : 1;
16240
+ const \u6A2A\u4F59\u767D = \u5916 * 2;
16241
+ const kx = \u6A2A\u4F59\u767D > \u7BB1w && \u6A2A\u4F59\u767D > 0 ? \u7BB1w / \u6A2A\u4F59\u767D : 1;
16242
+ const x = node.cx - \u7BB1w / 2 + \u5916 * kx;
16243
+ const y = node.cy - \u7BB1h / 2 + \u5916 * ky;
16244
+ const w = Math.max(0, \u7BB1w - \u6A2A\u4F59\u767D * kx);
16245
+ const h = Math.max(0, \u7BB1h - \u7E26\u4F59\u767D * ky);
16246
+ return { x, y, w, h, cx: x + w / 2, cy: y + h / 2, \u53F3: x + w, \u5E95: y + h };
16247
+ }
16248
+ function fitLabel(band, block, pos) {
16249
+ const \u7E26 = block.\u4E0A + block.\u4E0B;
16250
+ const \u6A2A = Math.max(0, block.\u5E45);
16251
+ if (!(\u7E26 > 0)) return { k: 1, x: pos.x, y: pos.y };
16252
+ if (!(band.h > 0) || !(band.w > 0)) return { k: 0, x: band.x + band.w / 2, y: band.y };
16253
+ const k = Math.min(1, band.h / \u7E26, \u6A2A > 0 ? band.w / \u6A2A : 1);
16254
+ const \u534A = \u6A2A * k / 2;
16255
+ return {
16256
+ k,
16257
+ x: Math.max(band.x + \u534A, Math.min(pos.x, band.x + band.w - \u534A)),
16258
+ y: Math.max(band.y + block.\u4E0A * k, Math.min(pos.y, band.y + band.h - block.\u4E0B * k))
16259
+ };
16260
+ }
16261
+ function fitArt(region, extent, art) {
16262
+ const \u7E26 = extent.\u4E0A + extent.\u4E0B;
16263
+ const \u6A2A = extent.\u5DE6 + extent.\u53F3;
16264
+ if (!Number.isFinite(\u7E26) || !Number.isFinite(\u6A2A) || \u7E26 <= 0 || \u6A2A <= 0) return art;
16265
+ if (!Number.isFinite(region.availH) || !Number.isFinite(region.availW) || region.availH <= 0 || region.availW <= 0) {
16266
+ return art;
16267
+ }
16268
+ const s = Math.min(1, region.availH / \u7E26, region.availW / \u6A2A);
16269
+ if (!Number.isFinite(s) || s <= 0) return art;
16270
+ const \u7D75cx = region.cx + (extent.\u53F3 - extent.\u5DE6) / 2;
16271
+ const \u7D75cy = region.cy + (extent.\u4E0B - extent.\u4E0A) / 2;
16272
+ const dx = region.cx - s * \u7D75cx;
16273
+ const dy = region.cy - s * \u7D75cy;
16274
+ if (s >= 1 && dx === 0 && dy === 0) return art;
16275
+ return /* @__PURE__ */ jsx("g", { transform: `translate(${dx} ${dy}) scale(${s})`, children: art });
16276
+ }
15991
16277
 
15992
16278
  // src/layout/geometry.ts
15993
16279
  function pointRectEdgeDistance(px, py, rect) {
@@ -16154,6 +16440,7 @@ function emptyCounts() {
16154
16440
  "validate-performance-budget": 0,
16155
16441
  "node-inside-viewbox": 0,
16156
16442
  "node-inside-lane": 0,
16443
+ "shape-label-dropped": 0,
16157
16444
  "edge-inside-viewbox": 0,
16158
16445
  "lane-label-inside-viewbox": 0,
16159
16446
  "lane-label-overlap": 0,
@@ -16844,6 +17131,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
16844
17131
  for (const n of laid.nodes) {
16845
17132
  if (n.id.endsWith("-spacer")) continue;
16846
17133
  if (!rendersTitleText(n.kind)) continue;
17134
+ if (fitsOwnTitleWidth(n.kind)) continue;
16847
17135
  if (!isRenderedNode(n)) continue;
16848
17136
  const titleTrimmed = n.title?.trim() ?? "";
16849
17137
  if (!titleTrimmed) continue;
@@ -17100,6 +17388,15 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
17100
17388
  );
17101
17389
  }
17102
17390
  }
17391
+ for (const n of laid.nodes) {
17392
+ const \u843D\u3068\u3057\u305F = labelPlan(n).\u843D\u3068\u3057\u305F.filter((line) => droppedLineIsHidden(n.kind, line));
17393
+ if (\u843D\u3068\u3057\u305F.length === 0) continue;
17394
+ push(
17395
+ "shape-label-dropped",
17396
+ `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`,
17397
+ "warn"
17398
+ );
17399
+ }
17103
17400
  for (const e of laid.edges) {
17104
17401
  const segs = flattenPathSegments(extractPathSegments(e.d));
17105
17402
  if (segs.length === 0) continue;
@@ -18344,6 +18641,7 @@ function validateMetaAxes(totalCounts, diagrams = [], durations = [], reports =
18344
18641
  "validate-performance-budget",
18345
18642
  "node-inside-viewbox",
18346
18643
  "node-inside-lane",
18644
+ "shape-label-dropped",
18347
18645
  "edge-inside-viewbox",
18348
18646
  "lane-label-inside-viewbox",
18349
18647
  "lane-label-overlap",
@@ -18412,6 +18710,7 @@ function validateMetaAxes(totalCounts, diagrams = [], durations = [], reports =
18412
18710
  "validate-performance-budget",
18413
18711
  "node-inside-viewbox",
18414
18712
  "node-inside-lane",
18713
+ "shape-label-dropped",
18415
18714
  "edge-inside-viewbox",
18416
18715
  "lane-label-inside-viewbox",
18417
18716
  "lane-label-overlap",
@@ -18438,7 +18737,7 @@ function validateMetaAxes(totalCounts, diagrams = [], durations = [], reports =
18438
18737
  });
18439
18738
  }
18440
18739
  }
18441
- const EXPECTED_AXIS_COUNT = 66;
18740
+ const EXPECTED_AXIS_COUNT = 67;
18442
18741
  if (allAxes.length !== EXPECTED_AXIS_COUNT) {
18443
18742
  out.push({
18444
18743
  axis: "axis-documentation-completeness",
@@ -19650,7 +19949,7 @@ function StateDiffCard({
19650
19949
  ] }) }),
19651
19950
  /* @__PURE__ */ jsx("tbody", { style: { color: "var(--cdl-text, #1a1f2a)" }, children: states.map((s) => {
19652
19951
  const initial = String(s.initial);
19653
- const current = stateValues[s.id] ?? initial;
19952
+ const current = Object.hasOwn(stateValues, s.id) ? stateValues[s.id] : initial;
19654
19953
  const changed = initial !== current;
19655
19954
  return /* @__PURE__ */ jsxs("tr", { children: [
19656
19955
  /* @__PURE__ */ jsx("td", { className: "py-1 text-left text-[12px]", children: s.id }),
@@ -19939,14 +20238,14 @@ function fitTextSize(text, maxWidth, targetSize, minSize) {
19939
20238
  var COMPACT_MAX_H = 100;
19940
20239
  var COMPACT_PADDING_X = 16;
19941
20240
  var MIN_SIZE = 11;
19942
- var ASCENT = 0.72;
19943
- var DESCENT = 0.25;
19944
- var MIN_BAND_H = MIN_SIZE * (ASCENT + DESCENT);
20241
+ var ASCENT2 = 0.72;
20242
+ var DESCENT2 = 0.25;
20243
+ var MIN_BAND_H = MIN_SIZE * (ASCENT2 + DESCENT2);
19945
20244
  var EYEBROW_BASELINE = 38;
19946
20245
  var EYEBROW_SIZE = 18;
19947
20246
  var EYEBROW_GAP = 8;
19948
20247
  var BOTTOM_INSET = 4;
19949
- var eyebrowBottom = () => EYEBROW_BASELINE + EYEBROW_SIZE * DESCENT;
20248
+ var eyebrowBottom = () => EYEBROW_BASELINE + EYEBROW_SIZE * DESCENT2;
19950
20249
  var titleBandTop = (hasEyebrow) => eyebrowBottom() + EYEBROW_GAP ;
19951
20250
  var isCompactBox = (h) => h < COMPACT_MAX_H;
19952
20251
  function titlePlacement(node, \u901A\u5E38, opts = {}) {
@@ -19965,10 +20264,10 @@ function titlePlacement(node, \u901A\u5E38, opts = {}) {
19965
20264
  \u901A\u5E38.size,
19966
20265
  MIN_SIZE
19967
20266
  );
19968
- const \u5E2F\u3067 = Math.floor(\u5E2F / (ASCENT + DESCENT));
20267
+ const \u5E2F\u3067 = Math.floor(\u5E2F / (ASCENT2 + DESCENT2));
19969
20268
  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;
20269
+ const \u5B57\u9AD8 = size * (ASCENT2 + DESCENT2);
20270
+ 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
20271
  return { x: node.w / 2, y, size, anchor: "middle" };
19973
20272
  }
19974
20273
  function ActorNode({ node, active, value }) {
@@ -20932,21 +21231,32 @@ function resolveBoundText(raw, values) {
20932
21231
  return hasUnresolvedRef(resolved) ? { value: resolved, ok: false } : { value: resolved, ok: true };
20933
21232
  }
20934
21233
  function resolveTreeData(nodes, values) {
20935
- if (!nodes.some((n) => n.title.includes("{"))) return nodes;
21234
+ const \u8AAD\u3080 = nodes.some((n) => n.title.includes("{") || (n.subtitle?.includes("{") ?? false));
21235
+ if (!\u8AAD\u3080) return nodes;
20936
21236
  return nodes.map((n) => {
20937
21237
  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 };
21238
+ const subtitle = n.subtitle === void 0 ? void 0 : resolveBoundText(n.subtitle, values);
21239
+ const \u89E3\u6C7A\u5F8C = {
21240
+ ...n,
21241
+ title: title.value,
21242
+ ...subtitle ? { subtitle: subtitle.value } : {}
21243
+ };
21244
+ return title.ok && (subtitle?.ok ?? true) ? \u89E3\u6C7A\u5F8C : { ...\u89E3\u6C7A\u5F8C, unresolved: true };
20940
21245
  });
20941
21246
  }
20942
21247
  function resolveMindData(data, values) {
20943
- const \u8AAD\u3080 = data.rootTitle.includes("{") || data.branches.some((b) => b.title.includes("{"));
21248
+ const \u8AAD\u3080 = data.rootTitle.includes("{") || data.branches.some((b) => b.title.includes("{") || (b.subtitle?.includes("{") ?? false));
20944
21249
  if (!\u8AAD\u3080) return data;
20945
21250
  const root = resolveBoundText(data.rootTitle, values);
20946
21251
  const branches = data.branches.map((b) => {
20947
21252
  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 };
21253
+ const subtitle = b.subtitle === void 0 ? void 0 : resolveBoundText(b.subtitle, values);
21254
+ const \u89E3\u6C7A\u5F8C2 = {
21255
+ ...b,
21256
+ title: title.value,
21257
+ ...subtitle ? { subtitle: subtitle.value } : {}
21258
+ };
21259
+ return title.ok && (subtitle?.ok ?? true) ? \u89E3\u6C7A\u5F8C2 : { ...\u89E3\u6C7A\u5F8C2, unresolved: true };
20950
21260
  });
20951
21261
  const \u89E3\u6C7A\u5F8C = { ...data, rootTitle: root.value, branches };
20952
21262
  return root.ok ? \u89E3\u6C7A\u5F8C : { ...\u89E3\u6C7A\u5F8C, unresolved: true };
@@ -21357,16 +21667,53 @@ function GanttNode({
21357
21667
  const rowGap = 20;
21358
21668
  const rowCount = tasks.length || 1;
21359
21669
  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)));
21670
+ const \u4F4D\u7F6E\u306E\u4E0A\u9650 = 1e6;
21671
+ const \u53CE\u3081\u305F = tasks.map((t) => {
21672
+ const \u59CB = Math.min(\u4F4D\u7F6E\u306E\u4E0A\u9650, Math.max(0, Number.isFinite(t.startIdx) ? t.startIdx : 0));
21673
+ const \u7D42 = Math.min(\u4F4D\u7F6E\u306E\u4E0A\u9650, Math.max(\u59CB, Number.isFinite(t.endIdx) ? t.endIdx : \u59CB));
21674
+ return { ...t, startIdx: \u59CB, endIdx: \u7D42 };
21675
+ });
21676
+ const \u5BA3\u8A00 = node.ganttAxisMax;
21677
+ 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;
21678
+ const maxIdx = \u5BA3\u8A00\u3057\u305F\u5C3A ?? Math.max(
21679
+ 1,
21680
+ Math.ceil(Math.max(...\u53CE\u3081\u305F.flatMap((t) => [t.startIdx + 1, t.endIdx + 1]), 1))
21681
+ );
21361
21682
  const cellW = canvasW / maxIdx;
21683
+ const \u6700\u5F8C\u306E\u76EE\u76DB\u308A = maxIdx - 1;
21684
+ const \u6574\u3048\u305F = \u5BA3\u8A00\u3057\u305F\u5C3A === void 0 ? \u53CE\u3081\u305F : \u53CE\u3081\u305F.map((t) => {
21685
+ const \u59CB = Math.min(t.startIdx, \u6700\u5F8C\u306E\u76EE\u76DB\u308A);
21686
+ const \u7D42 = Math.min(t.endIdx, \u6700\u5F8C\u306E\u76EE\u76DB\u308A);
21687
+ const \u5BC4\u305B\u305F = \u59CB !== t.startIdx || \u7D42 !== t.endIdx;
21688
+ return \u5BC4\u305B\u305F ? { ...t, startIdx: \u59CB, endIdx: \u7D42, clipped: true } : t;
21689
+ });
21690
+ const \u76EE\u76DB\u308A\u306E\u4E0A\u9650 = 200;
21691
+ const \u76EE\u76DB\u308A\u306E\u9593\u9694 = Math.max(1, Math.ceil(maxIdx / \u76EE\u76DB\u308A\u306E\u4E0A\u9650));
21692
+ const \u76EE\u76DB\u308A\u306E\u672C\u6570 = Math.ceil(maxIdx / \u76EE\u76DB\u308A\u306E\u9593\u9694);
21362
21693
  const xAt = (idx) => PAD_LEFT + idx * cellW;
21363
21694
  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]));
21695
+ 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() };
21696
+ const \u7F6E\u304F = (\u8868, \u4F4D\u7F6E, label) => {
21697
+ if (label !== "" && Number.isFinite(\u4F4D\u7F6E) && !\u8868.has(\u4F4D\u7F6E)) \u8868.set(\u4F4D\u7F6E, label);
21698
+ };
21699
+ for (const t of \u53CE\u3081\u305F) {
21700
+ const \u6574\u6570\u306E\u958B\u59CB = Number.isInteger(t.startIdx);
21701
+ \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);
21702
+ const \u6574\u6570\u306E\u7D42\u4E86 = Number.isInteger(t.endIdx);
21703
+ \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);
21704
+ }
21705
+ 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) ?? "";
21706
+ const \u4F4D\u7F6E\u306E\u96C6\u5408 = /* @__PURE__ */ new Set();
21707
+ 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);
21708
+ 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]) {
21709
+ for (const i of \u8868.keys()) if (i >= 0 && i < maxIdx) \u4F4D\u7F6E\u306E\u96C6\u5408.add(i);
21710
+ }
21711
+ const gridLabels = [...\u4F4D\u7F6E\u306E\u96C6\u5408].sort((a, b) => a - b).map((i) => ({ \u4F4D\u7F6E: i, label: \u540D\u524D\u3092\u5F15\u304F(i) }));
21712
+ const \u5E2F\u306E\u4F59\u767D = Math.min(6, cellW / 2);
21713
+ const \u5E2F\u306E\u5DE6 = (idx) => xAt(idx) + \u5E2F\u306E\u4F59\u767D / 2;
21714
+ const \u5E2F\u306E\u53F3 = (idx) => xAt(idx) + cellW - \u5E2F\u306E\u4F59\u767D / 2;
21715
+ const taskById = new Map(\u6574\u3048\u305F.map((t) => [t.id, t]));
21716
+ const rowOf = new Map(\u6574\u3048\u305F.map((t, i) => [t.id, i]));
21370
21717
  return /* @__PURE__ */ jsxs("g", { transform: `translate(${x0} ${y0})`, children: [
21371
21718
  /* @__PURE__ */ jsx(
21372
21719
  "rect",
@@ -21382,10 +21729,11 @@ function GanttNode({
21382
21729
  strokeWidth: active ? 3 : 1.25
21383
21730
  }
21384
21731
  ),
21385
- gridLabels.map((label, i) => /* @__PURE__ */ jsxs("g", { children: [
21732
+ gridLabels.map(({ \u4F4D\u7F6E: i, label }) => /* @__PURE__ */ jsxs("g", { children: [
21386
21733
  /* @__PURE__ */ jsx(
21387
21734
  "line",
21388
21735
  {
21736
+ "data-cdl-role": "gantt-grid",
21389
21737
  x1: xAt(i),
21390
21738
  y1: PAD_TOP,
21391
21739
  x2: xAt(i),
@@ -21396,9 +21744,10 @@ function GanttNode({
21396
21744
  opacity: 0.5
21397
21745
  }
21398
21746
  ),
21399
- /* @__PURE__ */ jsx(
21747
+ label === "" ? null : /* @__PURE__ */ jsx(
21400
21748
  "text",
21401
21749
  {
21750
+ "data-cdl-role": "gantt-tick",
21402
21751
  x: xAt(i) + cellW / 2,
21403
21752
  y: PAD_TOP + canvasH + 18,
21404
21753
  fontSize: 11,
@@ -21420,7 +21769,7 @@ function GanttNode({
21420
21769
  opacity: 0.5
21421
21770
  }
21422
21771
  ),
21423
- tasks.map((t, row) => /* @__PURE__ */ jsx(
21772
+ \u6574\u3048\u305F.map((t, row) => /* @__PURE__ */ jsx(
21424
21773
  "text",
21425
21774
  {
21426
21775
  x: PAD_LEFT - 12,
@@ -21433,16 +21782,17 @@ function GanttNode({
21433
21782
  },
21434
21783
  `label-${t.id}`
21435
21784
  )),
21436
- tasks.map((t, row) => {
21437
- const bx = xAt(t.startIdx) + 3;
21785
+ \u6574\u3048\u305F.map((t, row) => {
21786
+ const bx = \u5E2F\u306E\u5DE6(t.startIdx);
21438
21787
  const by = yAt(row);
21439
- const bw = Math.max(cellW - 6, (t.endIdx - t.startIdx + 1) * cellW - 6);
21788
+ const bw = Math.max(0, \u5E2F\u306E\u53F3(t.endIdx) - bx);
21440
21789
  return /* @__PURE__ */ jsxs("g", { children: [
21441
21790
  /* @__PURE__ */ jsx(
21442
21791
  "rect",
21443
21792
  {
21444
21793
  "data-cdl-role": "gantt-bar",
21445
21794
  "data-cdl-unresolved": t.unresolved ? "true" : void 0,
21795
+ "data-cdl-clipped": "clipped" in t && t.clipped ? "true" : void 0,
21446
21796
  x: bx,
21447
21797
  y: by,
21448
21798
  width: bw,
@@ -21465,13 +21815,13 @@ function GanttNode({
21465
21815
  )
21466
21816
  ] }, `bar-${t.id}`);
21467
21817
  }),
21468
- tasks.filter((t) => t.dependsOn && taskById.has(t.dependsOn)).map((t) => {
21818
+ \u6574\u3048\u305F.filter((t) => t.dependsOn && taskById.has(t.dependsOn)).map((t) => {
21469
21819
  const parent = taskById.get(t.dependsOn);
21470
21820
  const parentRow = rowOf.get(parent.id);
21471
21821
  const childRow = rowOf.get(t.id);
21472
- const parentBarRight = xAt(parent.endIdx) + cellW - 3;
21822
+ const parentBarRight = \u5E2F\u306E\u53F3(parent.endIdx);
21473
21823
  const parentMidY = yAt(parentRow) + rowH / 2;
21474
- const childBarLeft = xAt(t.startIdx) + 3;
21824
+ const childBarLeft = \u5E2F\u306E\u5DE6(t.startIdx);
21475
21825
  const childMidY = yAt(childRow) + rowH / 2;
21476
21826
  const arrowHeadSize = 8;
21477
21827
  const arrowHeadTipGap = 10;
@@ -21513,6 +21863,49 @@ function toneColor3(tone) {
21513
21863
  if (!tone) return TONE.accent;
21514
21864
  return TONE[tone];
21515
21865
  }
21866
+
21867
+ // src/kinds/box-lines.ts
21868
+ var \u884C\u9001\u308A\u306E\u6BD4 = 1.15;
21869
+ var \u5B57\u306E\u9AD8\u3055\u306E\u6BD4 = 0.72;
21870
+ var \u4E0A\u4E0B\u306E\u4F59\u767D = 2;
21871
+ var \u5DE6\u53F3\u306E\u4F59\u767D = 8;
21872
+ function \u5E45\u3067\u5207\u308B(text, fontSize, \u4F7F\u3048\u308B\u5E45, \u6E2C\u308B = textWidth) {
21873
+ if (\u4F7F\u3048\u308B\u5E45 <= 0) return "";
21874
+ if (\u6E2C\u308B(text, fontSize) <= \u4F7F\u3048\u308B\u5E45) return text;
21875
+ const \u7701\u7565 = "\u2026";
21876
+ const \u7701\u7565\u306E\u5E45 = \u6E2C\u308B(\u7701\u7565, fontSize);
21877
+ if (\u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E45) return "";
21878
+ let \u51FA = "";
21879
+ let \u5E45 = 0;
21880
+ for (const c of \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text)) {
21881
+ const \u5B57\u306E\u5E452 = \u6E2C\u308B(c, fontSize);
21882
+ if (\u5E45 + \u5B57\u306E\u5E452 + \u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E45) break;
21883
+ \u5E45 += \u5B57\u306E\u5E452;
21884
+ \u51FA += c;
21885
+ }
21886
+ return `${\u51FA}${\u7701\u7565}`;
21887
+ }
21888
+ function \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text) {
21889
+ const \u533A\u5207\u308A = Intl.Segmenter;
21890
+ if (typeof \u533A\u5207\u308A !== "function") return [...text];
21891
+ return [...new \u533A\u5207\u308A(void 0, { granularity: "grapheme" }).segment(text)].map((g) => g.segment);
21892
+ }
21893
+ function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u3055) {
21894
+ const \u5019\u88DC = \u884C.filter((r, i) => i === 0 || r.text.trim() !== "");
21895
+ if (\u5019\u88DC.length === 0) return [];
21896
+ const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u3055 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
21897
+ const \u9AD8\u3055 = (rs) => rs.reduce((a, r) => a + r.fontSize * \u884C\u9001\u308A\u306E\u6BD4, 0);
21898
+ const \u6B8B\u3059 = [...\u5019\u88DC];
21899
+ while (\u6B8B\u3059.length > 1 && \u9AD8\u3055(\u6B8B\u3059) > \u4F7F\u3048\u308B\u9AD8\u3055) \u6B8B\u3059.pop();
21900
+ const \u4F7F\u3048\u308B\u5E45 = \u7BB1\u306E\u5E45 - \u5DE6\u53F3\u306E\u4F59\u767D * 2;
21901
+ const \u7DCF\u9AD8 = \u9AD8\u3055(\u6B8B\u3059);
21902
+ let \u7A4D\u307F = -\u7DCF\u9AD8 / 2;
21903
+ return \u6B8B\u3059.map((r) => {
21904
+ const dy = \u7A4D\u307F + (\u884C\u9001\u308A\u306E\u6BD4 + \u5B57\u306E\u9AD8\u3055\u306E\u6BD4) / 2 * r.fontSize;
21905
+ \u7A4D\u307F += r.fontSize * \u884C\u9001\u308A\u306E\u6BD4;
21906
+ return { ...r, text: \u5E45\u3067\u5207\u308B(r.text, r.fontSize, \u4F7F\u3048\u308B\u5E45), dy };
21907
+ });
21908
+ }
21516
21909
  var MIND_TONES = ["accent", "teal", "success", "warning", "info", "error"];
21517
21910
  var MIND_BOX_GAP = 24;
21518
21911
  function MindMapNode({
@@ -21558,33 +21951,59 @@ function MindMapNode({
21558
21951
  },
21559
21952
  `edge-${i}`
21560
21953
  )),
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}`))
21954
+ layout2.nodes.map((n) => {
21955
+ const \u884C = \u7BB1\u306B\u7A4D\u3080(
21956
+ [
21957
+ { \u5F79\u5272: "title", text: n.title, fontSize: n.isRoot ? 15 : 13 },
21958
+ { \u5F79\u5272: "subtitle", text: n.subtitle ?? "", fontSize: 9 }
21959
+ ],
21960
+ n.w,
21961
+ n.h
21962
+ );
21963
+ const \u88DC\u8DB3\u3042\u308A = (n.subtitle ?? "").trim() !== "";
21964
+ const \u6587\u5B57\u306E\u8272 = n.isRoot ? "var(--cdl-text-on-tone, #ffffff)" : "var(--cdl-chip-text, #1a1f2a)";
21965
+ return /* @__PURE__ */ jsxs("g", { "data-cdl-unresolved": n.unresolved ? "true" : void 0, children: [
21966
+ /* @__PURE__ */ jsx(
21967
+ "rect",
21968
+ {
21969
+ x: n.x - n.w / 2,
21970
+ y: n.y - n.h / 2,
21971
+ width: n.w,
21972
+ height: n.h,
21973
+ rx: n.isRoot ? 22 : 10,
21974
+ fill: n.isRoot ? toneColor4(n.tone ?? "accent") : "var(--cdl-chip-fill, #f4f6fb)",
21975
+ stroke: n.isRoot ? toneColor4(n.tone ?? "accent") : toneColor4(n.tone),
21976
+ strokeWidth: n.isRoot ? 2 : 1.75
21977
+ }
21978
+ ),
21979
+ \u88DC\u8DB3\u3042\u308A ? \u884C.map((r) => /* @__PURE__ */ jsx(
21980
+ "text",
21981
+ {
21982
+ "data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "mind-node-subtitle" : void 0,
21983
+ x: n.x,
21984
+ y: n.y + r.dy,
21985
+ fontSize: r.fontSize,
21986
+ fontWeight: r.\u5F79\u5272 === "title" ? n.isRoot ? 700 : 600 : 500,
21987
+ textAnchor: "middle",
21988
+ fill: \u6587\u5B57\u306E\u8272,
21989
+ opacity: r.\u5F79\u5272 === "subtitle" ? 0.85 : void 0,
21990
+ children: r.text
21991
+ },
21992
+ r.\u5F79\u5272
21993
+ )) : /* @__PURE__ */ jsx(
21994
+ "text",
21995
+ {
21996
+ x: n.x,
21997
+ y: n.y + 5,
21998
+ fontSize: n.isRoot ? 15 : 13,
21999
+ fontWeight: n.isRoot ? 700 : 600,
22000
+ textAnchor: "middle",
22001
+ fill: \u6587\u5B57\u306E\u8272,
22002
+ children: n.title
22003
+ }
22004
+ )
22005
+ ] }, `n-${n.id}`);
22006
+ })
21588
22007
  ] });
21589
22008
  }
21590
22009
  function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
@@ -21706,6 +22125,7 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
21706
22125
  nodes.push({
21707
22126
  id: node.id,
21708
22127
  title: node.title,
22128
+ ...node.subtitle !== void 0 ? { subtitle: node.subtitle } : {},
21709
22129
  x,
21710
22130
  y,
21711
22131
  w,
@@ -21910,6 +22330,9 @@ function QuadrantNode({
21910
22330
  const PAD_BOTTOM = 56;
21911
22331
  const AXIS_LABEL_FONT = 12;
21912
22332
  const PAD_MIN = 60;
22333
+ const ITEM_FONT = 13;
22334
+ const ITEM_PAD_X = 12;
22335
+ const ITEM_MIN_W = 48;
21913
22336
  const axisLabelPad = (text) => Math.max(PAD_MIN, measureTextWidth(`\u2190 ${text}`, { fontSize: AXIS_LABEL_FONT}) + 12);
21914
22337
  const padBudget = Math.max(0, node.w * 0.5 - PAD_MIN * 2);
21915
22338
  const wantLeft = axisLabelPad(data.xAxis.left) - PAD_MIN;
@@ -22005,6 +22428,12 @@ function QuadrantNode({
22005
22428
  const qxStart = (isLeft ? PAD_LEFT : cx) + 18;
22006
22429
  const qyStart = (isTop ? PAD_TOP : cy) + 44;
22007
22430
  const qHalfW = halfW - 36;
22431
+ const \u67A0\u306E\u4F59\u5730 = qHalfW;
22432
+ if (\u67A0\u306E\u4F59\u5730 <= 0) return null;
22433
+ const \u67A0\u306E\u5E45 = (title) => Math.min(
22434
+ \u67A0\u306E\u4F59\u5730,
22435
+ Math.max(ITEM_MIN_W, measureTextWidth(title, { fontSize: ITEM_FONT}) + ITEM_PAD_X * 2)
22436
+ );
22008
22437
  const qHalfH = halfH - 60;
22009
22438
  const gap = 10;
22010
22439
  const rowH = 34;
@@ -22019,7 +22448,7 @@ function QuadrantNode({
22019
22448
  "data-cdl-unresolved": it.unresolved ? "true" : void 0,
22020
22449
  x: qxStart,
22021
22450
  y: py,
22022
- width: qHalfW,
22451
+ width: \u67A0\u306E\u5E45(it.title),
22023
22452
  height: rowH,
22024
22453
  rx: 6,
22025
22454
  fill: "var(--cdl-node-fill, #ffffff)",
@@ -22027,12 +22456,35 @@ function QuadrantNode({
22027
22456
  strokeWidth: 1.5
22028
22457
  }
22029
22458
  ),
22030
- /* @__PURE__ */ jsx("text", { x: qxStart + 12, y: py + rowH / 2 + 5, fontSize: 13, fontWeight: 600, fill: "var(--cdl-text, #1a1f2a)", children: it.title })
22459
+ /* @__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
22460
  ] }, `item-${it.id}`);
22032
22461
  });
22033
22462
  })
22034
22463
  ] });
22035
22464
  }
22465
+ function \u7BB1\u306E\u6587\u5B57({
22466
+ \u884C,
22467
+ x,
22468
+ \u7BB1\u306E\u9AD8\u3055,
22469
+ fill,
22470
+ \u540D\u524D\u306E\u592A\u3055
22471
+ }) {
22472
+ return \u884C.map((r) => /* @__PURE__ */ jsx(
22473
+ "text",
22474
+ {
22475
+ "data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "tree-node-subtitle" : void 0,
22476
+ x,
22477
+ y: \u7BB1\u306E\u9AD8\u3055 / 2 + r.dy,
22478
+ fontSize: r.fontSize,
22479
+ fontWeight: r.\u5F79\u5272 === "title" ? \u540D\u524D\u306E\u592A\u3055 : 500,
22480
+ textAnchor: "middle",
22481
+ fill,
22482
+ opacity: r.\u5F79\u5272 === "subtitle" ? 0.85 : void 0,
22483
+ children: r.text
22484
+ },
22485
+ r.\u5F79\u5272
22486
+ ));
22487
+ }
22036
22488
  function TreeNode({
22037
22489
  node,
22038
22490
  active,
@@ -22095,6 +22547,15 @@ function TreeNode({
22095
22547
  layout2.nodes.map((n) => {
22096
22548
  const accent = depthColors[Math.min(n.depth, depthColors.length - 1)] ?? depthColors[0];
22097
22549
  const isRoot = n.depth === 0;
22550
+ const \u884C = \u7BB1\u306B\u7A4D\u3080(
22551
+ [
22552
+ { \u5F79\u5272: "title", text: n.title, fontSize: isRoot ? 13 : 12 },
22553
+ { \u5F79\u5272: "subtitle", text: n.subtitle ?? "", fontSize: 9 }
22554
+ ],
22555
+ n.w,
22556
+ n.h
22557
+ );
22558
+ const \u88DC\u8DB3\u3042\u308A = (n.subtitle ?? "").trim() !== "";
22098
22559
  return /* @__PURE__ */ jsx(
22099
22560
  "g",
22100
22561
  {
@@ -22113,7 +22574,13 @@ function TreeNode({
22113
22574
  fill: `url(#${gradientId})`
22114
22575
  }
22115
22576
  ),
22116
- /* @__PURE__ */ jsx(
22577
+ \u88DC\u8DB3\u3042\u308A ? \u7BB1\u306E\u6587\u5B57({
22578
+ \u884C,
22579
+ x: n.w / 2,
22580
+ \u7BB1\u306E\u9AD8\u3055: n.h,
22581
+ fill: "var(--cdl-text-on-tone, #ffffff)",
22582
+ \u540D\u524D\u306E\u592A\u3055: 700
22583
+ }) : /* @__PURE__ */ jsx(
22117
22584
  "text",
22118
22585
  {
22119
22586
  x: n.w / 2,
@@ -22141,7 +22608,13 @@ function TreeNode({
22141
22608
  }
22142
22609
  ),
22143
22610
  /* @__PURE__ */ jsx("rect", { x: 0, y: 0, width: 4, height: n.h, rx: 2, fill: accent }),
22144
- /* @__PURE__ */ jsx(
22611
+ \u88DC\u8DB3\u3042\u308A ? \u7BB1\u306E\u6587\u5B57({
22612
+ \u884C,
22613
+ x: n.w / 2 + 2,
22614
+ \u7BB1\u306E\u9AD8\u3055: n.h,
22615
+ fill: "var(--cdl-chip-text, #1a1f2a)",
22616
+ \u540D\u524D\u306E\u592A\u3055: 600
22617
+ }) : /* @__PURE__ */ jsx(
22145
22618
  "text",
22146
22619
  {
22147
22620
  x: n.w / 2 + 2,
@@ -22222,6 +22695,7 @@ function computeTreeLayout(treeNodes, canvasW, canvasH) {
22222
22695
  nodes.push({
22223
22696
  id: n.id,
22224
22697
  title: n.title,
22698
+ ...n.subtitle !== void 0 ? { subtitle: n.subtitle } : {},
22225
22699
  x,
22226
22700
  y,
22227
22701
  w: nodeW,
@@ -22503,122 +22977,6 @@ function UserJourneyNode({
22503
22977
  ))
22504
22978
  ] });
22505
22979
  }
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
22980
  var BASEMENT_FILL = "#dde8f0";
22623
22981
  var commonFrame = (active) => ({
22624
22982
  fill: BASEMENT_FILL,
@@ -22633,8 +22991,8 @@ var EYEBROW_TRACKING = 2;
22633
22991
  var SUB_SIZE = 11;
22634
22992
  var SUB_GAP = 4;
22635
22993
  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;
22994
+ const \u4E0A = node.eyebrow ? size + EYEBROW_GAP2 + EYEBROW_SIZE2 * ASCENT : size * ASCENT;
22995
+ const \u4E0B = node.subtitle ? size + SUB_GAP + SUB_SIZE * DESCENT : size * DESCENT;
22638
22996
  const \u5E45 = Math.max(
22639
22997
  textWidth(node.title ?? "", size),
22640
22998
  node.eyebrow ? textWidth(node.eyebrow, EYEBROW_SIZE2, EYEBROW_TRACKING) : 0,
@@ -24824,6 +25182,15 @@ function ShapeSmartContractNode({ node, active }) {
24824
25182
  bottomLabel2(node, r.cx, r.label)
24825
25183
  ] });
24826
25184
  }
25185
+ var \u5B57\u306E\u5E45 = (text, size) => Math.max(displayWidth(text) * size * MONO_ADVANCE_RATIO, textWidth(text, size));
25186
+ var BLOCK_DEFAULT_FIELDS = [
25187
+ { label: "hash", value: "0xaf31c9d2..." },
25188
+ { label: "prev", value: "0x7b3f92c1..." },
25189
+ { label: "merkle", value: "0xc1892f4a..." },
25190
+ { label: "nonce", value: "82,914" },
25191
+ { label: "tx", value: "142 tx" }
25192
+ ];
25193
+ var BLOCK_DEFAULT_TITLE = "Block #421,873";
24827
25194
  function ShapeBlockchainBlockNode({ node, active }) {
24828
25195
  const frame = commonFrame4(active);
24829
25196
  const r = shapeRegion(node);
@@ -24833,21 +25200,22 @@ function ShapeBlockchainBlockNode({ node, active }) {
24833
25200
  const cy = r.cy;
24834
25201
  const x = cx - bw / 2;
24835
25202
  const y = cy - bh / 2;
25203
+ const \u6E21\u3055\u308C\u305F = (v) => (v ?? "").trim();
25204
+ const \u898B\u51FA\u3057 = \u6E21\u3055\u308C\u305F(node.title) || BLOCK_DEFAULT_TITLE;
25205
+ const fields = BLOCK_DEFAULT_FIELDS.map((f) => ({
25206
+ label: f.label,
25207
+ value: f.label === "hash" ? \u6E21\u3055\u308C\u305F(node.subtitle) || f.value : f.value
25208
+ }));
25209
+ const \u898B\u51FA\u3057\u306E\u5E45 = bw - 14 - 30;
24836
25210
  const art = /* @__PURE__ */ jsxs("g", { children: [
24837
25211
  /* @__PURE__ */ jsx("rect", { x: x + 6, y: y + 6, width: bw, height: bh, rx: 8, fill: frame.stroke, opacity: 0.2, stroke: "none" }),
24838
25212
  /* @__PURE__ */ jsx("rect", { "data-cdl-role": "node-body", x, y, width: bw, height: bh, rx: 8, ...frame }),
24839
25213
  /* @__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" }),
25214
+ /* @__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
25215
  /* @__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: [
25216
+ fields.map((f, i) => /* @__PURE__ */ jsxs("g", { children: [
24849
25217
  /* @__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 }),
25218
+ /* @__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
25219
  /* @__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
25220
  ] }, i)),
24853
25221
  /* @__PURE__ */ jsxs("g", { transform: `translate(${cx - 32}, ${y + bh - 26})`, children: [
@@ -26543,6 +26911,29 @@ function CdlNodeView({
26543
26911
  }
26544
26912
  );
26545
26913
  }
26914
+
26915
+ // src/layout/lifeline.ts
26916
+ function lifelineStartYs(nodes) {
26917
+ const topmost = /* @__PURE__ */ new Map();
26918
+ for (const n of nodes) {
26919
+ const cur = topmost.get(n.lane);
26920
+ if (cur === void 0 || n.cy < cur.cy) topmost.set(n.lane, n);
26921
+ }
26922
+ const starts = /* @__PURE__ */ new Map();
26923
+ for (const [laneId, n] of topmost) starts.set(laneId, n.cy + n.h / 2);
26924
+ return starts;
26925
+ }
26926
+ function uniformLifelineEndY(lanes, nodes, starts = lifelineStartYs(nodes)) {
26927
+ const lifelineLanes = lanes.filter((l) => l.lifeline);
26928
+ let deepestStart = Number.NEGATIVE_INFINITY;
26929
+ for (const lane of lifelineLanes) {
26930
+ const start = starts.get(lane.id);
26931
+ if (start !== void 0) deepestStart = Math.max(deepestStart, start);
26932
+ }
26933
+ const footerTops = lifelineFooterNodes(lanes, nodes).map((f) => footerShapeDrawTop(f)).filter((top) => top > deepestStart);
26934
+ if (footerTops.length > 0) return Math.min(...footerTops);
26935
+ return lifelineLanes[0] ? lifelineLanes[0].y + lifelineLanes[0].height : 0;
26936
+ }
26546
26937
  function CdlStage({
26547
26938
  laid,
26548
26939
  currentPhase,
@@ -26553,15 +26944,13 @@ function CdlStage({
26553
26944
  svgRef
26554
26945
  }) {
26555
26946
  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);
26947
+ const { lifelineStarts, uniformFooterTop } = useMemo(() => {
26948
+ const starts = lifelineStartYs(laid.nodes);
26559
26949
  return {
26560
- footerTops: footers.map((f) => f.cy - f.h / 2),
26561
- footerDropById: footerShapeDropsOf(footers)
26950
+ lifelineStarts: starts,
26951
+ uniformFooterTop: uniformLifelineEndY(laid.lanes, laid.nodes, starts)
26562
26952
  };
26563
26953
  }, [laid]);
26564
- const uniformFooterTop = footerTops.length > 0 ? Math.min(...footerTops) : lifelineLanes[0] ? lifelineLanes[0].y + lifelineLanes[0].height : 0;
26565
26954
  const diagramScale = laid.diagramScale ?? 1;
26566
26955
  return /* @__PURE__ */ jsxs("div", { className: compact ? "px-3 py-3" : "px-6 py-6", style: compact ? void 0 : { minHeight: 460 }, children: [
26567
26956
  /* @__PURE__ */ jsxs(
@@ -26648,11 +27037,8 @@ function CdlStage({
26648
27037
  }
26649
27038
  ),
26650
27039
  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;
27040
+ const y1 = lifelineStarts.get(lane.id);
27041
+ if (y1 === void 0) return null;
26656
27042
  const y2 = uniformFooterTop;
26657
27043
  if (y2 <= y1) return null;
26658
27044
  return /* @__PURE__ */ jsx(
@@ -26699,8 +27085,7 @@ function CdlStage({
26699
27085
  currentPhaseId: currentPhase?.id
26700
27086
  }
26701
27087
  );
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);
27088
+ return /* @__PURE__ */ jsx("g", { children: view }, node.id);
26704
27089
  }),
26705
27090
  laid.edges.filter((edge) => Boolean(edge.dThrough)).map((edge) => /* @__PURE__ */ jsx(CdlEdgeGlowView, { edge, active: activeSet.has(edge.id) }, `glow-${edge.id}`)),
26706
27091
  laid.edges.map((edge) => /* @__PURE__ */ jsx(
@@ -26923,14 +27308,7 @@ function CdlDiagramView({ diagram: diagram2, laid: laidProp, hideHeader = false,
26923
27308
  );
26924
27309
  const stateValues = useMemo(() => {
26925
27310
  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;
27311
+ return mergeStateValues(baseStateValues, interactive.stateOverrides);
26934
27312
  }, [isInteractive, baseStateValues, interactive.stateOverrides]);
26935
27313
  return /* @__PURE__ */ jsxs(
26936
27314
  "div",
@@ -27172,6 +27550,7 @@ function bboxDiffWorld(predicted, actual) {
27172
27550
  }
27173
27551
 
27174
27552
  // src/presets.ts
27553
+ var \u53C2\u7167\u305D\u306E\u3082\u306E = (v) => /^\{[A-Za-z_][\s\S]*\}$/.test(v);
27175
27554
  var GRID_UNIT = 16;
27176
27555
  function gridAlignedLaneW(canvasW) {
27177
27556
  const padPerSide = Math.ceil(LANE_PAD_MIN / GRID_UNIT) * GRID_UNIT;
@@ -27239,6 +27618,7 @@ function flow(preset) {
27239
27618
  b.lane("flow", { width: w, ...preset.laneLabel ? { label: preset.laneLabel } : {} });
27240
27619
  const tone = preset.defaultTone ?? "accent";
27241
27620
  const style = preset.defaultStyle ?? "dotted-flow";
27621
+ const autoChain = preset.autoChain ?? true;
27242
27622
  let prevId = null;
27243
27623
  let stackIdx = 0;
27244
27624
  const phaseActivate = [];
@@ -27253,7 +27633,7 @@ function flow(preset) {
27253
27633
  ...node.subtitle ? { subtitle: node.subtitle } : {}
27254
27634
  });
27255
27635
  phaseActivate.push(node.id);
27256
- if (prevId !== null) {
27636
+ if (autoChain && prevId !== null) {
27257
27637
  const edgeId = `e-${prevId}-${node.id}`;
27258
27638
  b.edge(prevId, node.id, {
27259
27639
  id: edgeId,
@@ -27266,6 +27646,17 @@ function flow(preset) {
27266
27646
  prevId = node.id;
27267
27647
  return api;
27268
27648
  },
27649
+ edge(from, to, opts) {
27650
+ const edgeId = opts?.id ?? `e-${from}-${to}`;
27651
+ b.edge(from, to, {
27652
+ id: edgeId,
27653
+ label: opts?.label ?? "\u2192",
27654
+ tone: opts?.tone ?? tone,
27655
+ style: opts?.style ?? style
27656
+ });
27657
+ phaseActivate.push(edgeId);
27658
+ return api;
27659
+ },
27269
27660
  build() {
27270
27661
  b.phase(
27271
27662
  "flow",
@@ -27329,7 +27720,7 @@ function sequence(preset) {
27329
27720
  const laneId = actorIds.get(label) ?? slugify(label);
27330
27721
  const footerId = `${laneId}-footer`;
27331
27722
  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 });
27723
+ b.node(footerId, { lane: laneId, stack: footerStack, kind: "card", title: label, w: actorW, h: 72, role: "lifeline-footer" });
27333
27724
  phaseActivate.push(footerId);
27334
27725
  });
27335
27726
  b.phase(
@@ -27652,8 +28043,7 @@ function tree(preset) {
27652
28043
  id: n.id,
27653
28044
  title: n.title,
27654
28045
  parent: n.parent,
27655
- subtitle: n.subtitle,
27656
- eyebrow: n.eyebrow
28046
+ subtitle: n.subtitle
27657
28047
  }))
27658
28048
  });
27659
28049
  b.phase(
@@ -27887,9 +28277,11 @@ function gantt(preset) {
27887
28277
  build() {
27888
28278
  const labelSeq = [];
27889
28279
  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);
28280
+ if (!\u53C2\u7167\u305D\u306E\u3082\u306E(t.start) && !labelSeq.includes(t.start)) labelSeq.push(t.start);
28281
+ if (!\u53C2\u7167\u305D\u306E\u3082\u306E(t.end) && !labelSeq.includes(t.end)) labelSeq.push(t.end);
27892
28282
  }
28283
+ const \u4F4D\u7F6E = (v) => \u53C2\u7167\u305D\u306E\u3082\u306E(v) ? v : labelSeq.indexOf(v);
28284
+ const \u540D\u672D = (v) => \u53C2\u7167\u305D\u306E\u3082\u306E(v) ? "" : v;
27893
28285
  b.lane("gantt", { width: canvasW });
27894
28286
  const nodeId = `${preset.id}-gantt`;
27895
28287
  b.node(nodeId, {
@@ -27900,13 +28292,15 @@ function gantt(preset) {
27900
28292
  eyebrow: "gantt",
27901
28293
  w: canvasW,
27902
28294
  h: canvasH,
28295
+ // 宣言していない図には欄自体を載せない = 自動で決める経路をそのまま通す
28296
+ ...preset.axisMax !== void 0 ? { ganttAxisMax: preset.axisMax } : {},
27903
28297
  ganttData: tasks.map((t) => ({
27904
28298
  id: t.id,
27905
28299
  title: t.title,
27906
- startIdx: labelSeq.indexOf(t.start),
27907
- endIdx: labelSeq.indexOf(t.end),
27908
- startLabel: t.start,
27909
- endLabel: t.end,
28300
+ startIdx: \u4F4D\u7F6E(t.start),
28301
+ endIdx: \u4F4D\u7F6E(t.end),
28302
+ startLabel: \u540D\u672D(t.start),
28303
+ endLabel: \u540D\u672D(t.end),
27910
28304
  owner: t.owner,
27911
28305
  dependsOn: t.dependsOn,
27912
28306
  tone