@cardenelabs/cdl 0.50.0 → 0.52.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 +33 -1
- package/dist/index.cjs +125 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +125 -5
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +117 -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 +117 -4
- package/dist/react.js.map +1 -1
- package/dist/{render-C53-PeJZ.d.cts → render-C0PJ2weJ.d.cts} +13 -0
- package/dist/{render-C53-PeJZ.d.ts → render-C0PJ2weJ.d.ts} +13 -0
- package/package.json +1 -1
- package/src/builder.ts +12 -0
- package/src/layout/head-label.ts +156 -0
- package/src/presets.ts +7 -2
- package/src/render/edges.tsx +41 -0
- package/src/render/stage.tsx +15 -1
- package/src/types.ts +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ CDL (Chainome Diagram Language) の主要変更履歴。
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.52.0] - 2026-09-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **クラス図の関係の出どころ側の端にも多重度を出せるようにした** (#825)
|
|
13
|
+
|
|
14
|
+
UML は関係の両端に多重度を書く (例 = 管理者 `1` が注文 `1..*` を持つ)。 組み立て器は多重度を
|
|
15
|
+
1 つ (`cardinality` = 行き先の端) しか受け取れず、出どころの端の数を書く口が無かった。
|
|
16
|
+
|
|
17
|
+
クラス図の組み立て器に `tailCardinality` を足した。 線に「出どころの端に添える字」 の欄 `tailLabel` を
|
|
18
|
+
足し (`headLabel` と対)、置き場所は行き先の端と同じ計算で決める。 出どころの端での向きは、線の
|
|
19
|
+
最初の区間を逆にたどって取る (曲線なら始点の接線)。
|
|
20
|
+
|
|
21
|
+
## [0.51.0] - 2026-09-11
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **クラス図の多重度を、線の中ほどの札から行き先の端へ移した** (#821)
|
|
26
|
+
|
|
27
|
+
クラス図の関係に書いた多重度 (`cardinality: "1..*"`) は、札の語の下の行 (`sub`) に入っていた。
|
|
28
|
+
語と続けて読まれ (英字の頃は `HAS` と `1..*` が「HAS1」)、 どちらの端の数かも読めなかった。
|
|
29
|
+
UML と同じく、行き先の端の近くへ等幅の字で添える。
|
|
30
|
+
|
|
31
|
+
置き場所は線の最後の区間から決まる。 端から 22 world 戻った点の、札と反対の側に置く
|
|
32
|
+
(札を持たない線は、横向きなら下、縦向きなら左)。 札と同じ側に置くと、見本帳のクラス図で
|
|
33
|
+
1 本が札と重なり、もう 1 本が札と 2 world まで寄った。
|
|
34
|
+
|
|
35
|
+
線に「行き先の端に添える字」 の欄 `headLabel` を足した。 クラス図の組み立て器は多重度を
|
|
36
|
+
`sub` ではなく `headLabel` に渡す。 ER 図の多重度の出し方は変えない (端の印で示す)。
|
|
37
|
+
|
|
8
38
|
## [0.50.0] - 2026-09-11
|
|
9
39
|
|
|
10
40
|
### Fixed
|
|
@@ -2418,7 +2448,9 @@ Initial OSS release.
|
|
|
2418
2448
|
使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
|
|
2419
2449
|
行き止まりになる。
|
|
2420
2450
|
|
|
2421
|
-
[Unreleased]: https://github.com/cardene777/cdl/compare/v0.
|
|
2451
|
+
[Unreleased]: https://github.com/cardene777/cdl/compare/v0.52.0...HEAD
|
|
2452
|
+
[0.52.0]: https://github.com/cardene777/cdl/compare/v0.51.0...v0.52.0
|
|
2453
|
+
[0.51.0]: https://github.com/cardene777/cdl/compare/v0.50.0...v0.51.0
|
|
2422
2454
|
[0.50.0]: https://github.com/cardene777/cdl/compare/v0.49.0...v0.50.0
|
|
2423
2455
|
[0.49.0]: https://github.com/cardene777/cdl/compare/v0.48.0...v0.49.0
|
|
2424
2456
|
[0.48.0]: https://github.com/cardene777/cdl/compare/v0.47.0...v0.48.0
|
package/dist/index.cjs
CHANGED
|
@@ -9501,6 +9501,8 @@ function diagram(id, options) {
|
|
|
9501
9501
|
tailHeadFill: opts.tailHeadFill,
|
|
9502
9502
|
guard: opts.guard,
|
|
9503
9503
|
cardinality: opts.cardinality,
|
|
9504
|
+
headLabel: opts.headLabel,
|
|
9505
|
+
tailLabel: opts.tailLabel,
|
|
9504
9506
|
labelOffsetX: opts.labelOffsetX,
|
|
9505
9507
|
labelOffsetY: opts.labelOffsetY,
|
|
9506
9508
|
routing: opts.routing,
|
|
@@ -9627,6 +9629,8 @@ function diagram(id, options) {
|
|
|
9627
9629
|
tailHeadFill: d.tailHeadFill,
|
|
9628
9630
|
guard: d.guard,
|
|
9629
9631
|
cardinality: d.cardinality,
|
|
9632
|
+
headLabel: d.headLabel,
|
|
9633
|
+
tailLabel: d.tailLabel,
|
|
9630
9634
|
labelOffsetX: d.labelOffsetX,
|
|
9631
9635
|
labelOffsetY: d.labelOffsetY,
|
|
9632
9636
|
routing: d.routing,
|
|
@@ -14105,10 +14109,10 @@ function \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text) {
|
|
|
14105
14109
|
if (typeof \u533A\u5207\u308A !== "function") return [...text];
|
|
14106
14110
|
return [...new \u533A\u5207\u308A(void 0, { granularity: "grapheme" }).segment(text)].map((g) => g.segment);
|
|
14107
14111
|
}
|
|
14108
|
-
function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\
|
|
14112
|
+
function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u30553) {
|
|
14109
14113
|
const \u5019\u88DC = \u884C.filter((r, i) => i === 0 || r.text.trim() !== "");
|
|
14110
14114
|
if (\u5019\u88DC.length === 0) return [];
|
|
14111
|
-
const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\
|
|
14115
|
+
const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u30553 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
|
|
14112
14116
|
const \u9AD8\u3055 = (rs) => rs.reduce((a, r) => a + r.fontSize * \u884C\u9001\u308A\u306E\u6BD4, 0);
|
|
14113
14117
|
const \u6B8B\u3059 = [...\u5019\u88DC];
|
|
14114
14118
|
while (\u6B8B\u3059.length > 1 && \u9AD8\u3055(\u6B8B\u3059) > \u4F7F\u3048\u308B\u9AD8\u3055) \u6B8B\u3059.pop();
|
|
@@ -14835,7 +14839,7 @@ function \u30D9\u30B8\u30A8\u306E\u7D2F\u7A4D\u5272\u5408(\u70B9, \u5236\u5FA1\u
|
|
|
14835
14839
|
function \u7BB1\u306E\u6587\u5B57({
|
|
14836
14840
|
\u884C,
|
|
14837
14841
|
x,
|
|
14838
|
-
\u7BB1\u306E\u9AD8\u3055: \u7BB1\u306E\u9AD8\
|
|
14842
|
+
\u7BB1\u306E\u9AD8\u3055: \u7BB1\u306E\u9AD8\u30553,
|
|
14839
14843
|
fill,
|
|
14840
14844
|
\u540D\u524D\u306E\u592A\u3055
|
|
14841
14845
|
}) {
|
|
@@ -14844,7 +14848,7 @@ function \u7BB1\u306E\u6587\u5B57({
|
|
|
14844
14848
|
{
|
|
14845
14849
|
"data-cdl-role": r.\u5F79\u5272 === "subtitle" ? "tree-node-subtitle" : void 0,
|
|
14846
14850
|
x,
|
|
14847
|
-
y: \u7BB1\u306E\u9AD8\
|
|
14851
|
+
y: \u7BB1\u306E\u9AD8\u30553 / 2 + r.dy,
|
|
14848
14852
|
fontSize: r.fontSize,
|
|
14849
14853
|
fontWeight: r.\u5F79\u5272 === "title" ? \u540D\u524D\u306E\u592A\u3055 : 500,
|
|
14850
14854
|
textAnchor: "middle",
|
|
@@ -22931,6 +22935,79 @@ function \u7B49\u5E45\u306E\u5B57(text, fontSize) {
|
|
|
22931
22935
|
});
|
|
22932
22936
|
return out;
|
|
22933
22937
|
}
|
|
22938
|
+
|
|
22939
|
+
// src/layout/head-label.ts
|
|
22940
|
+
var \u7AEF\u306E\u5B57\u3092\u623B\u3059\u8DDD\u96E2 = 22;
|
|
22941
|
+
var \u7AEF\u306E\u5B57\u3068\u7DDA\u306E\u9699\u9593 = 8;
|
|
22942
|
+
var \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055 = EDGE_LABEL_TEXT.sub.fontSize;
|
|
22943
|
+
var \u7BB1\u306E\u9AD8\u30552 = Math.round(\u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055 * 1.2);
|
|
22944
|
+
var BASELINE_RATIO = 0.8;
|
|
22945
|
+
function \u5411\u304D\u3092\u53D6\u308B(end, \u5019\u88DC) {
|
|
22946
|
+
for (const p of \u5019\u88DC) {
|
|
22947
|
+
if (!p) continue;
|
|
22948
|
+
const dx = end.x - p.x;
|
|
22949
|
+
const dy = end.y - p.y;
|
|
22950
|
+
const len = Math.hypot(dx, dy);
|
|
22951
|
+
if (len > 1e-6) return { end, ux: dx / len, uy: dy / len };
|
|
22952
|
+
}
|
|
22953
|
+
return null;
|
|
22954
|
+
}
|
|
22955
|
+
function \u7AEF\u3067\u306E\u5411\u304D(d, \u7AEF) {
|
|
22956
|
+
const segs = extractPathSegments(d);
|
|
22957
|
+
if (segs.length === 0) return null;
|
|
22958
|
+
if (\u7AEF === "head") {
|
|
22959
|
+
const last = segs[segs.length - 1];
|
|
22960
|
+
const end2 = { x: last.x2, y: last.y2 };
|
|
22961
|
+
const \u5019\u88DC2 = segs.slice().reverse().flatMap((s) => [s.cmd === "Q" ? s.ctrl?.[0] : s.cmd === "C" ? s.ctrl?.[1] : void 0, { x: s.x1, y: s.y1 }]);
|
|
22962
|
+
return \u5411\u304D\u3092\u53D6\u308B(end2, \u5019\u88DC2);
|
|
22963
|
+
}
|
|
22964
|
+
const first = segs[0];
|
|
22965
|
+
const end = { x: first.x1, y: first.y1 };
|
|
22966
|
+
const \u5019\u88DC = segs.flatMap((s) => [...s.ctrl ?? [], { x: s.x2, y: s.y2 }]);
|
|
22967
|
+
return \u5411\u304D\u3092\u53D6\u308B(end, \u5019\u88DC);
|
|
22968
|
+
}
|
|
22969
|
+
function \u7AEF\u306E\u5B57\u3092\u7F6E\u304F(edge, \u7AEF = "head") {
|
|
22970
|
+
const text = (\u7AEF === "head" ? edge.headLabel : edge.tailLabel)?.trim();
|
|
22971
|
+
if (!text) return null;
|
|
22972
|
+
const \u5411\u304D = \u7AEF\u3067\u306E\u5411\u304D(edge.d, \u7AEF);
|
|
22973
|
+
if (!\u5411\u304D) return null;
|
|
22974
|
+
const { end, ux, uy } = \u5411\u304D;
|
|
22975
|
+
const bx = end.x - ux * \u7AEF\u306E\u5B57\u3092\u623B\u3059\u8DDD\u96E2;
|
|
22976
|
+
const by = end.y - uy * \u7AEF\u306E\u5B57\u3092\u623B\u3059\u8DDD\u96E2;
|
|
22977
|
+
const w = measureTextWidth(text, {
|
|
22978
|
+
fontSize: \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055,
|
|
22979
|
+
fontWeight: EDGE_LABEL_TEXT.sub.fontWeight,
|
|
22980
|
+
fontFamily: "mono"
|
|
22981
|
+
});
|
|
22982
|
+
const h = \u7BB1\u306E\u9AD8\u30552;
|
|
22983
|
+
const \u672D = hasRenderedLabel(edge) && edge.labelX !== void 0 && edge.labelY !== void 0 ? { x: edge.labelX, y: edge.labelY } : null;
|
|
22984
|
+
let anchor;
|
|
22985
|
+
let box;
|
|
22986
|
+
if (Math.abs(ux) >= Math.abs(uy)) {
|
|
22987
|
+
const \u53F3\u3078\u9032\u3080 = ux > 0;
|
|
22988
|
+
const \u4E0A\u306B\u7F6E\u304F = \u672D !== null && \u672D.y > by;
|
|
22989
|
+
anchor = \u53F3\u3078\u9032\u3080 ? "end" : "start";
|
|
22990
|
+
box = {
|
|
22991
|
+
x: \u53F3\u3078\u9032\u3080 ? bx - w : bx,
|
|
22992
|
+
y: \u4E0A\u306B\u7F6E\u304F ? by - \u7AEF\u306E\u5B57\u3068\u7DDA\u306E\u9699\u9593 - h : by + \u7AEF\u306E\u5B57\u3068\u7DDA\u306E\u9699\u9593,
|
|
22993
|
+
w,
|
|
22994
|
+
h
|
|
22995
|
+
};
|
|
22996
|
+
} else {
|
|
22997
|
+
const \u4E0B\u3078\u9032\u3080 = uy > 0;
|
|
22998
|
+
const \u53F3\u306B\u7F6E\u304F = \u672D !== null && \u672D.x < bx;
|
|
22999
|
+
anchor = \u53F3\u306B\u7F6E\u304F ? "start" : "end";
|
|
23000
|
+
box = {
|
|
23001
|
+
x: \u53F3\u306B\u7F6E\u304F ? bx + \u7AEF\u306E\u5B57\u3068\u7DDA\u306E\u9699\u9593 : bx - \u7AEF\u306E\u5B57\u3068\u7DDA\u306E\u9699\u9593 - w,
|
|
23002
|
+
y: \u4E0B\u3078\u9032\u3080 ? by - h : by,
|
|
23003
|
+
w,
|
|
23004
|
+
h
|
|
23005
|
+
};
|
|
23006
|
+
}
|
|
23007
|
+
const x = anchor === "start" ? box.x : box.x + box.w;
|
|
23008
|
+
const y = box.y + (h - \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055) / 2 + \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055 * BASELINE_RATIO;
|
|
23009
|
+
return { x, y, anchor, box };
|
|
23010
|
+
}
|
|
22934
23011
|
function defaultEdgeWidth(active) {
|
|
22935
23012
|
return active ? 2.5 : 1.25;
|
|
22936
23013
|
}
|
|
@@ -23193,6 +23270,35 @@ function CdlEdgeLabelView({
|
|
|
23193
23270
|
}
|
|
23194
23271
|
);
|
|
23195
23272
|
}
|
|
23273
|
+
function CdlEdgeEndLabelView({
|
|
23274
|
+
edge,
|
|
23275
|
+
active,
|
|
23276
|
+
\u7AEF
|
|
23277
|
+
}) {
|
|
23278
|
+
const \u7F6E\u304D\u5834\u6240 = \u7AEF\u306E\u5B57\u3092\u7F6E\u304F(edge, \u7AEF);
|
|
23279
|
+
if (!\u7F6E\u304D\u5834\u6240) return null;
|
|
23280
|
+
const color = edgeColor(edge);
|
|
23281
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
23282
|
+
"text",
|
|
23283
|
+
{
|
|
23284
|
+
"data-cdl-role": "edge-end-label",
|
|
23285
|
+
"data-cdl-edge-end-label-for": edge.id,
|
|
23286
|
+
"data-cdl-edge-end": \u7AEF,
|
|
23287
|
+
x: \u7F6E\u304D\u5834\u6240.x,
|
|
23288
|
+
y: \u7F6E\u304D\u5834\u6240.y,
|
|
23289
|
+
fontSize: \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055,
|
|
23290
|
+
fontWeight: EDGE_LABEL_TEXT.sub.fontWeight,
|
|
23291
|
+
textAnchor: \u7F6E\u304D\u5834\u6240.anchor,
|
|
23292
|
+
fill: active ? color : "var(--cdl-text-dim, #5a6270)",
|
|
23293
|
+
stroke: "var(--cdl-label-bg, #ffffff)",
|
|
23294
|
+
strokeWidth: 4,
|
|
23295
|
+
strokeLinejoin: "round",
|
|
23296
|
+
paintOrder: "stroke",
|
|
23297
|
+
style: { fontFamily: fontFamilyAttr("sub") },
|
|
23298
|
+
children: \u7B49\u5E45\u306E\u5B57(\u7AEF === "head" ? edge.headLabel : edge.tailLabel, \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055)
|
|
23299
|
+
}
|
|
23300
|
+
);
|
|
23301
|
+
}
|
|
23196
23302
|
|
|
23197
23303
|
// src/kinds/node-tone.ts
|
|
23198
23304
|
function nodeAccent(node, fallback) {
|
|
@@ -31477,6 +31583,17 @@ function CdlStage({
|
|
|
31477
31583
|
},
|
|
31478
31584
|
`label-${edge.id}`
|
|
31479
31585
|
)),
|
|
31586
|
+
laid.edges.filter((edge) => (edge.headLabel || edge.tailLabel) && \u77E2\u5370\u306E\u51FA\u756A.\u51FA\u308B\u304B(edge.id)).flatMap(
|
|
31587
|
+
(edge) => ["head", "tail"].map((\u7AEF) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
31588
|
+
CdlEdgeEndLabelView,
|
|
31589
|
+
{
|
|
31590
|
+
edge,
|
|
31591
|
+
active: activeSet.has(edge.id),
|
|
31592
|
+
\u7AEF
|
|
31593
|
+
},
|
|
31594
|
+
`${\u7AEF}-label-${edge.id}`
|
|
31595
|
+
))
|
|
31596
|
+
),
|
|
31480
31597
|
debug && /* @__PURE__ */ jsxRuntime.jsxs("g", { pointerEvents: "none", children: [
|
|
31481
31598
|
laid.bboxes.map((bbox, idx) => {
|
|
31482
31599
|
const color = bbox.kind === "node" ? "#3b82f6" : bbox.kind === "lane-label" ? "#a855f7" : bbox.kind === "edge-label" ? "#10b981" : "#f59e0b";
|
|
@@ -32521,7 +32638,10 @@ function classDiagram(preset) {
|
|
|
32521
32638
|
b.edge(r.from, r.to, {
|
|
32522
32639
|
id: edgeId,
|
|
32523
32640
|
label: r.label ?? r.type,
|
|
32524
|
-
|
|
32641
|
+
// 多重度は行き先の端に添える (#821)。 札の下の行に入れると語と続けて読まれ
|
|
32642
|
+
// (英字の頃は「HAS 1..*」 が「HAS1」)、 どちらの端の数かも読めない
|
|
32643
|
+
...r.cardinality ? { headLabel: r.cardinality } : {},
|
|
32644
|
+
...r.tailCardinality ? { tailLabel: r.tailCardinality } : {},
|
|
32525
32645
|
tone: r.tone ?? \u56F3\u306E\u65E2\u5B9A ?? CLASS_RELATION_TONE[r.type],
|
|
32526
32646
|
// 関係の種類から線と端の形を決める (cdl#574 / #578)。 書いた値が勝つ
|
|
32527
32647
|
style: r.style ?? \u898B\u305F\u76EE.style,
|