@cardenelabs/cdl 0.12.0 → 0.13.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.
@@ -293,6 +293,14 @@ type GanttTaskPayload = {
293
293
  type MindBranchPayload = {
294
294
  rootId: string;
295
295
  rootTitle: string;
296
+ /**
297
+ * 中心の箱の 2 行目に出す補足 (#530)。
298
+ *
299
+ * 枝 (`MindBranchNode`) は元から `subtitle` を持つのに中心だけ渡す口が無く、呼出側が
300
+ * 名前と補足を連結して `rootTitle` に入れていた。 1 行に全部入るため箱幅を超え、
301
+ * 末尾が切られる (実測 = 箱 120px に対し文字 163px)。
302
+ */
303
+ rootSubtitle?: string;
296
304
  branches: MindBranchNode[];
297
305
  };
298
306
  /** 1 branch node = id + title + parent + optional tone + subtitle */
@@ -293,6 +293,14 @@ type GanttTaskPayload = {
293
293
  type MindBranchPayload = {
294
294
  rootId: string;
295
295
  rootTitle: string;
296
+ /**
297
+ * 中心の箱の 2 行目に出す補足 (#530)。
298
+ *
299
+ * 枝 (`MindBranchNode`) は元から `subtitle` を持つのに中心だけ渡す口が無く、呼出側が
300
+ * 名前と補足を連結して `rootTitle` に入れていた。 1 行に全部入るため箱幅を超え、
301
+ * 末尾が切られる (実測 = 箱 120px に対し文字 163px)。
302
+ */
303
+ rootSubtitle?: string;
296
304
  branches: MindBranchNode[];
297
305
  };
298
306
  /** 1 branch node = id + title + parent + optional tone + subtitle */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardenelabs/cdl",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "CDL (Chainome Diagram Language). Mermaid-like declarative DSL that compiles to animated SVG diagrams. Built for blockchain / Solidity flows, generic enough for sequence / flow / state / ER / topology diagrams.",
5
5
  "license": "MIT",
6
6
  "author": "cardene777",
@@ -28,6 +28,16 @@ const 上下の余白 = 2;
28
28
  /** 箱の左右に空ける余白 (片側) */
29
29
  const 左右の余白 = 8;
30
30
 
31
+ /**
32
+ * その箱で文字に使える幅。
33
+ *
34
+ * **余白を呼出側に写さない**。 写すと余白を変えた時に片方だけ古くなり、`箱に積む` を通る
35
+ * 経路と通らない経路で収まる幅が変わる (cdl#526 で 1 行だけの経路が幅を見ていなかった)。
36
+ */
37
+ export function 使える幅(箱の幅: number): number {
38
+ return 箱の幅 - 左右の余白 * 2;
39
+ }
40
+
31
41
  export type 積む行 = {
32
42
  役割: "title" | "subtitle";
33
43
  text: string;
@@ -109,12 +119,12 @@ export function 箱に積む(行: 積む行[], 箱の幅: number, 箱の高さ:
109
119
  const 残す = [...候補];
110
120
  while (残す.length > 1 && 高さ(残す) > 使える高さ) 残す.pop();
111
121
 
112
- const 使える幅 = 箱の幅 - 左右の余白 * 2;
122
+ const = 使える幅(箱の幅);
113
123
  const 総高 = 高さ(残す);
114
124
  let 積み = -総高 / 2;
115
125
  return 残す.map((r) => {
116
126
  const dy = 積み + ((行送りの比 + 字の高さの比) / 2) * r.fontSize;
117
127
  積み += r.fontSize * 行送りの比;
118
- return { ...r, text: 幅で切る(r.text, r.fontSize, 使える幅), dy };
128
+ return { ...r, text: 幅で切る(r.text, r.fontSize, ), dy };
119
129
  });
120
130
  }
@@ -1,6 +1,6 @@
1
1
  import type { JSX } from "react";
2
- import { 箱に積む } from "./box-lines";
3
- import type { LaidNode, Tone, MindBranchNode } from "../types";
2
+ import { 使える幅, 幅で切る, 箱に積む } from "./box-lines";
3
+ import type { LaidNode, Tone, MindBranchNode, MindBranchPayload } from "../types";
4
4
  import { TONE } from "../render/tone";
5
5
  import { resolveMindData } from "../render/payload-binding";
6
6
  import { 進みを畳む, 伸ばすdash, 段の伸び } from "./draw-progress";
@@ -147,6 +147,9 @@ export function MindMapNode({
147
147
  </text>
148
148
  ))
149
149
  ) : (
150
+ // 補足が無くても **幅に収める** (#526)。 `箱に積む` を通らないこの経路だけが
151
+ // 幅を見ておらず、長い名前がそのまま箱の外へ出て枝の線と重なっていた
152
+ // (実測 = 中心の箱で文字 163px に対し箱 120px)
150
153
  <text
151
154
  x={n.x}
152
155
  y={n.y + 5}
@@ -155,7 +158,7 @@ export function MindMapNode({
155
158
  textAnchor="middle"
156
159
  fill={文字の色}
157
160
  >
158
- {n.title}
161
+ {幅で切る(n.title, n.isRoot ? 15 : 13, 使える幅(n.w))}
159
162
  </text>
160
163
  )}
161
164
  </g>
@@ -192,7 +195,7 @@ type LayoutEdge = {
192
195
  };
193
196
 
194
197
  export function computeMindMapLayout(
195
- mindData: { rootId: string; rootTitle: string; branches: MindBranchNode[] },
198
+ mindData: MindBranchPayload,
196
199
  cx: number,
197
200
  cy: number,
198
201
  canvasW: number,
@@ -206,6 +209,8 @@ export function computeMindMapLayout(
206
209
  nodes.push({
207
210
  id: mindData.rootId,
208
211
  title: mindData.rootTitle,
212
+ // 中心も枝と同じく 2 行に積める (#530)。 高さ 52 に 15px + 9px の 2 行が入る
213
+ ...(mindData.rootSubtitle === undefined ? {} : { subtitle: mindData.rootSubtitle }),
209
214
  x: cx,
210
215
  y: cy,
211
216
  w: rootW,
@@ -2,7 +2,7 @@ import type { JSX } from "react";
2
2
  import type { LaidNode, TreeNodePayload } from "../types";
3
3
  import { TONE } from "../render/tone";
4
4
  import { resolveTreeData } from "../render/payload-binding";
5
- import { 箱に積む, type 積んだ行 } from "../kinds/box-lines";
5
+ import { 使える幅, 幅で切る, 箱に積む, type 積んだ行 } from "../kinds/box-lines";
6
6
  import { 進みを畳む, 伸ばすdash, 段の伸び } from "./draw-progress";
7
7
 
8
8
  /**
@@ -190,6 +190,8 @@ export function TreeNode({
190
190
  名前の太さ: 700,
191
191
  })
192
192
  ) : (
193
+ // 補足が無くても幅に収める (#526)。 `箱の文字` を通らないこの経路だけが
194
+ // 幅を見ておらず、長い名前が箱の外へ出ていた
193
195
  <text
194
196
  x={n.w / 2}
195
197
  y={n.h / 2 + 5}
@@ -198,7 +200,7 @@ export function TreeNode({
198
200
  textAnchor="middle"
199
201
  fill="var(--cdl-text-on-tone, #ffffff)"
200
202
  >
201
- {n.title}
203
+ {幅で切る(n.title, 13, 使える幅(n.w))}
202
204
  </text>
203
205
  )}
204
206
  </>
@@ -233,7 +235,7 @@ export function TreeNode({
233
235
  textAnchor="middle"
234
236
  fill="var(--cdl-chip-text, #1a1f2a)"
235
237
  >
236
- {n.title}
238
+ {幅で切る(n.title, 12, 使える幅(n.w))}
237
239
  </text>
238
240
  )}
239
241
  </>
package/src/presets.ts CHANGED
@@ -1292,6 +1292,8 @@ export type MindMapPreset = {
1292
1292
  /** 中心 topic ID + label */
1293
1293
  rootId: string;
1294
1294
  rootTitle: string;
1295
+ /** 中心の箱の 2 行目に出す補足 (#530)。 枝の `subtitle` と同じ扱い */
1296
+ rootSubtitle?: string;
1295
1297
  branchWidth?: number;
1296
1298
  defaultTone?: Tone;
1297
1299
  };
@@ -1338,6 +1340,7 @@ export function mindMap(preset: MindMapPreset): MindMapBuilder {
1338
1340
  mindData: {
1339
1341
  rootId: preset.rootId,
1340
1342
  rootTitle: preset.rootTitle,
1343
+ ...(preset.rootSubtitle === undefined ? {} : { rootSubtitle: preset.rootSubtitle }),
1341
1344
  branches: branches.map((br) => ({
1342
1345
  id: br.id,
1343
1346
  title: br.title,
@@ -252,9 +252,9 @@ export function resolveTreeData(
252
252
  }
253
253
 
254
254
  /**
255
- * 放射の名前と補足を解決する。 中心の名前と枝の名前 / 補足を見る。
255
+ * 放射の名前と補足を解決する。 中心と枝の名前 / 補足を見る。
256
256
  *
257
- * 補足を入れた理由は `resolveTreeData` と同じ (#471)。 中心は補足の欄を持たない。
257
+ * 補足を入れた理由は `resolveTreeData` と同じ (#471 / #530)。
258
258
  */
259
259
  export function resolveMindData(
260
260
  data: MindBranchPayload,
@@ -262,10 +262,13 @@ export function resolveMindData(
262
262
  ): ResolvedMindData {
263
263
  const 読む =
264
264
  data.rootTitle.includes("{") ||
265
+ (data.rootSubtitle?.includes("{") ?? false) ||
265
266
  data.branches.some((b) => b.title.includes("{") || (b.subtitle?.includes("{") ?? false));
266
267
  if (!読む) return data as ResolvedMindData;
267
268
 
268
269
  const root = resolveBoundText(data.rootTitle, values);
270
+ const rootSubtitle =
271
+ data.rootSubtitle === undefined ? undefined : resolveBoundText(data.rootSubtitle, values);
269
272
  const branches = data.branches.map((b) => {
270
273
  const title = resolveBoundText(b.title, values);
271
274
  const subtitle = b.subtitle === undefined ? undefined : resolveBoundText(b.subtitle, values);
@@ -276,6 +279,13 @@ export function resolveMindData(
276
279
  };
277
280
  return title.ok && (subtitle?.ok ?? true) ? 解決後 : { ...解決後, unresolved: true as const };
278
281
  });
279
- const 解決後: ResolvedMindData = { ...data, rootTitle: root.value, branches };
280
- return root.ok ? 解決後 : { ...解決後, unresolved: true as const };
282
+ const 解決後: ResolvedMindData = {
283
+ ...data,
284
+ rootTitle: root.value,
285
+ ...(rootSubtitle ? { rootSubtitle: rootSubtitle.value } : {}),
286
+ branches,
287
+ };
288
+ return root.ok && (rootSubtitle?.ok ?? true)
289
+ ? 解決後
290
+ : { ...解決後, unresolved: true as const };
281
291
  }
@@ -179,6 +179,7 @@ function payloadTexts(node: CdlNode): string[] {
179
179
  }
180
180
  if (node.mindData) {
181
181
  足す(node.mindData.rootTitle);
182
+ 足す(node.mindData.rootSubtitle);
182
183
  for (const b of node.mindData.branches) {
183
184
  足す(b.title);
184
185
  足す(b.subtitle);
package/src/types.ts CHANGED
@@ -359,6 +359,14 @@ export type GanttTaskPayload = {
359
359
  export type MindBranchPayload = {
360
360
  rootId: string;
361
361
  rootTitle: string;
362
+ /**
363
+ * 中心の箱の 2 行目に出す補足 (#530)。
364
+ *
365
+ * 枝 (`MindBranchNode`) は元から `subtitle` を持つのに中心だけ渡す口が無く、呼出側が
366
+ * 名前と補足を連結して `rootTitle` に入れていた。 1 行に全部入るため箱幅を超え、
367
+ * 末尾が切られる (実測 = 箱 120px に対し文字 163px)。
368
+ */
369
+ rootSubtitle?: string;
362
370
  branches: MindBranchNode[];
363
371
  };
364
372