@cardenelabs/cdl 0.18.1 → 0.20.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,68 @@ CDL (Chainome Diagram Language) の主要変更履歴。
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.20.0] - 2026-08-29
9
+
10
+ ### Changed
11
+
12
+ - **箱の高さを書いた段の数から決めるようにした** (#589)
13
+
14
+ 高さが中身に依らず種別ごとの固定値で、小見出し + 名前 + 説明の 3 段が入る前提だった。
15
+ 名前 1 語だけの箱も 3 段ぶんの高さになり、実測で `function` は 151 に対し字が 29 しか
16
+ 無かった。
17
+
18
+ 空きは上下の両方に出ていた。 小見出しを書かないと、そのために空けた帯が上に残る。
19
+ 説明を書かないと、説明の段が下に残る。
20
+
21
+ 2 つを組み合わせて直した。 小見出しが無い時は字の塊を上へ繰り上げ、高さは最後の段の
22
+ 下端から出す。 繰り上げ量は `layout/spec.ts` が持ち、描き手と layout が同じ値を引く。
23
+
24
+ **3 段を書いた箱の高さは変わらない**。 書かなかった段のぶんだけ引く形なので、既存の図で
25
+ 3 段そろっているものは 1 も動かない。
26
+
27
+ 実測 (名前だけの箱)。 `actor` 165 → 73、`function` 151 → 67、`event` 156 → 72、
28
+ `card` 150 → 68、`storage` 115 → 79、`service` 等 21 種別 116 → 54。
29
+
30
+ 4 つの書き方 (名前だけ / 小見出し + 名前 / 名前 + 説明 / 3 段) × 9 種別の 36 通りで、
31
+ 上と下の余白の差は最大 5 に収まる。
32
+
33
+ 行を持つ箱と、値を持つ箱と、字を中央へ寄せる 2 種別 (`cloud` / `decision`) は対象外。
34
+ 行は上端から数えて置かれ、値は下端から置かれるので、繰り上げると重なる。
35
+
36
+ ### Fixed
37
+
38
+ - **形の違う線が混ざる扇でも、同じ形どうしは説明を離すようにした** (#589)
39
+
40
+ 扇状に広がる線の説明を横へ逃がす処理が、線の形 (迂回するかどうか) が混ざる群では
41
+ **丸ごと止まって** いた。 その結果、同じ形どうしの重なりまで残っていた。
42
+
43
+ 形ごとに分けてから逃がす。 実測 = 4 段の網の図で、迂回する 2 本の説明が 25 しか離れず
44
+ `clearance` が error を出していた (要る間隔は 36)。
45
+
46
+ 逃がす時の間隔も、検査が要求する値 (`CLEARANCE_LABEL_LABEL` = 36) そのものにした。
47
+ 20 を独自に持っていた間、逃がした結果が要求に届かず 32 で止まっていた = 掃く側と見る側で
48
+ 別の値を持つと、掃いても落ちる。
49
+
50
+ ## [0.19.0] - 2026-08-29
51
+
52
+ ### Changed
53
+
54
+ - **字だけの箱で上下の余白を揃えた** (#586)
55
+
56
+ 字しか持たない箱が、字の下に余白を大きく残したまま並んでいた (user 実機指摘)。
57
+ 実測で `service` は上 15.7 に対し下が 81、 `merkle-tree` は下が 121 空いていた。
58
+ 字は上から描かれるので、箱を高くしたぶんがそのまま下の空きになっていた。
59
+
60
+ 上の余白と同じだけを下にも取る形へ揃える (`新 h = 上の余白 × 2 + 字の高さ`)。
61
+ 23 種別が 19 から 104 縮む。 `person` / `service` / `api` 等 18 種別は 116 に揃う。
62
+
63
+ **絵を持つ種別は動かさない**。 `shape-` の 49 種別は箱いっぱいに絵を描くので、
64
+ 詰めると絵が入らない (実測で `cloud` は絵が 200 あり、箱 173 を既に超えている)。
65
+ 差が 5 未満の 2 種別 (`card` -1 / `decision` -3) も、見た目が変わらないので据え置く。
66
+
67
+ 行を持たない `storage` だけは token ではなく `autoStorageHeight` の中の値で決まるため、
68
+ そちらを 150 から 115 にした。 行を持つ形 (token 240 が下限) は変えていない。
69
+
8
70
  ## [0.18.1] - 2026-08-29
9
71
 
10
72
  ### Fixed
@@ -964,7 +1026,9 @@ Initial OSS release.
964
1026
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
965
1027
  行き止まりになる。
966
1028
 
967
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.18.1...HEAD
1029
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.20.0...HEAD
1030
+ [0.20.0]: https://github.com/cardene777/cdl/compare/v0.19.0...v0.20.0
1031
+ [0.19.0]: https://github.com/cardene777/cdl/compare/v0.18.1...v0.19.0
968
1032
  [0.18.1]: https://github.com/cardene777/cdl/compare/v0.18.0...v0.18.1
969
1033
  [0.18.0]: https://github.com/cardene777/cdl/compare/v0.17.1...v0.18.0
970
1034
  [0.17.1]: https://github.com/cardene777/cdl/compare/v0.17.0...v0.17.1
package/dist/index.cjs CHANGED
@@ -11978,6 +11978,54 @@ function buildDiagramAltText(topic, phase) {
11978
11978
  else if (body) parts.push(body);
11979
11979
  return parts.join(" ");
11980
11980
  }
11981
+ var \u6BB5\u306E\u4F4D\u7F6E = {
11982
+ actor: { \u76EE\u5370: { y: 38, size: 18 }, \u540D\u524D: { y: 86, size: 32 }, \u8AAC\u660E: { y: 140, size: 20 } },
11983
+ function: { \u76EE\u5370: { y: 38, size: 18 }, \u540D\u524D: { y: 86, size: 24 }, \u8AAC\u660E: { y: 126, size: 20 } },
11984
+ event: { \u76EE\u5370: { y: 38, size: 18 }, \u540D\u524D: { y: 88, size: 26 }, \u8AAC\u660E: { y: 128, size: 21 } },
11985
+ card: { \u76EE\u5370: { y: 38, size: 18 }, \u540D\u524D: { y: 86, size: 24 }, \u8AAC\u660E: { y: 124, size: 21 } },
11986
+ storage: {
11987
+ \u76EE\u5370: { y: 38, size: 18 },
11988
+ \u540D\u524D: { y: STORAGE_TITLE_BASELINE, size: STORAGE_TITLE_FONT },
11989
+ \u8AAC\u660E: { y: 118, size: 20 }
11990
+ }
11991
+ };
11992
+ var \u6C4E\u7528\u306E\u6BB5 = {
11993
+ \u76EE\u5370: { y: 32, size: 17 },
11994
+ \u540D\u524D: { y: GENERIC_TITLE_TOP, size: GENERIC_TITLE_FONT },
11995
+ \u8AAC\u660E: { y: 96, size: 17 }
11996
+ };
11997
+ function \u6BB5\u3092\u7A4D\u3080\u7BB1\u304B(kind, hasRows) {
11998
+ if (hasRows) return false;
11999
+ if (kind === void 0) return false;
12000
+ if (genericTextCentered(kind, false)) return false;
12001
+ return kind in \u6BB5\u306E\u4F4D\u7F6E || rendersRows(kind);
12002
+ }
12003
+ function \u6BB5\u3092\u5F15\u304F(kind) {
12004
+ const \u56FA\u6709 = \u6BB5\u306E\u4F4D\u7F6E[kind];
12005
+ if (\u56FA\u6709) return \u56FA\u6709;
12006
+ if (rendersRows(kind)) return \u6C4E\u7528\u306E\u6BB5;
12007
+ return null;
12008
+ }
12009
+ function \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052(kind, hasRows = false) {
12010
+ if (!\u6BB5\u3092\u7A4D\u3080\u7BB1\u304B(kind, hasRows)) return 0;
12011
+ const \u6BB5 = \u6BB5\u3092\u5F15\u304F(kind);
12012
+ if (!\u6BB5) return 0;
12013
+ const \u4E0A\u3052\u308B = \u6BB5.\u540D\u524D.y - \u6BB5.\u76EE\u5370.y + (\u6BB5.\u76EE\u5370.size - \u6BB5.\u540D\u524D.size) * GLYPH_CAP_RATIO;
12014
+ return Math.max(0, Math.round(\u4E0A\u3052\u308B));
12015
+ }
12016
+ function \u8AAC\u660E\u306A\u3057\u3067\u7E2E\u3080\u91CF(kind, hasRows = false) {
12017
+ if (!\u6BB5\u3092\u7A4D\u3080\u7BB1\u304B(kind, hasRows)) return 0;
12018
+ const \u6BB5 = \u6BB5\u3092\u5F15\u304F(kind);
12019
+ if (!\u6BB5) return 0;
12020
+ return Math.max(0, \u6BB5.\u8AAC\u660E.y - \u6BB5.\u540D\u524D.y);
12021
+ }
12022
+ function \u4E2D\u8EAB\u304B\u3089\u51FA\u3059\u9AD8\u3055(kind, \u6E80\u8F09h, \u4E2D\u8EAB) {
12023
+ if (!\u6BB5\u3092\u7A4D\u3080\u7BB1\u304B(kind, \u4E2D\u8EAB.hasRows)) return \u6E80\u8F09h;
12024
+ if (\u4E2D\u8EAB.hasValue) return \u6E80\u8F09h;
12025
+ const \u5F15\u304F = (\u4E2D\u8EAB.hasEyebrow ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052(kind)) + (\u4E2D\u8EAB.hasSubtitle ? 0 : \u8AAC\u660E\u306A\u3057\u3067\u7E2E\u3080\u91CF(kind));
12026
+ return Math.max(MIN_BOX_H, \u6E80\u8F09h - \u5F15\u304F);
12027
+ }
12028
+ var MIN_BOX_H = 44;
11981
12029
 
11982
12030
  // src/layout/footer-shape.ts
11983
12031
  var SHAPE_DRAW_UP_EXTENT = {
@@ -13300,35 +13348,35 @@ var TOKENS = {
13300
13348
  contain_pad: 28,
13301
13349
  // node sizes (kind ごと、 unified row h は engine が max() で算出)
13302
13350
  node: {
13303
- actor: { w: 340, h: 200 },
13304
- function: { w: 380, h: 170 },
13351
+ actor: { w: 340, h: 165 },
13352
+ function: { w: 380, h: 151 },
13305
13353
  storage: { w: 400, h: 240 },
13306
- event: { w: 360, h: 200 },
13354
+ event: { w: 360, h: 156 },
13307
13355
  card: { w: 320, h: 150 },
13308
13356
  // 人系
13309
- person: { w: 280, h: 180 },
13310
- "user-group": { w: 320, h: 180 },
13311
- admin: { w: 280, h: 180 },
13312
- developer: { w: 280, h: 180 },
13313
- "external-user": { w: 300, h: 180 },
13357
+ person: { w: 280, h: 116 },
13358
+ "user-group": { w: 320, h: 116 },
13359
+ admin: { w: 280, h: 116 },
13360
+ developer: { w: 280, h: 116 },
13361
+ "external-user": { w: 300, h: 116 },
13314
13362
  // インフラ
13315
- database: { w: 320, h: 200 },
13316
- cache: { w: 280, h: 160 },
13317
- queue: { w: 340, h: 140 },
13318
- "message-bus": { w: 380, h: 140 },
13363
+ database: { w: 320, h: 172 },
13364
+ cache: { w: 280, h: 116 },
13365
+ queue: { w: 340, h: 116 },
13366
+ "message-bus": { w: 380, h: 116 },
13319
13367
  cloud: { w: 320, h: 180 },
13320
- cdn: { w: 320, h: 160 },
13368
+ cdn: { w: 320, h: 116 },
13321
13369
  // アプリ系
13322
- service: { w: 320, h: 180 },
13323
- api: { w: 320, h: 160 },
13324
- frontend: { w: 320, h: 180 },
13325
- backend: { w: 320, h: 180 },
13326
- webhook: { w: 320, h: 160 },
13327
- microservice: { w: 320, h: 180 },
13370
+ service: { w: 320, h: 116 },
13371
+ api: { w: 320, h: 116 },
13372
+ frontend: { w: 320, h: 116 },
13373
+ backend: { w: 320, h: 116 },
13374
+ webhook: { w: 320, h: 116 },
13375
+ microservice: { w: 320, h: 116 },
13328
13376
  // データ / 判定
13329
- signer: { w: 300, h: 180 },
13330
- oracle: { w: 320, h: 180 },
13331
- "merkle-tree": { w: 340, h: 220 },
13377
+ signer: { w: 300, h: 116 },
13378
+ oracle: { w: 320, h: 116 },
13379
+ "merkle-tree": { w: 340, h: 116 },
13332
13380
  decision: { w: 300, h: 180 },
13333
13381
  // Chart 系 (CAR-994 Phase A) ... 1 node に datum 配列を持ち、 kind 内で SVG geometry 描画。
13334
13382
  // 実際の w/h は preset chart() が w/h override で指定 (default fallback は preset 未指定時のみ)。
@@ -13605,7 +13653,7 @@ function layoutEdges(diag, nodes, lanes = []) {
13605
13653
  for (const p of list) parallelGroupedIds.add(p.e.id);
13606
13654
  }
13607
13655
  const distributedInParallel = /* @__PURE__ */ new Set();
13608
- const FAN_LABEL_GAP = 20;
13656
+ const FAN_LABEL_GAP = CLEARANCE_LABEL_LABEL;
13609
13657
  const computeEffectiveSides = (p) => {
13610
13658
  if (p.e.routing === "back-detour") {
13611
13659
  return { effFromSide: "top", effToSide: "top" };
@@ -13995,7 +14043,17 @@ function layoutEdges(diag, nodes, lanes = []) {
13995
14043
  const applyFanDispersion = (list, tracked) => {
13996
14044
  if (list.length < 2) return;
13997
14045
  const obstaclePatterns = new Set(list.map((r) => detectsBlockingObstacle(r.p)));
13998
- if (obstaclePatterns.size > 1) return;
14046
+ if (obstaclePatterns.size > 1) {
14047
+ const \u5F62\u3054\u3068 = /* @__PURE__ */ new Map();
14048
+ for (const r of list) {
14049
+ const \u5F62 = detectsBlockingObstacle(r.p);
14050
+ \u5F62\u3054\u3068.set(\u5F62, [...\u5F62\u3054\u3068.get(\u5F62) ?? [], r]);
14051
+ }
14052
+ for (const \u540C\u3058\u5F62 of \u5F62\u3054\u3068.values()) {
14053
+ if (\u540C\u3058\u5F62.length < list.length) applyFanDispersion(\u540C\u3058\u5F62, tracked);
14054
+ }
14055
+ return;
14056
+ }
13999
14057
  if (list.some((r) => r.e.overlay)) return;
14000
14058
  const items = list.map((r) => ({
14001
14059
  r,
@@ -15088,7 +15146,8 @@ function autoStorageHeight(n, defaultH) {
15088
15146
  if (n.h != null) return n.h;
15089
15147
  const \u5370\u3042\u308A = n.rowMarks !== void 0;
15090
15148
  const \u547C\u3073\u540D\u306E\u5206 = \u5370\u3042\u308A && n.subtitle ? SUBTITLE_ROW_SHIFT : 0;
15091
- if (!n.rows || n.rows.length === 0) return 150 + \u547C\u3073\u540D\u306E\u5206;
15149
+ const \u7E70\u308A\u4E0A\u3052 = n.eyebrow ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052("storage");
15150
+ if (!n.rows || n.rows.length === 0) return 115 + \u547C\u3073\u540D\u306E\u5206 - \u7E70\u308A\u4E0A\u3052;
15092
15151
  const \u5FC5\u8981 = requiredRowsHeight("storage", n.rows.length) ?? defaultH;
15093
15152
  if (\u5370\u3042\u308A) return \u5FC5\u8981 + \u547C\u3073\u540D\u306E\u5206;
15094
15153
  return Math.max(defaultH, \u5FC5\u8981);
@@ -15099,6 +15158,16 @@ function autoRowsWidth(n, defaultW) {
15099
15158
  const required = requiredRowsWidth(n.rows, n.kind);
15100
15159
  return Math.max(defaultW, required);
15101
15160
  }
15161
+ function \u7BB1\u306E\u9AD8\u3055(n, \u65E2\u5B9Ah) {
15162
+ if (n.h != null) return n.h;
15163
+ if (n.kind === "storage") return autoStorageHeight(n, \u65E2\u5B9Ah);
15164
+ return \u4E2D\u8EAB\u304B\u3089\u51FA\u3059\u9AD8\u3055(n.kind, \u65E2\u5B9Ah, {
15165
+ hasEyebrow: Boolean(n.eyebrow),
15166
+ hasSubtitle: Boolean(n.subtitle),
15167
+ hasValue: Boolean(n.value),
15168
+ hasRows: (n.rows?.length ?? 0) > 0
15169
+ });
15170
+ }
15102
15171
  function requiredStackGapForEdgeLabels(diag, allStacks) {
15103
15172
  const byId = new Map(diag.nodes.map((n) => [n.id, n]));
15104
15173
  const rankOf = new Map(allStacks.map((stack, i) => [stack, i]));
@@ -15128,7 +15197,7 @@ function layoutNodes(diag, lanes) {
15128
15197
  const rowH = /* @__PURE__ */ new Map();
15129
15198
  for (const stack of allStacks) {
15130
15199
  const nodesAtStack = diag.nodes.filter((n) => n.stack === stack);
15131
- const h = Math.max(...nodesAtStack.map((n) => autoStorageHeight(n, NODE_SIZE[n.kind].h)));
15200
+ const h = Math.max(...nodesAtStack.map((n) => \u7BB1\u306E\u9AD8\u3055(n, NODE_SIZE[n.kind].h)));
15132
15201
  rowH.set(stack, h);
15133
15202
  }
15134
15203
  const rowCy = /* @__PURE__ */ new Map();
@@ -15181,8 +15250,8 @@ function layoutNodes(diag, lanes) {
15181
15250
  const cx = lane.x + lane.width / 2;
15182
15251
  const \u6BB5\u306E\u82AF = rowCy.get(n.stack);
15183
15252
  const \u6BB5\u306E\u9AD8\u3055 = rowH.get(n.stack);
15184
- const \u81EA\u524D\u306E\u9AD8\u3055 = n.rowMarks !== void 0;
15185
- const h = n.h ?? (\u81EA\u524D\u306E\u9AD8\u3055 ? autoStorageHeight(n, size.h) : \u6BB5\u306E\u9AD8\u3055);
15253
+ const \u81EA\u524D\u306E\u9AD8\u3055 = n.rowMarks !== void 0 || \u6BB5\u3092\u7A4D\u3080\u7BB1\u304B(n.kind, (n.rows?.length ?? 0) > 0);
15254
+ const h = n.h ?? (\u81EA\u524D\u306E\u9AD8\u3055 ? \u7BB1\u306E\u9AD8\u3055(n, size.h) : \u6BB5\u306E\u9AD8\u3055);
15186
15255
  const cy = \u6BB5\u306E\u82AF;
15187
15256
  const w = autoRowsWidth(n, size.w);
15188
15257
  out.push({
@@ -16623,10 +16692,10 @@ function \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text) {
16623
16692
  if (typeof \u533A\u5207\u308A !== "function") return [...text];
16624
16693
  return [...new \u533A\u5207\u308A(void 0, { granularity: "grapheme" }).segment(text)].map((g) => g.segment);
16625
16694
  }
16626
- function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u3055) {
16695
+ function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u30552) {
16627
16696
  const \u5019\u88DC = \u884C.filter((r, i) => i === 0 || r.text.trim() !== "");
16628
16697
  if (\u5019\u88DC.length === 0) return [];
16629
- const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u3055 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
16698
+ const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u30552 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
16630
16699
  const \u9AD8\u3055 = (rs) => rs.reduce((a, r) => a + r.fontSize * \u884C\u9001\u308A\u306E\u6BD4, 0);
16631
16700
  const \u6B8B\u3059 = [...\u5019\u88DC];
16632
16701
  while (\u6B8B\u3059.length > 1 && \u9AD8\u3055(\u6B8B\u3059) > \u4F7F\u3048\u308B\u9AD8\u3055) \u6B8B\u3059.pop();
@@ -16845,7 +16914,7 @@ function \u30D9\u30B8\u30A8\u306E\u7D2F\u7A4D\u5272\u5408(\u70B9, \u5236\u5FA1\u
16845
16914
  function \u7BB1\u306E\u6587\u5B57({
16846
16915
  \u884C,
16847
16916
  x,
16848
- \u7BB1\u306E\u9AD8\u3055,
16917
+ \u7BB1\u306E\u9AD8\u3055: \u7BB1\u306E\u9AD8\u30552,
16849
16918
  fill,
16850
16919
  \u540D\u524D\u306E\u592A\u3055
16851
16920
  }) {
@@ -16854,7 +16923,7 @@ function \u7BB1\u306E\u6587\u5B57({
16854
16923
  {
16855
16924
  "data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "tree-node-subtitle" : void 0,
16856
16925
  x,
16857
- y: \u7BB1\u306E\u9AD8\u3055 / 2 + r.dy,
16926
+ y: \u7BB1\u306E\u9AD8\u30552 / 2 + r.dy,
16858
16927
  fontSize: r.fontSize,
16859
16928
  fontWeight: r.\u5F79\u5272 === "title" ? \u540D\u524D\u306E\u592A\u3055 : 500,
16860
16929
  textAnchor: "middle",
@@ -21533,7 +21602,8 @@ function ActorNode({ node, active, value }) {
21533
21602
  const accent = nodeAccent(node, "var(--cdl-tone-accent, #2d6a8f)");
21534
21603
  const x = node.cx - node.w / 2;
21535
21604
  const y = node.cy - node.h / 2;
21536
- const \u540D\u524D = titlePlacement(node, { x: 26, y: 86, size: 32 }, { hasEyebrow: Boolean(node.eyebrow) });
21605
+ const \u7E70\u308A\u4E0A\u3052 = node.eyebrow ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052("actor");
21606
+ const \u540D\u524D = titlePlacement(node, { x: 26, y: 86 - \u7E70\u308A\u4E0A\u3052, size: 32 }, { hasEyebrow: Boolean(node.eyebrow) });
21537
21607
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${x} ${y})`, children: [
21538
21608
  /* @__PURE__ */ jsxRuntime.jsx(
21539
21609
  "rect",
@@ -21568,13 +21638,13 @@ function ActorNode({ node, active, value }) {
21568
21638
  {
21569
21639
  "data-cdl-role": "node-row-divider",
21570
21640
  x1: 26,
21571
- y1: 110,
21641
+ y1: 110 - \u7E70\u308A\u4E0A\u3052,
21572
21642
  x2: node.w - 26,
21573
- y2: 110,
21643
+ y2: 110 - \u7E70\u308A\u4E0A\u3052,
21574
21644
  stroke: "var(--cdl-row-divider, #7e848e)"
21575
21645
  }
21576
21646
  ),
21577
- node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("text", { x: 26, y: 140, fontSize: 20, fill: "var(--cdl-text-dim, #5a6270)", children: node.subtitle }),
21647
+ node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("text", { x: 26, y: 140 - \u7E70\u308A\u4E0A\u3052, fontSize: 20, fill: "var(--cdl-text-dim, #5a6270)", children: node.subtitle }),
21578
21648
  value && /* @__PURE__ */ jsxRuntime.jsx(
21579
21649
  "text",
21580
21650
  {
@@ -21599,7 +21669,8 @@ function CardNode({ node, active }) {
21599
21669
  }
21600
21670
  const compact = isCompactBox(node.h);
21601
21671
  const \u5C0F\u578B\u306B\u547C\u3073\u540D = compact && Boolean(node.subtitle);
21602
- const titleY = compact ? \u5C0F\u578B\u306B\u547C\u3073\u540D ? node.h / 2 - 2 : node.h / 2 + 8 : 86;
21672
+ const \u7E70\u308A\u4E0A\u3052 = node.eyebrow ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052("card");
21673
+ const titleY = compact ? \u5C0F\u578B\u306B\u547C\u3073\u540D ? node.h / 2 - 2 : node.h / 2 + 8 : 86 - \u7E70\u308A\u4E0A\u3052;
21603
21674
  const titleX = compact ? node.w / 2 : 26;
21604
21675
  const paddingX = compact ? 16 : 52;
21605
21676
  const availableW = node.w - paddingX;
@@ -21636,7 +21707,7 @@ function CardNode({ node, active }) {
21636
21707
  children: node.title
21637
21708
  }
21638
21709
  ),
21639
- !compact && node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("text", { x: 26, y: 124, fontSize: subtitleSize, fill: "var(--cdl-text-dim, #5a6270)", children: node.subtitle }),
21710
+ !compact && node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("text", { x: 26, y: 124 - \u7E70\u308A\u4E0A\u3052, fontSize: subtitleSize, fill: "var(--cdl-text-dim, #5a6270)", children: node.subtitle }),
21640
21711
  \u5C0F\u578B\u306B\u547C\u3073\u540D && /* @__PURE__ */ jsxRuntime.jsx(
21641
21712
  "text",
21642
21713
  {
@@ -21900,7 +21971,8 @@ function EventNode({
21900
21971
  const accent = nodeAccent(node, "var(--cdl-tone-success, #4ea36a)");
21901
21972
  const x = node.cx - node.w / 2;
21902
21973
  const y = node.cy - node.h / 2;
21903
- const \u540D\u524D = titlePlacement(node, { x: 26, y: 88, size: 26 }, { hasEyebrow: Boolean(node.eyebrow) });
21974
+ const \u7E70\u308A\u4E0A\u3052 = node.eyebrow ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052("event");
21975
+ const \u540D\u524D = titlePlacement(node, { x: 26, y: 88 - \u7E70\u308A\u4E0A\u3052, size: 26 }, { hasEyebrow: Boolean(node.eyebrow) });
21904
21976
  const scale = active ? 0.78 + 0.22 * progress : 0.92;
21905
21977
  const opacity = active ? 0.5 + 0.5 * progress : 0.65;
21906
21978
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -21942,7 +22014,7 @@ function EventNode({
21942
22014
  "text",
21943
22015
  {
21944
22016
  x: 26,
21945
- y: 128,
22017
+ y: 128 - \u7E70\u308A\u4E0A\u3052,
21946
22018
  fontSize: 21,
21947
22019
  fill: "var(--cdl-text-dim, #5a6270)",
21948
22020
  style: { fontFamily: "'JetBrains Mono', monospace" },
@@ -21958,7 +22030,8 @@ function FunctionNode({ node, active }) {
21958
22030
  const stroke = nodeAccent(node, active ? "var(--cdl-tone-accent, #2d6a8f)" : "var(--cdl-tone-teal, #2f8770)");
21959
22031
  const x = node.cx - node.w / 2;
21960
22032
  const y = node.cy - node.h / 2;
21961
- const \u540D\u524D = titlePlacement(node, { x: 26, y: 86, size: 24 }, { hasEyebrow: Boolean(node.eyebrow) });
22033
+ const \u7E70\u308A\u4E0A\u3052 = node.eyebrow ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052("function");
22034
+ const \u540D\u524D = titlePlacement(node, { x: 26, y: 86 - \u7E70\u308A\u4E0A\u3052, size: 24 }, { hasEyebrow: Boolean(node.eyebrow) });
21962
22035
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${x} ${y})`, children: [
21963
22036
  /* @__PURE__ */ jsxRuntime.jsx(
21964
22037
  "rect",
@@ -21990,7 +22063,7 @@ function FunctionNode({ node, active }) {
21990
22063
  children: node.title
21991
22064
  }
21992
22065
  ),
21993
- node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("text", { x: 26, y: 126, fontSize: 20, fill: "var(--cdl-text-dim, #5a6270)", children: node.subtitle })
22066
+ node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("text", { x: 26, y: 126 - \u7E70\u308A\u4E0A\u3052, fontSize: 20, fill: "var(--cdl-text-dim, #5a6270)", children: node.subtitle })
21994
22067
  ] });
21995
22068
  }
21996
22069
  var ROW_GLYPH_HALF = 7;
@@ -22025,7 +22098,8 @@ function StorageNode({
22025
22098
  const accent = nodeAccent(node, "var(--cdl-tone-accent, #2d6a8f)");
22026
22099
  const x = node.cx - node.w / 2;
22027
22100
  const y = node.cy - node.h / 2;
22028
- const \u540D\u524D = titlePlacement(node, { x: 26, y: STORAGE_TITLE_BASELINE, size: STORAGE_TITLE_FONT }, { hasEyebrow: Boolean(node.eyebrow) });
22101
+ const \u7E70\u308A\u4E0A\u3052 = node.eyebrow || rows.length > 0 ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052("storage");
22102
+ const \u540D\u524D = titlePlacement(node, { x: 26, y: STORAGE_TITLE_BASELINE - \u7E70\u308A\u4E0A\u3052, size: STORAGE_TITLE_FONT }, { hasEyebrow: Boolean(node.eyebrow) });
22029
22103
  const splits = rows.map((r) => splitRow(r));
22030
22104
  const leftMaxWidth = splits.reduce((m, s) => Math.max(m, displayWidth(s.left)), 0);
22031
22105
  const rightColX = ROW_PAD_X_PX + leftMaxWidth * STORAGE_CHAR_ADVANCE_PX + STORAGE_COL_GAP_PX;
@@ -22062,7 +22136,7 @@ function StorageNode({
22062
22136
  {
22063
22137
  "data-cdl-role": "node-subtitle",
22064
22138
  x: ROW_PAD_X_PX,
22065
- y: SUBTITLE_BASELINE,
22139
+ y: SUBTITLE_BASELINE - \u7E70\u308A\u4E0A\u3052,
22066
22140
  fontSize: SUBTITLE_FONT,
22067
22141
  fill: "var(--cdl-text-dim, #5a6270)",
22068
22142
  children: node.subtitle
@@ -22380,9 +22454,10 @@ function GenericNode({
22380
22454
  const textAnchor = centered ? "middle" : "start";
22381
22455
  const textX = centered ? w / 2 : 20;
22382
22456
  const cylinderShift = genericTextShift(node.kind);
22457
+ const \u7E70\u308A\u4E0A\u3052 = node.eyebrow || centered ? 0 : \u76EE\u5370\u306A\u3057\u306E\u7E70\u308A\u4E0A\u3052(node.kind, hasRows);
22383
22458
  const eyebrowY = centered ? h / 2 - 26 : 32 + cylinderShift;
22384
- const titleY = genericTitleBaselineY(node.kind, h, hasRows);
22385
- const subtitleY = centered ? h / 2 + 28 : 96 + cylinderShift;
22459
+ const titleY = genericTitleBaselineY(node.kind, h, hasRows) - \u7E70\u308A\u4E0A\u3052;
22460
+ const subtitleY = centered ? h / 2 + 28 : 96 + cylinderShift - \u7E70\u308A\u4E0A\u3052;
22386
22461
  const iconX = centered ? w / 2 + 40 : w - 48;
22387
22462
  const iconY = centered ? h / 2 - 44 : 18 + cylinderShift;
22388
22463
  const dominantBaseline = centered ? "middle" : void 0;