@cardenelabs/cdl 0.17.0 → 0.17.1
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 +50 -1
- package/dist/index.cjs +20 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +20 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +20 -15
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +20 -15
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/src/kinds/sequence-board.tsx +9 -1
- package/src/kinds/storage.tsx +5 -4
- package/src/layout/nodes.ts +8 -7
- package/src/layout/spec.ts +22 -4
- package/src/visual-validate.ts +24 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardenelabs/cdl",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
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",
|
|
@@ -68,7 +68,15 @@ export function SequenceBoardNode({
|
|
|
68
68
|
const v = Number.parseInt(interpolate(node.sequenceStep, stateValues ?? {}).trim(), 10);
|
|
69
69
|
return Number.isFinite(v) ? v : null;
|
|
70
70
|
})();
|
|
71
|
-
|
|
71
|
+
/*
|
|
72
|
+
* いまの言づての色 (#580)。
|
|
73
|
+
*
|
|
74
|
+
* **意味の 6 色とは別に持つ**。 `--cdl-tone-accent` は「呼び」 のような図の中の意味を
|
|
75
|
+
* 描き分ける色で、利用側が系統色から取ることがある (実測 = dragon は青)。 ここが指すのは
|
|
76
|
+
* 意味ではなく「いまどこか」 で、役割は強調した箱の枠と同じ = 利用側の主役色に揃うべき。
|
|
77
|
+
* 書かれていなければ従来どおり意味の色へ落ちる。
|
|
78
|
+
*/
|
|
79
|
+
const 朱 = "var(--cdl-now, var(--cdl-tone-accent, #2d6a8f))";
|
|
72
80
|
/** 済んだ言づての色。 薄めるのではなく墨へ移すので、後からでも読める濃さを持つ */
|
|
73
81
|
const 墨 = "var(--cdl-text-2, #4a5162)";
|
|
74
82
|
|
package/src/kinds/storage.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
ROW_TOP_STORAGE,
|
|
8
8
|
STORAGE_ROW_DIVIDER_Y,
|
|
9
9
|
STORAGE_TITLE_BASELINE,
|
|
10
|
+
STORAGE_TITLE_FONT,
|
|
10
11
|
SUBTITLE_ROW_SHIFT,
|
|
11
12
|
rowBaselineY,
|
|
12
13
|
rowGlyphDepth,
|
|
@@ -37,7 +38,7 @@ const ROW_GLYPH_CX = ROW_PAD_X_PX + ROW_GLYPH_HALF + 1;
|
|
|
37
38
|
const ROW_GLYPH_LEAD = 40;
|
|
38
39
|
|
|
39
40
|
/** 印を持つ行の型の級。 名前 (26) より 1 段落とし、色も薄くして名前を先に読ませる */
|
|
40
|
-
const ROW_TYPE_FONT =
|
|
41
|
+
const ROW_TYPE_FONT = 22;
|
|
41
42
|
|
|
42
43
|
/** 印の中心を baseline からどれだけ上へ置くか。 級の 1/3 が字の見た目の中心 */
|
|
43
44
|
const ROW_GLYPH_RISE = 8;
|
|
@@ -48,10 +49,10 @@ const ROW_GLYPH_RISE = 8;
|
|
|
48
49
|
* 題 (78) と 1 行目 (130) の間。 印で分ける箱では区切り線を引かないので、その分の余白が空く。
|
|
49
50
|
* ER の表名や状態の名前は識別子なので、その下に日本語の呼び名を薄く添える。
|
|
50
51
|
*/
|
|
51
|
-
const SUBTITLE_BASELINE =
|
|
52
|
+
const SUBTITLE_BASELINE = 118;
|
|
52
53
|
|
|
53
54
|
/** 呼び名の級。 行の名前 (26) より小さく、型 (24) と同じ */
|
|
54
|
-
const SUBTITLE_FONT =
|
|
55
|
+
const SUBTITLE_FONT = 20;
|
|
55
56
|
|
|
56
57
|
/** 主キーの下線を名前の baseline からどれだけ下に引くか */
|
|
57
58
|
const UNDERLINE_DROP = 7;
|
|
@@ -98,7 +99,7 @@ export function StorageNode({
|
|
|
98
99
|
const x = node.cx - node.w / 2;
|
|
99
100
|
const y = node.cy - node.h / 2;
|
|
100
101
|
// 小型の箱では名前を中央に置く。 固定の位置のままだと下端をまたぐ (#416)
|
|
101
|
-
const 名前 = titlePlacement(node, { x: 26, y: STORAGE_TITLE_BASELINE, size:
|
|
102
|
+
const 名前 = titlePlacement(node, { x: 26, y: STORAGE_TITLE_BASELINE, size: STORAGE_TITLE_FONT }, { hasEyebrow: Boolean(node.eyebrow) });
|
|
102
103
|
// 全 row を delimiter (`:` / ` = ` / ` → ` / ` -> `) で left / right に分割し、
|
|
103
104
|
// left 列 max 文字数を算出 → 右列の固定 x 位置を決める (DB table / UML class box 風)。
|
|
104
105
|
// 結果として全 row の右列開始 x が揃い、 区切り線がガタつかなくなる。
|
package/src/layout/nodes.ts
CHANGED
|
@@ -189,18 +189,19 @@ export function layoutNodes(diag: CdlDiagram, lanes: LaidLane[]): LaidNode[] {
|
|
|
189
189
|
const 段の芯 = rowCy.get(n.stack)!;
|
|
190
190
|
const 段の高さ = rowH.get(n.stack)!;
|
|
191
191
|
/*
|
|
192
|
-
* 行頭の印を持つ箱は
|
|
192
|
+
* 行頭の印を持つ箱は **自分の高さで、段の芯に揃える** (#578 → #580)。
|
|
193
193
|
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
194
|
+
* 既定は段の高さに合わせて伸ばす = 行が 1 つしか無い箱が 4 行の箱と同じ高さになり、
|
|
195
|
+
* 下が空いたまま並ぶ。 印を持つ箱は高さを中身から出しているので (`autoStorageHeight`)、
|
|
196
|
+
* 伸ばすとその値が捨てられる。
|
|
196
197
|
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
198
|
+
* **揃える先は芯**。 #578 では上端に揃えていたが、高さの違う箱が横に並ぶと
|
|
199
|
+
* 図全体が上へ寄って見えた (user 指摘)。 芯で揃えると上端も下端も箱ごとに違うが、
|
|
200
|
+
* 並びの重心が 1 本に通る。 見た目検査の `row-alignment` もこの前提で書かれている。
|
|
200
201
|
*/
|
|
201
202
|
const 自前の高さ = n.rowMarks !== undefined;
|
|
202
203
|
const h = n.h ?? (自前の高さ ? autoStorageHeight(n, size.h) : 段の高さ);
|
|
203
|
-
const cy =
|
|
204
|
+
const cy = 段の芯;
|
|
204
205
|
// n.w 明示時は尊重、 未指定で rows[] を持つ node は内容長に合わせて auto 拡張。
|
|
205
206
|
const w = autoRowsWidth(n, size.w);
|
|
206
207
|
out.push({
|
package/src/layout/spec.ts
CHANGED
|
@@ -242,8 +242,13 @@ export function genericTitleBaselineY(kind: string | undefined, h: number, hasRo
|
|
|
242
242
|
: GENERIC_TITLE_TOP + genericTextShift(kind);
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
/**
|
|
246
|
-
|
|
245
|
+
/**
|
|
246
|
+
* `kinds/storage.tsx` の 1 行目 baseline と行送り。
|
|
247
|
+
*
|
|
248
|
+
* 1 行目は #1468 で 130 から下げた。 題を 22 から 34 に上げたぶん、題の下に空きが要る
|
|
249
|
+
* (実測 = 130 のままだと題の descender と 1 行目の cap が 6 まで詰まる)。
|
|
250
|
+
*/
|
|
251
|
+
export const ROW_TOP_STORAGE = 152;
|
|
247
252
|
export const ROW_PITCH_STORAGE = 56;
|
|
248
253
|
|
|
249
254
|
/** `kinds/generic.tsx` の 1 行目 baseline と行送り。 */
|
|
@@ -276,8 +281,21 @@ export const GLYPH_CAP_RATIO = 0.72;
|
|
|
276
281
|
export const ROW_FONT_STORAGE = 26;
|
|
277
282
|
export const ROW_FONT_GENERIC = 21;
|
|
278
283
|
|
|
279
|
-
/**
|
|
280
|
-
|
|
284
|
+
/**
|
|
285
|
+
* `kinds/storage.tsx` の名前 (title) の baseline。
|
|
286
|
+
*
|
|
287
|
+
* #1468 で 78 から下げた。 題が 34 になり、上端から baseline までに cap 分の余白が要る。
|
|
288
|
+
*/
|
|
289
|
+
export const STORAGE_TITLE_BASELINE = 86;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* `kinds/storage.tsx` の名前 (title) の字の大きさ (#1468)。
|
|
293
|
+
*
|
|
294
|
+
* **行 (`ROW_FONT_STORAGE` = 26) より大きい**。 22 だった間は題の方が小さく、箱の中で
|
|
295
|
+
* 何が見出しか読み取れなかった (user 指摘)。 題 34 / 行 26 / 型 22 の 3 段にして、
|
|
296
|
+
* 上から順に読む順序を字の大きさで示す。
|
|
297
|
+
*/
|
|
298
|
+
export const STORAGE_TITLE_FONT = 34;
|
|
281
299
|
|
|
282
300
|
/**
|
|
283
301
|
* 呼び名を出す箱で、行の群をどれだけ下げるか (#578)。
|
package/src/visual-validate.ts
CHANGED
|
@@ -125,6 +125,7 @@ export type { EdgeLabelLine, EdgeLabelTextSpec } from "./label-text";
|
|
|
125
125
|
import {
|
|
126
126
|
ARROW_ENDPOINT_CENTER_TOL,
|
|
127
127
|
COLUMN_GAP_VARIANCE_TOL,
|
|
128
|
+
requiredNearClearance,
|
|
128
129
|
DETOUR_CREST_OVERLAP_MIN,
|
|
129
130
|
DETOUR_SLOT_GAP,
|
|
130
131
|
EDGE_STUB_OUT,
|
|
@@ -2493,18 +2494,9 @@ function runAxes(
|
|
|
2493
2494
|
for (const [stack, group] of byStack) {
|
|
2494
2495
|
if (group.length < 2) continue;
|
|
2495
2496
|
const cy0 = group[0]!.cy;
|
|
2496
|
-
/*
|
|
2497
|
-
* **上端で揃える形も認める** (#578 の設計)。
|
|
2498
|
-
*
|
|
2499
|
-
* 高さの違う箱を横に並べる図 (表 / クラス / 状態) では、中心ではなく上端を揃える。
|
|
2500
|
-
* 中心だけを見ると、正しく上端で揃っている行が高さの差の半分だけずれて見える
|
|
2501
|
-
* (実測 = 行数の違う表で 28 の差)。 どちらかで揃っていれば揃っているとみなす。
|
|
2502
|
-
*/
|
|
2503
|
-
const top0 = cy0 - (group[0]!.h ?? 0) / 2;
|
|
2504
2497
|
for (const n of group.slice(1)) {
|
|
2505
2498
|
const diff = Math.abs(n.cy - cy0);
|
|
2506
|
-
|
|
2507
|
-
if (diff > MIN_ROW_ALIGNMENT_TOLERANCE && topDiff > MIN_ROW_ALIGNMENT_TOLERANCE) {
|
|
2499
|
+
if (diff > MIN_ROW_ALIGNMENT_TOLERANCE) {
|
|
2508
2500
|
push(
|
|
2509
2501
|
"row-alignment",
|
|
2510
2502
|
`stack=${stack} row 内 node "${n.id}" cy=${n.cy.toFixed(1)} が row 基準 cy=${cy0.toFixed(1)} と ${diff.toFixed(1)} world 差 (許容 ${MIN_ROW_ALIGNMENT_TOLERANCE})`,
|
|
@@ -4239,24 +4231,37 @@ function runAxes(
|
|
|
4239
4231
|
const sorted = [...group].sort((a, b) => a.cy - b.cy);
|
|
4240
4232
|
const gaps: number[] = [];
|
|
4241
4233
|
/*
|
|
4242
|
-
*
|
|
4243
|
-
*
|
|
4244
|
-
* 段の位置を著者が決める図 (クラス / 表 / 状態) では、engine が制御しているのは
|
|
4245
|
-
* 段の基準線であって端の間隔ではない。 箱の高さが段ごとに違うと端の間隔は必ずばらつく
|
|
4246
|
-
* (実測 = クラス図の 2 列目で 132 と 300)。 どちらかが揃っていれば揃っているとみなす。
|
|
4234
|
+
* 端の間隔で測る理由は下の Issue #202 の節を参照。
|
|
4247
4235
|
*/
|
|
4248
|
-
const tops: number[] = [];
|
|
4249
4236
|
for (let i = 1; i < sorted.length; i++) {
|
|
4250
4237
|
const prev = sorted[i - 1]!;
|
|
4251
4238
|
const cur = sorted[i]!;
|
|
4252
4239
|
gaps.push(cur.cy - cur.h / 2 - (prev.cy + prev.h / 2));
|
|
4253
|
-
tops.push(cur.cy - cur.h / 2 - (prev.cy - prev.h / 2));
|
|
4254
4240
|
}
|
|
4255
4241
|
const maxGap = Math.max(...gaps);
|
|
4256
4242
|
const minGap = Math.min(...gaps);
|
|
4257
4243
|
const variance = maxGap - minGap;
|
|
4258
|
-
|
|
4259
|
-
|
|
4244
|
+
/*
|
|
4245
|
+
* **格子に置いた箱では間隔の均一を求めない** (#580)。
|
|
4246
|
+
*
|
|
4247
|
+
* この軸は「engine が縦の間隔を制御している」 ことを前提に、そのばらつきを layout の
|
|
4248
|
+
* 破綻として見る。 行頭の印を持つ箱は前提が違う = 段の位置を著者が `col` / `row` で決め、
|
|
4249
|
+
* 高さは中身から出る (`autoStorageHeight`)。 段ごとに背の高さが違えば、端の間隔も芯の
|
|
4250
|
+
* 間隔も必ずばらつく (実測 = クラス図の 2 列目で端 132/216、芯 528/472)。
|
|
4251
|
+
*
|
|
4252
|
+
* **近づき過ぎだけは見る** (#202)。 間隔の均一を外しても、箱どうしが接する形は通さない
|
|
4253
|
+
* (#202 が実測した形 = 芯の間隔が揃い、端の間隔が 100 と 0)。
|
|
4254
|
+
*/
|
|
4255
|
+
const 格子に置く = group.every((n) => n.rowMarks !== undefined);
|
|
4256
|
+
const 端が足りている = minGap >= requiredNearClearance("node", "node");
|
|
4257
|
+
if (格子に置く) {
|
|
4258
|
+
if (!端が足りている) {
|
|
4259
|
+
push(
|
|
4260
|
+
"column-gap-uniform",
|
|
4261
|
+
`lane "${laneId}" 内 node 間の端間 gap ${minGap.toFixed(0)} world が下限 ${requiredNearClearance("node", "node")} を割る`,
|
|
4262
|
+
);
|
|
4263
|
+
}
|
|
4264
|
+
} else if (variance > COLUMN_GAP_VARIANCE_TOL) {
|
|
4260
4265
|
push(
|
|
4261
4266
|
"column-gap-uniform",
|
|
4262
4267
|
`lane "${laneId}" 内 node 間の端間 gap variance ${variance.toFixed(1)} world が spec ${COLUMN_GAP_VARIANCE_TOL} 超過 (min=${minGap.toFixed(0)} max=${maxGap.toFixed(0)})`,
|