@cardenelabs/cdl 0.114.0 → 0.116.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 +71 -1
- package/dist/index.cjs +65 -5
- 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 +65 -6
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +28 -4
- 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 +28 -4
- 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 +127 -4
- package/src/presets.ts +5 -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.116.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)。
|
|
@@ -409,6 +485,53 @@ export function computeTreeLayout(
|
|
|
409
485
|
return Math.min(Math.max(要る, nodeW), slotW * 0.92);
|
|
410
486
|
};
|
|
411
487
|
|
|
488
|
+
/*
|
|
489
|
+
置く前に、葉の並びと段を先に出す (#968)。
|
|
490
|
+
|
|
491
|
+
端の葉の箱がどれだけ幅を取るかが判らないと、箱の辺を描画域の端へ合わせられない。
|
|
492
|
+
箱の幅は名前と段から決まる (`箱の幅`) ので、位置より先に出せる。
|
|
493
|
+
|
|
494
|
+
走査の順は `place` と同じ (同じ `childrenOf` を同じ順に辿り、既訪で打ち切る)。
|
|
495
|
+
*/
|
|
496
|
+
const 葉の並び: string[] = [];
|
|
497
|
+
const 段の表 = new Map<string, number>();
|
|
498
|
+
const 幅の表 = new Map<string, number>();
|
|
499
|
+
{
|
|
500
|
+
const 見た = new Set<string>();
|
|
501
|
+
const 下見 = (n: TreeNodePayload, depth: number): void => {
|
|
502
|
+
見た.add(n.id);
|
|
503
|
+
段の表.set(n.id, depth);
|
|
504
|
+
幅の表.set(n.id, 箱の幅(n, depth));
|
|
505
|
+
const kids = (childrenOf.get(n.id) ?? []).filter((k) => !見た.has(k.id));
|
|
506
|
+
if (kids.length === 0) {
|
|
507
|
+
葉の並び.push(n.id);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
for (const k of kids) 下見(k, depth + 1);
|
|
511
|
+
};
|
|
512
|
+
for (const r of roots) if (!見た.has(r.id)) 下見(r, 0);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/*
|
|
516
|
+
葉と葉の隙間を、**段と段の隙間に揃える** (#968)。
|
|
517
|
+
|
|
518
|
+
それまでは葉を `canvasW / 葉の数` で等分した区画の中央に置いていた。
|
|
519
|
+
葉が少ない図では区画が箱よりずっと広くなり、兄弟どうしが遠くへ離れる
|
|
520
|
+
(実測 = 葉 2 枚の図で箱の縁の間が 196 空き、段の隙間 95 の 2 倍になった)。
|
|
521
|
+
|
|
522
|
+
木は根から下へ辿る図なので、横の隙間だけが縦の 2 倍あると、離れた 2 本の列に見える。
|
|
523
|
+
横の隙間を縦の隙間と同じにすれば、図の中の間隔が 1 つの調子で揃う。
|
|
524
|
+
|
|
525
|
+
**今より広げない** (`Math.min(slotW, ...)`)。 葉が多い図では区画の方が狭いので、
|
|
526
|
+
そちらが効いて位置は 1 ポイントも動かない。
|
|
527
|
+
*/
|
|
528
|
+
const 葉の数 = Math.max(葉の並び.length, 1);
|
|
529
|
+
const 段の隙間 = depthGap - nodeH;
|
|
530
|
+
const 葉の間隔 = Math.min(slotW, nodeW + 段の隙間);
|
|
531
|
+
/** 葉の列全体を描画域の真ん中に置く。 葉が 1 枚なら間隔が要らない */
|
|
532
|
+
const 葉のx = (i: number): number =>
|
|
533
|
+
canvasW / 2 - ((葉の数 - 1) * 葉の間隔) / 2 + i * 葉の間隔;
|
|
534
|
+
|
|
412
535
|
const posOf = new Map<string, { x: number; y: number }>();
|
|
413
536
|
const nodes: LayoutNode[] = [];
|
|
414
537
|
const placed = new Set<string>();
|
|
@@ -420,7 +543,7 @@ export function computeTreeLayout(
|
|
|
420
543
|
const kids = (childrenOf.get(n.id) ?? []).filter((k) => !placed.has(k.id));
|
|
421
544
|
let x: number;
|
|
422
545
|
if (kids.length === 0) {
|
|
423
|
-
x = leafCursor
|
|
546
|
+
x = 葉のx(leafCursor);
|
|
424
547
|
leafCursor += 1;
|
|
425
548
|
} else {
|
|
426
549
|
const xs = kids.map((k) => place(k, depth + 1));
|
|
@@ -434,7 +557,7 @@ export function computeTreeLayout(
|
|
|
434
557
|
...(n.subtitle !== undefined ? { subtitle: n.subtitle } : {}),
|
|
435
558
|
x,
|
|
436
559
|
y,
|
|
437
|
-
w: 箱の幅(n, depth),
|
|
560
|
+
w: 幅の表.get(n.id) ?? 箱の幅(n, depth),
|
|
438
561
|
h: nodeH,
|
|
439
562
|
depth,
|
|
440
563
|
...((n as { unresolved?: true }).unresolved ? { unresolved: true as const } : {}),
|
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, {
|