@cardenelabs/cdl 0.115.0 → 0.117.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 +69 -1
- package/dist/index.cjs +47 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +47 -5
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +10 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +10 -3
- package/dist/react.js.map +1 -1
- package/dist/{render-oEmwYN-q.d.cts → render-A5AKjNuy.d.cts} +1 -1
- package/dist/{render-oEmwYN-q.d.ts → render-A5AKjNuy.d.ts} +1 -1
- package/package.json +1 -1
- package/src/index.ts +3 -0
- package/src/kinds/tree.tsx +78 -2
- package/src/presets.ts +5 -1
- package/src/visual-validate.ts +22 -1
|
@@ -3035,4 +3035,4 @@ type CdlDiagramViewProps = {
|
|
|
3035
3035
|
};
|
|
3036
3036
|
declare function CdlDiagramView({ diagram, laid: laidProp, hideHeader, hideMiniPhaseIndicator, focusPhaseId, debug, emitGeometryWarn, headingLevel, interactiveHandlers }: CdlDiagramViewProps): JSX.Element;
|
|
3037
3037
|
|
|
3038
|
-
export {
|
|
3038
|
+
export { computeEventBindingKey as $, EDGE_HEADS as A, type BBox as B, type CdlDiagram as C, EDGE_HEAD_DEFAULT as D, type EdgeStyle as E, EDGE_HEAD_FILLS as F, EDGE_HEAD_FILL_DEFAULT as G, EDGE_REVEALS as H, EDGE_REVEAL_DEFAULT as I, type JourneyEmotion as J, EDGE_STYLES as K, type LaidDiagram as L, type EdgeReveal as M, type NodeKind as N, type InteractiveHandlerMap as O, type InteractiveSignalsAccessor as P, type QuadrantKey as Q, type RowMark as R, type Signal as S, type Tone as T, type LaidLane as U, NODE_KINDS as V, RELATION_FOCUSES as W, RELATION_FOCUS_DEFAULT as X, type RelationFocus as Y, type ScrollProgressHandle as Z, TONES as _, type CdlInput as a, computeFormulaKey as a0, computeInputSignalKey as a1, computeScrollTriggerKey as a2, computed as a3, createInteractiveSignalsAccessor as a4, createScrollProgressHandle as a5, createScrollProgressSignals as a6, hasInteractivePrimitives as a7, resolveLang as a8, sequenceBoardMetrics as a9, sequenceStepId as aa, signal as ab, type CdlLane as b, type CdlNode as c, type Side as d, type EdgeRole as e, type EdgeHead as f, type EdgeHeadFill as g, type CdlState as h, type CdlInputOption as i, type CdlEventTarget as j, type CdlLang as k, type Computed as l, type CdlDerivedValue as m, type CdlScrollTrigger as n, type CdlDiagramViewProps as o, type LaidEdge as p, type LaidNode as q, type CdlEdge as r, type TreeNodePayload as s, CdlDiagramView as t, type CdlEventBinding as u, type CdlEventKind as v, type CdlFormula as w, type CdlPhase as x, type ChartPieForm as y, type ChartSlopeForm as z };
|
|
@@ -3035,4 +3035,4 @@ type CdlDiagramViewProps = {
|
|
|
3035
3035
|
};
|
|
3036
3036
|
declare function CdlDiagramView({ diagram, laid: laidProp, hideHeader, hideMiniPhaseIndicator, focusPhaseId, debug, emitGeometryWarn, headingLevel, interactiveHandlers }: CdlDiagramViewProps): JSX.Element;
|
|
3037
3037
|
|
|
3038
|
-
export {
|
|
3038
|
+
export { computeEventBindingKey as $, EDGE_HEADS as A, type BBox as B, type CdlDiagram as C, EDGE_HEAD_DEFAULT as D, type EdgeStyle as E, EDGE_HEAD_FILLS as F, EDGE_HEAD_FILL_DEFAULT as G, EDGE_REVEALS as H, EDGE_REVEAL_DEFAULT as I, type JourneyEmotion as J, EDGE_STYLES as K, type LaidDiagram as L, type EdgeReveal as M, type NodeKind as N, type InteractiveHandlerMap as O, type InteractiveSignalsAccessor as P, type QuadrantKey as Q, type RowMark as R, type Signal as S, type Tone as T, type LaidLane as U, NODE_KINDS as V, RELATION_FOCUSES as W, RELATION_FOCUS_DEFAULT as X, type RelationFocus as Y, type ScrollProgressHandle as Z, TONES as _, type CdlInput as a, computeFormulaKey as a0, computeInputSignalKey as a1, computeScrollTriggerKey as a2, computed as a3, createInteractiveSignalsAccessor as a4, createScrollProgressHandle as a5, createScrollProgressSignals as a6, hasInteractivePrimitives as a7, resolveLang as a8, sequenceBoardMetrics as a9, sequenceStepId as aa, signal as ab, type CdlLane as b, type CdlNode as c, type Side as d, type EdgeRole as e, type EdgeHead as f, type EdgeHeadFill as g, type CdlState as h, type CdlInputOption as i, type CdlEventTarget as j, type CdlLang as k, type Computed as l, type CdlDerivedValue as m, type CdlScrollTrigger as n, type CdlDiagramViewProps as o, type LaidEdge as p, type LaidNode as q, type CdlEdge as r, type TreeNodePayload as s, CdlDiagramView as t, type CdlEventBinding as u, type CdlEventKind as v, type CdlFormula as w, type CdlPhase as x, type ChartPieForm as y, type ChartSlopeForm as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardenelabs/cdl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.117.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",
|
package/src/index.ts
CHANGED
|
@@ -220,6 +220,9 @@ export { CLASS_RELATION_LOOK, ER_CARDINALITY_HEAD, FSM_ACTION_MARK, SEQUENCE_MES
|
|
|
220
220
|
// 時系列のやり取りの図が引く名前と寸法 (#578)。 **組み立て器ではない** ので presets からは出さない
|
|
221
221
|
// (`mermaid-parity` が presets の公開関数を組み立て器として数える)
|
|
222
222
|
export { sequenceStepId, sequenceBoardMetrics } from "./kinds/sequence-board-metrics";
|
|
223
|
+
// 木の札の幅 (#970)。 葉の数で必要な幅が変わるので、組み立てる側が札を作る前に引く。
|
|
224
|
+
// **組み立て器ではない** ので presets からは出さない (`mermaid-parity` の数え方に合わせる)
|
|
225
|
+
export { 木の札の幅 } from "./kinds/tree";
|
|
223
226
|
// Text DSL は @cardenelabs/dragon に切出済 (cdl は engine only)
|
|
224
227
|
export type {
|
|
225
228
|
SwimlanePreset,
|
package/src/kinds/tree.tsx
CHANGED
|
@@ -62,6 +62,82 @@ const PAD_RIGHT = 24;
|
|
|
62
62
|
const PAD_BOTTOM = 40;
|
|
63
63
|
const PAD_LEFT = 24;
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* 箱の上限 (#970)。 割付の中で `Math.min` の相手として使う値を module に出した。
|
|
67
|
+
*
|
|
68
|
+
* 札の大きさを中身から出すには、置く前に「箱がどれだけ取るか」 を知る必要がある。
|
|
69
|
+
* 割付の中に閉じていると、呼ぶ側は同じ数を書き写すしかない。
|
|
70
|
+
*/
|
|
71
|
+
const 箱の最大幅 = 140;
|
|
72
|
+
const 箱の最大高さ = 38;
|
|
73
|
+
|
|
74
|
+
/** 札の既定の大きさ。 中身から出した値がこれを超える時の頭打ちになる (#970) */
|
|
75
|
+
const 札の既定幅 = 720;
|
|
76
|
+
const 札の既定高さ = 480;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 木を描くのに要る札の幅を、葉の数から出す (#970)。
|
|
80
|
+
*
|
|
81
|
+
* 木の札は種別ごとに 1 つの値 (720) で固定されていた。 必要な幅は葉の数で変わるので、
|
|
82
|
+
* 葉が少ない図は札の中で浮く (実測 = 葉 2 枚の図が 720 の札に 476 で、左右に 122 ずつ余る)。
|
|
83
|
+
*
|
|
84
|
+
* **縦が既に持っている規則を、横にも当てる**。
|
|
85
|
+
* 段は `canvasH / 段数` で等分した区画の中央に置かれるので、縦の余白は隙間の半分ずつになる。
|
|
86
|
+
* 同じ形を横に当てると `葉の数 × (箱の幅 + 隙間)` で、中身の左右にも隙間の半分ずつが残る。
|
|
87
|
+
* 実際 3 段の木では この式が今の高さ (480) をそのまま返す = 縦は既にこの値で描かれている。
|
|
88
|
+
*
|
|
89
|
+
* **広げる向きには使わない** (`Math.min(札の既定幅, ...)`)。 葉が多い図では式の値が
|
|
90
|
+
* 既定を超えるが、札を広げると見本帳の並びが崩れる。 超える図は今までどおり区画が狭まり、
|
|
91
|
+
* 箱が小さくなる側で吸収する。
|
|
92
|
+
*
|
|
93
|
+
* **葉が 1 枚の図は 2 枚として扱う**。 1 枚の木は縦 1 本の鎖で、式のまま出すと
|
|
94
|
+
* 箱 1 つぶんの幅 (188) になる。 縦に長く横に細い札は、木ではなく縦書きの字列に見える。
|
|
95
|
+
*/
|
|
96
|
+
export function 木の札の幅(treeNodes: TreeNodePayload[]): number {
|
|
97
|
+
const { 葉の数, 段数 } = 木の形(treeNodes);
|
|
98
|
+
// 隙間は段の隙間と同じ値を使う。 段の高さは札の高さを段数で割った値から出る
|
|
99
|
+
const 段の高さ = (札の既定高さ - PAD_TOP - PAD_BOTTOM) / Math.max(段数, 1);
|
|
100
|
+
const 箱の高さ = Math.min(箱の最大高さ, 段の高さ * 0.7);
|
|
101
|
+
const 隙間 = 段の高さ - 箱の高さ;
|
|
102
|
+
const 要る幅 = Math.max(葉の数, 2) * (箱の最大幅 + 隙間);
|
|
103
|
+
// 切り上げる。 切り下げると区画が要る間隔よりわずかに狭くなり、頭打ちが効いて
|
|
104
|
+
// 葉の隙間が段の隙間より詰まる (割付は `canvasW / 葉の数` を上限に持つ)
|
|
105
|
+
return Math.ceil(Math.min(札の既定幅, 要る幅 + PAD_LEFT + PAD_RIGHT));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 木の形 (葉の数と段数) を出す (#970)。
|
|
110
|
+
*
|
|
111
|
+
* 走査の順と打ち切りは `computeTreeLayout` と同じにする。 親が実在しない項目を根として拾い、
|
|
112
|
+
* 既に見た項目で打ち切るので、循環参照のある入力でも止まる。
|
|
113
|
+
*/
|
|
114
|
+
function 木の形(treeNodes: TreeNodePayload[]): { 葉の数: number; 段数: number } {
|
|
115
|
+
const ids = new Set(treeNodes.map((n) => n.id));
|
|
116
|
+
const childrenOf = new Map<string, TreeNodePayload[]>();
|
|
117
|
+
for (const n of treeNodes) {
|
|
118
|
+
const p = n.parent && ids.has(n.parent) ? n.parent : "__root__";
|
|
119
|
+
if (!childrenOf.has(p)) childrenOf.set(p, []);
|
|
120
|
+
childrenOf.get(p)!.push(n);
|
|
121
|
+
}
|
|
122
|
+
const 見た = new Set<string>();
|
|
123
|
+
let 葉の数 = 0;
|
|
124
|
+
let 段数 = 0;
|
|
125
|
+
const 下見 = (n: TreeNodePayload, depth: number): void => {
|
|
126
|
+
見た.add(n.id);
|
|
127
|
+
段数 = Math.max(段数, depth + 1);
|
|
128
|
+
const kids = (childrenOf.get(n.id) ?? []).filter((k) => !見た.has(k.id));
|
|
129
|
+
if (kids.length === 0) {
|
|
130
|
+
葉の数 += 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
for (const k of kids) 下見(k, depth + 1);
|
|
134
|
+
};
|
|
135
|
+
for (const r of childrenOf.get("__root__") ?? []) if (!見た.has(r.id)) 下見(r, 0);
|
|
136
|
+
// 循環参照で根から辿れない項目は、宣言順で最初に現れたものを根として拾う
|
|
137
|
+
for (const n of treeNodes) if (!見た.has(n.id)) 下見(n, 0);
|
|
138
|
+
return { 葉の数, 段数 };
|
|
139
|
+
}
|
|
140
|
+
|
|
65
141
|
/**
|
|
66
142
|
* 枝の太さ。 根に近いほど太く、葉へ行くほど細い (#909)。
|
|
67
143
|
*
|
|
@@ -383,8 +459,8 @@ export function computeTreeLayout(
|
|
|
383
459
|
// box は必ず slot の一定割合に収める。 加算的な floor (min 12 / min 8 等) を置くと、 深い / 多い
|
|
384
460
|
// 入力で floor が slot を超えて隣と重なる。 slot の割合にすれば規模によらず必ず gap が残る。
|
|
385
461
|
// 深い / 多い入力では box が小さくなるが、 位置のはみ出しは末尾の最終スケールが捌く。
|
|
386
|
-
const nodeH = Math.min(
|
|
387
|
-
const nodeW = Math.min(
|
|
462
|
+
const nodeH = Math.min(箱の最大高さ, depthGap * 0.7);
|
|
463
|
+
const nodeW = Math.min(箱の最大幅, slotW * 0.85);
|
|
388
464
|
|
|
389
465
|
/**
|
|
390
466
|
* 箱の幅を名前から出す (#909)。
|
package/src/presets.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { diagram } from "./builder";
|
|
|
2
2
|
import type { DiagramBuilder } from "./builder";
|
|
3
3
|
import { LANE_PAD_MIN, NODE_SIZE } from "./layout/tokens";
|
|
4
4
|
import { requiredRowsWidth } from "./kinds/row-align";
|
|
5
|
+
import { 木の札の幅 } from "./kinds/tree";
|
|
5
6
|
import {
|
|
6
7
|
sequenceBoardMetrics,
|
|
7
8
|
sequenceStepId,
|
|
@@ -1647,7 +1648,6 @@ export type TreeBuilder = {
|
|
|
1647
1648
|
* .build();
|
|
1648
1649
|
*/
|
|
1649
1650
|
export function tree(preset: TreePreset): TreeBuilder {
|
|
1650
|
-
const canvasW = preset.nodeWidth ? preset.nodeWidth * 2 : 720;
|
|
1651
1651
|
const canvasH = 480;
|
|
1652
1652
|
const b = diagram(preset.id, { topic: preset.topic, type: "tree" });
|
|
1653
1653
|
const treeNodes: TreeNode[] = [];
|
|
@@ -1658,6 +1658,10 @@ export function tree(preset: TreePreset): TreeBuilder {
|
|
|
1658
1658
|
return api;
|
|
1659
1659
|
},
|
|
1660
1660
|
build() {
|
|
1661
|
+
// 札の幅は葉の数で変わる (#970)。 項目が出揃う `build` まで待たないと出せない
|
|
1662
|
+
const canvasW = preset.nodeWidth
|
|
1663
|
+
? preset.nodeWidth * 2
|
|
1664
|
+
: 木の札の幅(treeNodes.map((n) => ({ id: n.id, title: n.title, parent: n.parent })));
|
|
1661
1665
|
b.lane("tree", { width: canvasW });
|
|
1662
1666
|
const nodeId = `${preset.id}-tree`;
|
|
1663
1667
|
b.node(nodeId, {
|
package/src/visual-validate.ts
CHANGED
|
@@ -1945,6 +1945,21 @@ function visualValidateInner(
|
|
|
1945
1945
|
}
|
|
1946
1946
|
}
|
|
1947
1947
|
|
|
1948
|
+
/**
|
|
1949
|
+
* 位置を手で書いた箱か (#972)。
|
|
1950
|
+
*
|
|
1951
|
+
* `posX` と `posY` を **両方** 書いた箱は、自動の配置の並びから外して置くためにある
|
|
1952
|
+
* (`types.ts` の `posX` の説明が「置いた位置に置く」 と定める)。 揃っていないこと自体が
|
|
1953
|
+
* 書き手の指定なので、揃えを見る軸の判定から外す。
|
|
1954
|
+
*
|
|
1955
|
+
* 軸 15 (`lane-cx-consistency`) が同じ条件を先に持っており、その 1 行をここへ括り出した。
|
|
1956
|
+
* **片方だけ書いた箱は外さない** = 片方だけでは自動の配置が生きており、並びから外す指定に
|
|
1957
|
+
* ならない (採用の条件も `posX !== undefined && posY !== undefined` で揃えてある)。
|
|
1958
|
+
*/
|
|
1959
|
+
function 位置を手で書いた(n: { posX?: number; posY?: number }): boolean {
|
|
1960
|
+
return n.posX !== undefined && n.posY !== undefined;
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1948
1963
|
function runAxes(
|
|
1949
1964
|
laid: LaidDiagram,
|
|
1950
1965
|
diag: CdlDiagram,
|
|
@@ -2087,8 +2102,12 @@ function runAxes(
|
|
|
2087
2102
|
// ───────────────────────────────────────────────────────────
|
|
2088
2103
|
// Axis 5: alignment (同 lane 内 node の cx 一致)
|
|
2089
2104
|
// ───────────────────────────────────────────────────────────
|
|
2105
|
+
//
|
|
2106
|
+
// 位置を手で書いた箱は判定にも基準にも使わない (#972)。 **基準から先に外す** =
|
|
2107
|
+
// 先頭の 1 つが手で置かれていると、自動で置いた箱が全部その位置と比べられて落ちる。
|
|
2090
2108
|
const byLane = new Map<string, typeof laid.nodes>();
|
|
2091
2109
|
for (const n of laid.nodes) {
|
|
2110
|
+
if (位置を手で書いた(n)) continue;
|
|
2092
2111
|
const list = byLane.get(n.lane) ?? [];
|
|
2093
2112
|
list.push(n);
|
|
2094
2113
|
byLane.set(n.lane, list);
|
|
@@ -2691,11 +2710,13 @@ function runAxes(
|
|
|
2691
2710
|
// positive-check 経路 (両者 同 tolerance を持つが、 SSOT 経由で spec-driven 判定にする)。
|
|
2692
2711
|
//
|
|
2693
2712
|
// spacer / lifeline は intentional な cx 差を持つので判定対象外。
|
|
2713
|
+
// 位置を手で書いた箱も同じ理由で外す (#972、 軸 5 と同じ条件)。
|
|
2694
2714
|
// ───────────────────────────────────────────────────────────
|
|
2695
2715
|
{
|
|
2696
2716
|
const byLaneCol = new Map<string, LaidDiagram["nodes"]>();
|
|
2697
2717
|
for (const n of laid.nodes) {
|
|
2698
2718
|
if (n.id.endsWith("-spacer") || /^s\d+-/.test(n.id)) continue;
|
|
2719
|
+
if (位置を手で書いた(n)) continue;
|
|
2699
2720
|
const list = byLaneCol.get(n.lane) ?? [];
|
|
2700
2721
|
list.push(n);
|
|
2701
2722
|
byLaneCol.set(n.lane, list);
|
|
@@ -2846,7 +2867,7 @@ function runAxes(
|
|
|
2846
2867
|
if (n.id.endsWith("-spacer") || /^s\d+-/.test(n.id)) continue;
|
|
2847
2868
|
// 座標を明示した node は lane 中心から外れているのが指定どおりの状態なので対象外。
|
|
2848
2869
|
// 「lane 中心と一致しない」 を症状として報告すると、 意図した配置が毎回 warn になる。
|
|
2849
|
-
if (n
|
|
2870
|
+
if (位置を手で書いた(n)) continue;
|
|
2850
2871
|
const lane = laneById.get(n.lane);
|
|
2851
2872
|
if (!lane) continue;
|
|
2852
2873
|
const laneCx = lane.x + lane.width / 2;
|