@cardenelabs/cdl 0.45.0 → 0.47.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 +58 -1
- package/dist/index.cjs +83 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +81 -7
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +79 -6
- 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 +79 -6
- package/dist/react.js.map +1 -1
- package/dist/{render-UGswDfAh.d.cts → render-C53-PeJZ.d.cts} +25 -1
- package/dist/{render-UGswDfAh.d.ts → render-C53-PeJZ.d.ts} +25 -1
- package/package.json +1 -1
- package/src/index.ts +6 -0
- package/src/layout/edges.ts +27 -2
- package/src/layout.ts +1 -0
- package/src/render/edges.tsx +19 -0
- package/src/render/nodes.tsx +40 -1
- package/src/render/relation-focus.ts +40 -0
- package/src/render/stage.tsx +55 -2
- package/src/types.ts +27 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,61 @@ CDL (Chainome Diagram Language) の主要変更履歴。
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.47.0] - 2026-09-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **箱に触れると関係する線だけが光るようにした** (#806)
|
|
13
|
+
|
|
14
|
+
クラス図と ER 図は **順番を持たない**。 段を進めて線を 1 本ずつ引く見せ方は作り手が決めた
|
|
15
|
+
読ませ方でしかなく、読み手の問い (この箱はどこと繋がっているか) には答えていなかった。
|
|
16
|
+
|
|
17
|
+
`CdlDiagram.relationFocus` に `"hover"` を書くと、箱に触れた時に その箱 ・ 繋がる線 ・
|
|
18
|
+
相手の箱だけが光り、他が沈む。 押すと留まり、もう一度押すか `Esc` で外れる
|
|
19
|
+
(線を目で追う間に指が外れると読めないため)。
|
|
20
|
+
|
|
21
|
+
| 書いた値 | 触れた時 |
|
|
22
|
+
|---|---|
|
|
23
|
+
| 書かない / `"off"` | 何もしない (既定) |
|
|
24
|
+
| `"hover"` | 関係する箱と線だけが光り、繋がる線に粒が流れる |
|
|
25
|
+
|
|
26
|
+
光る集合は「触れた箱」「繋がる線」「線の相手の箱」 の 3 つで、**線の向きは問わない** =
|
|
27
|
+
クラス図の「継ぐ」 は子から親へ、 ER の「持つ」 は親から子へ向くが、読み手にとっては
|
|
28
|
+
どちらも「この箱の関係」 だから。 集合は `activate` と同じ所に入れるので、光る / 沈むの
|
|
29
|
+
見え方は既にある仕組みをそのまま使う。
|
|
30
|
+
|
|
31
|
+
**触れていない間は段が勝つ** = この指定を足しても、段を持つ図の見え方は変わらない。
|
|
32
|
+
指定を書かない図では箱に属性も受け口も付かないので、`tab` の順番も DOM も動かない。
|
|
33
|
+
|
|
34
|
+
`prefers-reduced-motion` が立っている時は粒を流さない。 光る側は控えない =
|
|
35
|
+
動きではなく見分けなので、控える指定とは別の軸。
|
|
36
|
+
|
|
37
|
+
箱は `role="button"` と `tabIndex` を持ち、`Enter` と `Space` でも留められる。
|
|
38
|
+
|
|
39
|
+
## [0.46.0] - 2026-09-11
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **上向きに曲がる線の角に突起が出るのを直した** (#801)
|
|
44
|
+
|
|
45
|
+
縦の対の辺 (`fromSide` と `toSide` が上下) は、角を「手前 14 で直線を止め、弧で 14 先へ
|
|
46
|
+
抜ける」 形で丸める。 その手前と先を上下に固定していたため、**相手が上にある辺**
|
|
47
|
+
(`fromSide === "top"`) では直線が角を 14 通り過ぎ、弧が戻る形になっていた。
|
|
48
|
+
戻りが画面上の突起として見える。
|
|
49
|
+
|
|
50
|
+
見本帳 `class-complex-demo` の実物で並べると差が読める。
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
正しい (下向き) 壊れていた (上向き)
|
|
54
|
+
L 903 1244 <- 角の 14 手前 L 1613 1244 <- 角を 14 通り過ぎている
|
|
55
|
+
Q 903 1258, 917 1258 Q 1613 1258, 1627 1258
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
角の丸めを **進む向き** から決めるようにした。 同じ誤りは `CAR-482` が別の分岐で
|
|
59
|
+
1 度直しており、本件はその時に見落とされた 2 つ目の分岐。
|
|
60
|
+
|
|
61
|
+
下向きの辺 (`fromSide === "bottom"`) の `d` は 1 文字も変わらない。
|
|
62
|
+
|
|
8
63
|
## [0.45.0] - 2026-09-11
|
|
9
64
|
|
|
10
65
|
### Added
|
|
@@ -2296,7 +2351,9 @@ Initial OSS release.
|
|
|
2296
2351
|
使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
|
|
2297
2352
|
行き止まりになる。
|
|
2298
2353
|
|
|
2299
|
-
[Unreleased]: https://github.com/cardene777/cdl/compare/v0.
|
|
2354
|
+
[Unreleased]: https://github.com/cardene777/cdl/compare/v0.47.0...HEAD
|
|
2355
|
+
[0.47.0]: https://github.com/cardene777/cdl/compare/v0.46.0...v0.47.0
|
|
2356
|
+
[0.46.0]: https://github.com/cardene777/cdl/compare/v0.45.0...v0.46.0
|
|
2300
2357
|
[0.45.0]: https://github.com/cardene777/cdl/compare/v0.44.0...v0.45.0
|
|
2301
2358
|
[0.44.0]: https://github.com/cardene777/cdl/compare/v0.43.0...v0.44.0
|
|
2302
2359
|
[0.43.0]: https://github.com/cardene777/cdl/compare/v0.42.0...v0.43.0
|
package/dist/index.cjs
CHANGED
|
@@ -13751,6 +13751,8 @@ var EDGE_HEADS = [
|
|
|
13751
13751
|
var EDGE_HEAD_FILL_DEFAULT = "solid";
|
|
13752
13752
|
var EDGE_HEAD_FILLS = ["solid", "hollow"];
|
|
13753
13753
|
var EDGE_REVEALS = ["phase", "all"];
|
|
13754
|
+
var RELATION_FOCUSES = ["off", "hover"];
|
|
13755
|
+
var RELATION_FOCUS_DEFAULT = "off";
|
|
13754
13756
|
var EDGE_REVEAL_DEFAULT = "phase";
|
|
13755
13757
|
|
|
13756
13758
|
// src/kinds/text-width.ts
|
|
@@ -18182,6 +18184,9 @@ var LANE_PAD_MIN = 25;
|
|
|
18182
18184
|
// src/layout/edges.ts
|
|
18183
18185
|
var VERTICAL_DETOUR_GAP = 50;
|
|
18184
18186
|
var VERTICAL_DETOUR_CORNER = 14;
|
|
18187
|
+
function verticalCornerDir(from, to) {
|
|
18188
|
+
return to < from ? -1 : 1;
|
|
18189
|
+
}
|
|
18185
18190
|
var VERTICAL_DETOUR_EXIT = 45;
|
|
18186
18191
|
function nearestBoxDistance(anchorX, dir, verticalTop, verticalBottom, boxes) {
|
|
18187
18192
|
let nearest = Infinity;
|
|
@@ -19363,12 +19368,14 @@ function routePath(from, to, fromSide, toSide, obstacles = [], detourSide, _from
|
|
|
19363
19368
|
midY2 = retreatBelowMidBlockers(midY2);
|
|
19364
19369
|
const corner = 14;
|
|
19365
19370
|
const labelY = midY2 - labelInit;
|
|
19371
|
+
const \u7E26\u306E\u5411\u304DA = verticalCornerDir(A.y, midY2);
|
|
19372
|
+
const \u7E26\u306E\u5411\u304DB = verticalCornerDir(midY2, B.y);
|
|
19366
19373
|
return {
|
|
19367
19374
|
d: `M ${A.x} ${A.y}
|
|
19368
|
-
L ${A.x} ${midY2 - corner}
|
|
19375
|
+
L ${A.x} ${midY2 - \u7E26\u306E\u5411\u304DA * corner}
|
|
19369
19376
|
Q ${A.x} ${midY2}, ${A.x + xDir * corner} ${midY2}
|
|
19370
19377
|
L ${B.x - xDir * corner} ${midY2}
|
|
19371
|
-
Q ${B.x} ${midY2}, ${B.x} ${midY2 + corner}
|
|
19378
|
+
Q ${B.x} ${midY2}, ${B.x} ${midY2 + \u7E26\u306E\u5411\u304DB * corner}
|
|
19372
19379
|
L ${B.x} ${B.y}`,
|
|
19373
19380
|
labelX: (A.x + B.x) / 2,
|
|
19374
19381
|
labelY,
|
|
@@ -20717,6 +20724,7 @@ function layout(diag) {
|
|
|
20717
20724
|
...diag.derived ? { derived: diag.derived } : {},
|
|
20718
20725
|
// 矢印をいつ出すか (#582)。 描き手が読む欄なので、そのまま持ち越す
|
|
20719
20726
|
...diag.edgeReveal ? { edgeReveal: diag.edgeReveal } : {},
|
|
20727
|
+
...diag.relationFocus ? { relationFocus: diag.relationFocus } : {},
|
|
20720
20728
|
// どの配色で描くか (#1553)。 空文字は書かなかった扱いにする = 空の目印を出すと、
|
|
20721
20729
|
// 消費側の `[data-cdl-palette]` が配色を書いていない図にも当たる。
|
|
20722
20730
|
//
|
|
@@ -22804,7 +22812,8 @@ function CdlEdgeView({
|
|
|
22804
22812
|
active,
|
|
22805
22813
|
drawing,
|
|
22806
22814
|
progress,
|
|
22807
|
-
stateValues
|
|
22815
|
+
stateValues,
|
|
22816
|
+
flowing = false
|
|
22808
22817
|
}) {
|
|
22809
22818
|
const color = edgeColor(edge);
|
|
22810
22819
|
const marker = edgeHeadMarkerName(edge.tone, edge.head, !active, edge.headFill);
|
|
@@ -22822,6 +22831,7 @@ function CdlEdgeView({
|
|
|
22822
22831
|
"data-cdl-from": edge.from,
|
|
22823
22832
|
"data-cdl-to": edge.to,
|
|
22824
22833
|
"data-cdl-active": active ? "true" : "false",
|
|
22834
|
+
"data-cdl-flowing": flowing ? "true" : "false",
|
|
22825
22835
|
"data-cdl-drawing": drawing ? "true" : "false",
|
|
22826
22836
|
"data-cdl-path-d": edge.d,
|
|
22827
22837
|
"data-cdl-label-x": edge.labelX,
|
|
@@ -22874,7 +22884,11 @@ function CdlEdgeView({
|
|
|
22874
22884
|
strokeWidth: 14,
|
|
22875
22885
|
strokeLinecap: "round"
|
|
22876
22886
|
}
|
|
22877
|
-
)
|
|
22887
|
+
),
|
|
22888
|
+
flowing && !isDotted && /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-cdl-role": "edge-flow", children: [
|
|
22889
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { id: glowPathId, d: edge.d, fill: "none", stroke: "none" }),
|
|
22890
|
+
/* @__PURE__ */ jsxRuntime.jsx(EdgeGlowCircles, { color, edgeId: edge.id })
|
|
22891
|
+
] })
|
|
22878
22892
|
]
|
|
22879
22893
|
}
|
|
22880
22894
|
);
|
|
@@ -30650,7 +30664,8 @@ function CdlNodeView({
|
|
|
30650
30664
|
progress,
|
|
30651
30665
|
stateValues,
|
|
30652
30666
|
currentPhaseId,
|
|
30653
|
-
chartLineScale
|
|
30667
|
+
chartLineScale,
|
|
30668
|
+
\u95A2\u4FC2\u306E\u53D7\u3051\u53E3
|
|
30654
30669
|
}) {
|
|
30655
30670
|
const value = node.value ? interpolate(node.value, stateValues) : void 0;
|
|
30656
30671
|
const rows = (node.rows ?? []).map((r) => interpolate(r, stateValues));
|
|
@@ -30972,6 +30987,23 @@ function CdlNodeView({
|
|
|
30972
30987
|
"data-cdl-eyebrow": resolvedNode.eyebrow ?? "",
|
|
30973
30988
|
"data-cdl-offset-x": offsetX || void 0,
|
|
30974
30989
|
"data-cdl-offset-y": offsetY || void 0,
|
|
30990
|
+
...\u95A2\u4FC2\u306E\u53D7\u3051\u53E3 === void 0 ? {} : {
|
|
30991
|
+
// 読み上げに「押せる」 ことを伝え、 tab でも辿れるようにする。
|
|
30992
|
+
role: "button",
|
|
30993
|
+
tabIndex: 0,
|
|
30994
|
+
"aria-pressed": \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u7126\u70B9 === node.id,
|
|
30995
|
+
style: { cursor: "pointer" },
|
|
30996
|
+
onPointerEnter: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u89E6\u308C\u305F(node.id),
|
|
30997
|
+
onPointerLeave: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u96E2\u308C\u305F(),
|
|
30998
|
+
onFocus: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u89E6\u308C\u305F(node.id),
|
|
30999
|
+
onBlur: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u96E2\u308C\u305F(),
|
|
31000
|
+
onClick: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u62BC\u3057\u305F(node.id),
|
|
31001
|
+
onKeyDown: (e) => {
|
|
31002
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
31003
|
+
e.preventDefault();
|
|
31004
|
+
\u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u62BC\u3057\u305F(node.id);
|
|
31005
|
+
}
|
|
31006
|
+
},
|
|
30975
31007
|
transform: hasOffset ? `translate(${offsetX}, ${offsetY})` : void 0,
|
|
30976
31008
|
opacity: boundOpacity,
|
|
30977
31009
|
"data-cdl-tone": node.tone,
|
|
@@ -30995,6 +31027,18 @@ function CdlNodeView({
|
|
|
30995
31027
|
}
|
|
30996
31028
|
);
|
|
30997
31029
|
}
|
|
31030
|
+
|
|
31031
|
+
// src/render/relation-focus.ts
|
|
31032
|
+
function relatedFocusSet(edges, nodeId) {
|
|
31033
|
+
const \u96C6\u5408 = /* @__PURE__ */ new Set([nodeId]);
|
|
31034
|
+
for (const e of edges) {
|
|
31035
|
+
if (e.from !== nodeId && e.to !== nodeId) continue;
|
|
31036
|
+
\u96C6\u5408.add(e.id);
|
|
31037
|
+
\u96C6\u5408.add(e.from);
|
|
31038
|
+
\u96C6\u5408.add(e.to);
|
|
31039
|
+
}
|
|
31040
|
+
return \u96C6\u5408;
|
|
31041
|
+
}
|
|
30998
31042
|
function CdlStage({
|
|
30999
31043
|
laid,
|
|
31000
31044
|
currentPhase,
|
|
@@ -31005,7 +31049,35 @@ function CdlStage({
|
|
|
31005
31049
|
compact = false,
|
|
31006
31050
|
svgRef
|
|
31007
31051
|
}) {
|
|
31008
|
-
const
|
|
31052
|
+
const [\u7126\u70B9, set\u7126\u70B9] = react.useState(null);
|
|
31053
|
+
const \u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B = (laid.relationFocus ?? RELATION_FOCUS_DEFAULT) === "hover";
|
|
31054
|
+
const \u52D5\u304D\u3092\u63A7\u3048\u308B = useReducedMotion();
|
|
31055
|
+
react.useEffect(() => {
|
|
31056
|
+
if (!\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B) set\u7126\u70B9(null);
|
|
31057
|
+
}, [\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B]);
|
|
31058
|
+
react.useEffect(() => {
|
|
31059
|
+
if (!\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B || \u7126\u70B9?.\u7559\u3081\u305F !== true) return;
|
|
31060
|
+
const \u62BC\u3057\u305F2 = (e) => {
|
|
31061
|
+
if (e.key === "Escape") set\u7126\u70B9(null);
|
|
31062
|
+
};
|
|
31063
|
+
window.addEventListener("keydown", \u62BC\u3057\u305F2);
|
|
31064
|
+
return () => window.removeEventListener("keydown", \u62BC\u3057\u305F2);
|
|
31065
|
+
}, [\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B, \u7126\u70B9?.\u7559\u3081\u305F]);
|
|
31066
|
+
const \u89E6\u308C\u305F = react.useCallback((id) => {
|
|
31067
|
+
set\u7126\u70B9((\u524D) => \u524D?.\u7559\u3081\u305F === true ? \u524D : { id, \u7559\u3081\u305F: false });
|
|
31068
|
+
}, []);
|
|
31069
|
+
const \u96E2\u308C\u305F = react.useCallback(() => {
|
|
31070
|
+
set\u7126\u70B9((\u524D) => \u524D?.\u7559\u3081\u305F === true ? \u524D : null);
|
|
31071
|
+
}, []);
|
|
31072
|
+
const \u62BC\u3057\u305F = react.useCallback((id) => {
|
|
31073
|
+
set\u7126\u70B9((\u524D) => \u524D?.id === id && \u524D.\u7559\u3081\u305F ? null : { id, \u7559\u3081\u305F: true });
|
|
31074
|
+
}, []);
|
|
31075
|
+
const \u7126\u70B9\u306E\u96C6\u5408 = react.useMemo(
|
|
31076
|
+
() => \u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B && \u7126\u70B9 !== null ? relatedFocusSet(laid.edges, \u7126\u70B9.id) : null,
|
|
31077
|
+
[\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B, \u7126\u70B9, laid.edges]
|
|
31078
|
+
);
|
|
31079
|
+
const activeSet = \u7126\u70B9\u306E\u96C6\u5408 ?? new Set(currentPhase?.activate ?? []);
|
|
31080
|
+
const \u7BB1\u306E\u53D7\u3051\u53E3 = \u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B ? { \u89E6\u308C\u305F, \u96E2\u308C\u305F, \u62BC\u3057\u305F, \u7126\u70B9: \u7126\u70B9?.id ?? null } : void 0;
|
|
31009
31081
|
const \u77E2\u5370\u306E\u51FA\u756A = react.useMemo(() => {
|
|
31010
31082
|
const \u521D\u51FA = /* @__PURE__ */ new Map();
|
|
31011
31083
|
laid.phases.forEach((p, i) => {
|
|
@@ -31236,6 +31308,7 @@ function CdlStage({
|
|
|
31236
31308
|
{
|
|
31237
31309
|
edge,
|
|
31238
31310
|
active: activeSet.has(edge.id),
|
|
31311
|
+
flowing: \u7126\u70B9\u306E\u96C6\u5408?.has(edge.id) === true && !\u52D5\u304D\u3092\u63A7\u3048\u308B,
|
|
31239
31312
|
drawing: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id),
|
|
31240
31313
|
progress: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id) ? \u63CF\u304F\u9032\u307F : progress,
|
|
31241
31314
|
stateValues
|
|
@@ -31249,6 +31322,7 @@ function CdlStage({
|
|
|
31249
31322
|
{
|
|
31250
31323
|
node,
|
|
31251
31324
|
active: activeSet.has(node.id),
|
|
31325
|
+
\u95A2\u4FC2\u306E\u53D7\u3051\u53E3: \u7BB1\u306E\u53D7\u3051\u53E3,
|
|
31252
31326
|
drawing: \u63CF\u304F,
|
|
31253
31327
|
progress: \u63CF\u304F ? \u63CF\u304F\u9032\u307F : progress,
|
|
31254
31328
|
stateValues,
|
|
@@ -32876,6 +32950,8 @@ exports.NEAR_COLLISION_DEFAULT_MIN = NEAR_COLLISION_DEFAULT_MIN;
|
|
|
32876
32950
|
exports.NEAR_COLLISION_POLICY = NEAR_COLLISION_POLICY;
|
|
32877
32951
|
exports.NODE_FRAME_SELECTOR = NODE_FRAME_SELECTOR;
|
|
32878
32952
|
exports.NODE_KINDS = NODE_KINDS;
|
|
32953
|
+
exports.RELATION_FOCUSES = RELATION_FOCUSES;
|
|
32954
|
+
exports.RELATION_FOCUS_DEFAULT = RELATION_FOCUS_DEFAULT;
|
|
32879
32955
|
exports.ROW_GAP_VARIANCE_TOL = ROW_GAP_VARIANCE_TOL;
|
|
32880
32956
|
exports.SEQUENCE_MESSAGE_LOOK = SEQUENCE_MESSAGE_LOOK;
|
|
32881
32957
|
exports.SPEC_CLEARANCE_POLICY = SPEC_CLEARANCE_POLICY;
|
|
@@ -32941,6 +33017,7 @@ exports.pxToWorld = pxToWorld;
|
|
|
32941
33017
|
exports.quadrant = quadrant;
|
|
32942
33018
|
exports.rectRectClearance = rectRectClearance;
|
|
32943
33019
|
exports.rectRectOverlapArea = rectRectOverlapArea;
|
|
33020
|
+
exports.relatedFocusSet = relatedFocusSet;
|
|
32944
33021
|
exports.rendersRows = rendersRows;
|
|
32945
33022
|
exports.requiredContrastRatio = requiredContrastRatio;
|
|
32946
33023
|
exports.requiredNearClearance = requiredNearClearance;
|