@cardenelabs/cdl 0.108.0 → 0.110.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 +61 -1
- package/dist/index.cjs +41 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +41 -24
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +41 -24
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +41 -24
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/src/kinds/shape-basement.tsx +16 -7
- package/src/kinds/shape-blockchain.tsx +9 -5
- package/src/kinds/shape-commerce.tsx +10 -9
- package/src/kinds/shape-finance.tsx +10 -9
- package/src/kinds/shape-hardware.tsx +10 -10
- package/src/kinds/shape-region.tsx +26 -1
- package/src/render/header.tsx +10 -1
- package/src/render.tsx +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardenelabs/cdl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.110.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",
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
shapeRegion,
|
|
13
13
|
textWidth,
|
|
14
14
|
切って収まる下限,
|
|
15
|
+
帯で切る,
|
|
15
16
|
type ArtExtent,
|
|
16
17
|
} from "./shape-region";
|
|
17
|
-
import { 幅で切る } from "./box-lines";
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Shape-driven basement 8 kinds (CAR-1099、 CAR-1130 people ベース統一版)。
|
|
@@ -90,8 +90,14 @@ function labelBlock(
|
|
|
90
90
|
node.eyebrow ? textWidth(node.eyebrow, EYEBROW_SIZE, EYEBROW_TRACKING) : 0,
|
|
91
91
|
node.subtitle ? textWidth(node.subtitle, SUB_SIZE) : 0,
|
|
92
92
|
);
|
|
93
|
-
// 横で縮める倍率を読める下限で止める (#953)。
|
|
94
|
-
|
|
93
|
+
// 横で縮める倍率を読める下限で止める (#953)。 切って収まらない幅では下限を当てない。
|
|
94
|
+
//
|
|
95
|
+
// **題が一番広い行のときだけ当てる** (#957)。 塊の倍率は一番広い行で決まるので、
|
|
96
|
+
// 補いの行が幅を決めている箱で下限を当てると、題を 0.6px 上げるために補いの行から
|
|
97
|
+
// 字を落とすことになる = 払うのと得るのが別の行になる
|
|
98
|
+
const 題幅 = textWidth(node.title ?? "", size);
|
|
99
|
+
const 下限 =
|
|
100
|
+
題幅 >= 幅 ? 切って収まる下限(node.title ?? "", size, 0, band.w, textWidth) : 0;
|
|
95
101
|
const { k, x, y: baseline } = fitLabel(band, { 上, 下, 幅 }, pos, 下限);
|
|
96
102
|
return { k, x, baseline, 上端: baseline - 上 * k, 下端: baseline + 下 * k };
|
|
97
103
|
}
|
|
@@ -102,7 +108,7 @@ function commonLabel(node: LaidNode, pos: { x: number; y: number }, size: number
|
|
|
102
108
|
const x = 塊.x;
|
|
103
109
|
// 下限で止めた行は帯に入らないので、入るところまで切って `…` を付ける (#953)
|
|
104
110
|
const 切る = (t: string, 大きさ: number, 字間 = 0) =>
|
|
105
|
-
|
|
111
|
+
帯で切る(t, 大きさ * k, band.w, (u, f) => textWidth(u, f, 字間 * k));
|
|
106
112
|
return (
|
|
107
113
|
<>
|
|
108
114
|
{node.eyebrow && (
|
|
@@ -564,12 +570,15 @@ function planLabel(node: LaidNode, cx: number, 幅上限: number, plan: ReturnTy
|
|
|
564
570
|
node.eyebrow && plan.肩書 ? textWidth(node.eyebrow, plan.肩書.size, EYEBROW_TRACKING) : 0,
|
|
565
571
|
node.subtitle && plan.説明 ? textWidth(node.subtitle, plan.説明.size) : 0,
|
|
566
572
|
);
|
|
567
|
-
// 縮めは読める下限で止める (#953)。
|
|
568
|
-
|
|
573
|
+
// 縮めは読める下限で止める (#953)。 下限が無いと長い名前が点にしか見えない大きさになる。
|
|
574
|
+
// 題が一番広い行のときだけ当てる (#957、 上の `labelBlock` と同じ理由)
|
|
575
|
+
const 題幅 = textWidth(node.title ?? "", plan.名前.size);
|
|
576
|
+
const 下限 =
|
|
577
|
+
題幅 >= 幅 ? 切って収まる下限(node.title ?? "", plan.名前.size, 0, 幅上限, textWidth) : 0;
|
|
569
578
|
const k = 幅 > 0 && 幅上限 > 0 ? Math.min(1, Math.max(幅上限 / 幅, 下限)) : 1;
|
|
570
579
|
// 下限で止めた行は箱に入らないので、入るところまで切って `…` を付ける (#953)
|
|
571
580
|
const 切る = (t: string, 大きさ: number, 字間 = 0) =>
|
|
572
|
-
|
|
581
|
+
帯で切る(t, 大きさ * k, 幅上限, (u, f) => textWidth(u, f, 字間 * k));
|
|
573
582
|
return (
|
|
574
583
|
<>
|
|
575
584
|
{node.eyebrow && plan.肩書 && (
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
shapeRegion,
|
|
7
7
|
幅の倍率,
|
|
8
8
|
切って収まる下限,
|
|
9
|
+
帯で切る,
|
|
9
10
|
打ち消しの倍率,
|
|
10
11
|
絵の中の字の幅,
|
|
11
12
|
type ArtExtent,
|
|
@@ -136,15 +137,18 @@ function blockchainNodeExtent(strokeWidth: number): ArtExtent {
|
|
|
136
137
|
* 名前の塊を描く。 位置と大きさは `labelPlan` が決める (箱の下端から積み上げる、 #433)。
|
|
137
138
|
*/
|
|
138
139
|
function bottomLabel(node: LaidNode, cx: number, plan: ReturnType<typeof labelPlan>) {
|
|
139
|
-
// 縮めは読める下限で止める (#953)。
|
|
140
|
-
|
|
140
|
+
// 縮めは読める下限で止める (#953)。 止めた行は箱に入らないので、入るところまで切る。
|
|
141
|
+
// 下限を当てるのは題の行だけ (#957) = 補いの行に当てると、収まっている行を大きくしてから
|
|
142
|
+
// 切ることになる
|
|
143
|
+
const 収める = (t: string, 大きさ: number, 字間: number, 題か = false) => {
|
|
141
144
|
const 測る = (u: string, f: number, ls: number) => 字の幅(u, f) + ls * [...u].length;
|
|
142
|
-
const
|
|
145
|
+
const 下限 = 題か ? 切って収まる下限(t, 大きさ, 字間, node.w, 測る) : 0;
|
|
146
|
+
const 倍率 = Math.max(幅の倍率(t, 大きさ, 字間, node.w), 下限);
|
|
143
147
|
const size = 大きさ * 倍率;
|
|
144
|
-
return { 倍率, text:
|
|
148
|
+
return { 倍率, text: 帯で切る(t, size, node.w, (u, f) => 字の幅(u, f) + 字間 * 倍率 * [...u].length) };
|
|
145
149
|
};
|
|
146
150
|
const 肩 = node.eyebrow && plan.肩書 ? 収める(node.eyebrow, plan.肩書.size, 2) : { 倍率: 1, text: node.eyebrow ?? "" };
|
|
147
|
-
const 名 = 収める(node.title ?? "", plan.名前.size, 0);
|
|
151
|
+
const 名 = 収める(node.title ?? "", plan.名前.size, 0, true);
|
|
148
152
|
const 説 = node.subtitle && plan.説明 ? 収める(node.subtitle, plan.説明.size, 0) : { 倍率: 1, text: node.subtitle ?? "" };
|
|
149
153
|
const 肩書倍率 = 肩.倍率;
|
|
150
154
|
const 名前倍率 = 名.倍率;
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
打ち消しの倍率,
|
|
8
8
|
type 打ち消す字,
|
|
9
9
|
切って収まる下限,
|
|
10
|
+
帯で切る,
|
|
10
11
|
} from "./shape-region";
|
|
11
|
-
import { 幅で切る } from "./box-lines";
|
|
12
12
|
import { MONO_ADVANCE_RATIO, displayWidth } from "./row-align";
|
|
13
13
|
import type { LaidNode } from "../types";
|
|
14
14
|
import { 字引きを作る, type CdlLang } from "../lang";
|
|
@@ -101,17 +101,18 @@ function 字幅(文字列: string, 大きさ: number, 字間: number): number {
|
|
|
101
101
|
*
|
|
102
102
|
* 字間も同じ割合で詰める = 大きさだけ縮めても字間が残ると幅が比例して縮まない。
|
|
103
103
|
*/
|
|
104
|
-
function 幅に収める(文字列: string, 大きさ: number, 字間: number, 箱幅: number) {
|
|
104
|
+
function 幅に収める(文字列: string, 大きさ: number, 字間: number, 箱幅: number, 題か = false) {
|
|
105
105
|
const 幅 = 字幅(文字列, 大きさ, 字間);
|
|
106
106
|
// 縮めは読める下限で止める (#953)。 下限が無いと長い名前が点にしか見えない大きさになる。
|
|
107
|
-
// 止めた行は箱に入らないので、入るところまで切って `…` を付ける (#433 の決まりを保つ)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
// 止めた行は箱に入らないので、入るところまで切って `…` を付ける (#433 の決まりを保つ)。
|
|
108
|
+
//
|
|
109
|
+
// **下限を当てるのは題の行だけ** (#957)。 補いの行に当てると、収まっている行を
|
|
110
|
+
// 大きくしてから切ることになる = 書いた字を落として得るのが 1px に満たない
|
|
111
|
+
const 下限 = 題か ? 切って収まる下限(文字列, 大きさ, 字間, 箱幅, 字幅) : 0;
|
|
112
|
+
const 倍率 = 幅 > 0 && 箱幅 > 0 ? Math.min(1, Math.max(箱幅 / 幅, 下限)) : 1;
|
|
112
113
|
const size = 大きさ * 倍率;
|
|
113
114
|
const spacing = 字間 * 倍率;
|
|
114
|
-
return { size, spacing, text:
|
|
115
|
+
return { size, spacing, text: 帯で切る(文字列, size, 箱幅, (u, f) => 字幅(u, f, spacing)) };
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
/**
|
|
@@ -120,7 +121,7 @@ function 幅に収める(文字列: string, 大きさ: number, 字間: number,
|
|
|
120
121
|
*/
|
|
121
122
|
function bottomLabel(node: LaidNode, cx: number, plan: ReturnType<typeof labelPlan>) {
|
|
122
123
|
const 肩 = 幅に収める(node.eyebrow ?? "", plan.肩書?.size ?? 0, LABEL_EYEBROW_SPACING, node.w);
|
|
123
|
-
const 名 = 幅に収める(node.title ?? "", plan.名前.size, 0, node.w);
|
|
124
|
+
const 名 = 幅に収める(node.title ?? "", plan.名前.size, 0, node.w, true);
|
|
124
125
|
const 説 = 幅に収める(node.subtitle ?? "", plan.説明?.size ?? 0, 0, node.w);
|
|
125
126
|
return (
|
|
126
127
|
<>
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
打ち消しの倍率,
|
|
7
7
|
type 打ち消す字,
|
|
8
8
|
切って収まる下限,
|
|
9
|
+
帯で切る,
|
|
9
10
|
} from "./shape-region";
|
|
10
|
-
import { 幅で切る } from "./box-lines";
|
|
11
11
|
import type { LaidNode } from "../types";
|
|
12
12
|
import { 字引きを作る, type CdlLang } from "../lang";
|
|
13
13
|
|
|
@@ -100,17 +100,18 @@ function 字幅(文字列: string, 大きさ: number, 字間: number): number {
|
|
|
100
100
|
*
|
|
101
101
|
* 字間も同じ割合で詰める = 大きさだけ縮めても字間が残ると幅が比例して縮まない。
|
|
102
102
|
*/
|
|
103
|
-
function 幅に収める(文字列: string, 大きさ: number, 字間: number, 箱幅: number) {
|
|
103
|
+
function 幅に収める(文字列: string, 大きさ: number, 字間: number, 箱幅: number, 題か = false) {
|
|
104
104
|
const 幅 = 字幅(文字列, 大きさ, 字間);
|
|
105
105
|
// 縮めは読める下限で止める (#953)。 下限が無いと長い名前が点にしか見えない大きさになる。
|
|
106
|
-
// 止めた行は箱に入らないので、入るところまで切って `…` を付ける (#433 の決まりを保つ)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
// 止めた行は箱に入らないので、入るところまで切って `…` を付ける (#433 の決まりを保つ)。
|
|
107
|
+
//
|
|
108
|
+
// **下限を当てるのは題の行だけ** (#957)。 補いの行に当てると、収まっている行を
|
|
109
|
+
// 大きくしてから切ることになる = 書いた字を落として得るのが 1px に満たない
|
|
110
|
+
const 下限 = 題か ? 切って収まる下限(文字列, 大きさ, 字間, 箱幅, 字幅) : 0;
|
|
111
|
+
const 倍率 = 幅 > 0 && 箱幅 > 0 ? Math.min(1, Math.max(箱幅 / 幅, 下限)) : 1;
|
|
111
112
|
const size = 大きさ * 倍率;
|
|
112
113
|
const spacing = 字間 * 倍率;
|
|
113
|
-
return { size, spacing, text:
|
|
114
|
+
return { size, spacing, text: 帯で切る(文字列, size, 箱幅, (u, f) => 字幅(u, f, spacing)) };
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
/**
|
|
@@ -119,7 +120,7 @@ function 幅に収める(文字列: string, 大きさ: number, 字間: number,
|
|
|
119
120
|
*/
|
|
120
121
|
function bottomLabel(node: LaidNode, cx: number, plan: ReturnType<typeof labelPlan>) {
|
|
121
122
|
const 肩 = 幅に収める(node.eyebrow ?? "", plan.肩書?.size ?? 0, LABEL_EYEBROW_SPACING, node.w);
|
|
122
|
-
const 名 = 幅に収める(node.title ?? "", plan.名前.size, 0, node.w);
|
|
123
|
+
const 名 = 幅に収める(node.title ?? "", plan.名前.size, 0, node.w, true);
|
|
123
124
|
const 説 = 幅に収める(node.subtitle ?? "", plan.説明?.size ?? 0, 0, node.w);
|
|
124
125
|
return (
|
|
125
126
|
<>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { JSX } from "react";
|
|
2
|
-
import { shapeRegion, labelPlan, fitArt, textWidth, 切って収まる下限, type ArtExtent } from "./shape-region";
|
|
3
|
-
import { 幅で切る } from "./box-lines";
|
|
2
|
+
import { shapeRegion, labelPlan, fitArt, textWidth, 切って収まる下限, 帯で切る, type ArtExtent } from "./shape-region";
|
|
4
3
|
import type { LaidNode } from "../types";
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -105,17 +104,18 @@ const LABEL_EYEBROW_SPACING = 2;
|
|
|
105
104
|
* 字幅の見積りは共有の `textWidth` (実測を階級で丸め上げた表) が持つ。 字間も同じ割合で
|
|
106
105
|
* 詰める = 大きさだけ縮めても字間が残ると幅が比例して縮まない。
|
|
107
106
|
*/
|
|
108
|
-
function 幅に収める(文字列: string, 大きさ: number, 字間: number, 箱幅: number) {
|
|
107
|
+
function 幅に収める(文字列: string, 大きさ: number, 字間: number, 箱幅: number, 題か = false) {
|
|
109
108
|
const 幅 = textWidth(文字列, 大きさ, 字間);
|
|
110
109
|
// 縮めは読める下限で止める (#953)。 下限が無いと長い名前が点にしか見えない大きさになる。
|
|
111
|
-
// 止めた行は箱に入らないので、入るところまで切って `…` を付ける (#433 の決まりを保つ)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
110
|
+
// 止めた行は箱に入らないので、入るところまで切って `…` を付ける (#433 の決まりを保つ)。
|
|
111
|
+
//
|
|
112
|
+
// **下限を当てるのは題の行だけ** (#957)。 補いの行に当てると、収まっている行を
|
|
113
|
+
// 大きくしてから切ることになる = 書いた字を落として得るのが 1px に満たない
|
|
114
|
+
const 下限 = 題か ? 切って収まる下限(文字列, 大きさ, 字間, 箱幅, textWidth) : 0;
|
|
115
|
+
const 倍率 = 幅 > 0 && 箱幅 > 0 ? Math.min(1, Math.max(箱幅 / 幅, 下限)) : 1;
|
|
116
116
|
const size = 大きさ * 倍率;
|
|
117
117
|
const spacing = 字間 * 倍率;
|
|
118
|
-
return { size, spacing, text:
|
|
118
|
+
return { size, spacing, text: 帯で切る(文字列, size, 箱幅, (u, f) => textWidth(u, f, spacing)) };
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/**
|
|
@@ -126,7 +126,7 @@ function 幅に収める(文字列: string, 大きさ: number, 字間: number,
|
|
|
126
126
|
*/
|
|
127
127
|
function bottomLabel(node: LaidNode, cx: number, plan: ReturnType<typeof labelPlan>) {
|
|
128
128
|
const 肩 = 幅に収める(node.eyebrow ?? "", plan.肩書?.size ?? 0, LABEL_EYEBROW_SPACING, node.w);
|
|
129
|
-
const 名 = 幅に収める(node.title ?? "", plan.名前.size, 0, node.w);
|
|
129
|
+
const 名 = 幅に収める(node.title ?? "", plan.名前.size, 0, node.w, true);
|
|
130
130
|
const 説 = 幅に収める(node.subtitle ?? "", plan.説明?.size ?? 0, 0, node.w);
|
|
131
131
|
return (
|
|
132
132
|
<>
|
|
@@ -89,6 +89,31 @@ export function 読める下限の倍率(大きさ: number): number {
|
|
|
89
89
|
* 測り方は呼ぶ側から渡す。 種別ごとに字幅の見積りが違い、ここで 1 つに決めると
|
|
90
90
|
* 縮める時と切る時で別の幅を使うことになる。
|
|
91
91
|
*/
|
|
92
|
+
/**
|
|
93
|
+
* 帯にちょうど収まる行を、丸め誤差で切らないための相対の余裕 (#957)。
|
|
94
|
+
*
|
|
95
|
+
* 塊の倍率は一番広い行が帯にちょうど収まる値なので、切る側の測り直しが浮動小数で
|
|
96
|
+
* 髪の毛 1 本ぶん上回ると、収まっている行を切る (実測 = `間隔を倍に広げる · 最大 3 回` が
|
|
97
|
+
* `... 最大 3 …` になった)。
|
|
98
|
+
*
|
|
99
|
+
* 相対で持つのは、帯の幅が 20 から 600 まで動くため。 絶対値で持つと狭い帯で効きすぎる。
|
|
100
|
+
*/
|
|
101
|
+
const 切る余裕 = 1e-9;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 行を帯に収まるところまでで切り、切った時は `…` を付ける (#953)。
|
|
105
|
+
*
|
|
106
|
+
* ちょうど収まる行は切らない (§ 切る余裕)。
|
|
107
|
+
*/
|
|
108
|
+
export function 帯で切る(
|
|
109
|
+
text: string,
|
|
110
|
+
大きさ: number,
|
|
111
|
+
幅上限: number,
|
|
112
|
+
測る: (t: string, size: number) => number,
|
|
113
|
+
): string {
|
|
114
|
+
return 幅で切る(text, 大きさ, 幅上限 * (1 + 切る余裕), 測る);
|
|
115
|
+
}
|
|
116
|
+
|
|
92
117
|
export function 切って収まる下限(
|
|
93
118
|
題: string,
|
|
94
119
|
大きさ: number,
|
|
@@ -98,7 +123,7 @@ export function 切って収まる下限(
|
|
|
98
123
|
): number {
|
|
99
124
|
const 下限 = 読める下限の倍率(大きさ);
|
|
100
125
|
if (!(下限 > 0) || !(幅上限 > 0)) return 0;
|
|
101
|
-
return
|
|
126
|
+
return 帯で切る(題, 大きさ * 下限, 幅上限, (u, f) => 測る(u, f, 字間 * 下限)) === "" ? 0 : 下限;
|
|
102
127
|
}
|
|
103
128
|
|
|
104
129
|
|
package/src/render/header.tsx
CHANGED
|
@@ -10,6 +10,7 @@ export function CdlHeader({
|
|
|
10
10
|
states,
|
|
11
11
|
onJumpPhase,
|
|
12
12
|
headingLevel = 3,
|
|
13
|
+
showTopic = true,
|
|
13
14
|
}: {
|
|
14
15
|
topic: string;
|
|
15
16
|
phases: CdlPhase[];
|
|
@@ -21,12 +22,20 @@ export function CdlHeader({
|
|
|
21
22
|
/** phase title 描画時の heading tag level (2 | 3 | 4)、 default 3 で従来動作維持。
|
|
22
23
|
* downstream で h1 直後に配置する場合は 2、 h2 直後なら 3 (default)、 h3 直後なら 4。 */
|
|
23
24
|
headingLevel?: 2 | 3 | 4;
|
|
25
|
+
/**
|
|
26
|
+
* 話題を左上に出すか (#955)。 図が同じ字を既に描いている時だけ呼出側が `false` を渡す。
|
|
27
|
+
*
|
|
28
|
+
* 段の印は `ml-auto` で右へ寄せてあるので、話題を落としても並びは動かない。
|
|
29
|
+
*/
|
|
30
|
+
showTopic?: boolean;
|
|
24
31
|
}): JSX.Element {
|
|
25
32
|
const HeadingTag = (`h${headingLevel}` as "h2" | "h3" | "h4");
|
|
26
33
|
return (
|
|
27
34
|
<div className="border-b border-[var(--cdl-divider,#d4d4d8)]/35 px-7 py-6">
|
|
28
35
|
<div className="mb-5 flex items-center gap-3">
|
|
29
|
-
|
|
36
|
+
{showTopic && (
|
|
37
|
+
<div className="text-[10px] font-bold uppercase tracking-[0.2em]" style={{ color: "var(--cdl-text-accent, #2d6a8f)" }}>{topic}</div>
|
|
38
|
+
)}
|
|
30
39
|
<div className="ml-auto flex items-center gap-1.5">
|
|
31
40
|
{phases.map((p, idx) => {
|
|
32
41
|
const active = idx === phaseIdx;
|
package/src/render.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { useEffect, useMemo } from "react";
|
|
|
2
2
|
import type { JSX } from "react";
|
|
3
3
|
import { useReducedMotion, useTimeline } from "./anim/react";
|
|
4
4
|
import { compile } from "./compile";
|
|
5
|
+
import { drawsFigureTitle } from "./layout/spec";
|
|
5
6
|
import { CdlHeader } from "./render/header";
|
|
6
7
|
import { CdlStage } from "./render/stage";
|
|
7
8
|
import {
|
|
@@ -170,6 +171,21 @@ export function CdlDiagramView({ diagram, laid: laidProp, hideHeader = false, hi
|
|
|
170
171
|
// (出し分けと綴りで読む読み出しは値を綴りのまま読む)
|
|
171
172
|
const 値の名前 = useMemo(() => 値の名前の表を作る(diagram.inputs), [diagram.inputs]);
|
|
172
173
|
|
|
174
|
+
/**
|
|
175
|
+
* 図が話題と同じ字を既に描いているか (#955)。
|
|
176
|
+
*
|
|
177
|
+
* 図表 15 種は 0.96.0 (#930) から自分の題を箱の上に描く。 頭の帯も話題を出すので、
|
|
178
|
+
* 話題と題が同じ図では同じ字が 2 か所に並ぶ。 描いている側を残し、帯の 1 行を落とす。
|
|
179
|
+
*
|
|
180
|
+
* 種別の一覧は `drawsFigureTitle` から導く。 手で持つと engine に図表が増えた日にずれる。
|
|
181
|
+
* 箱の題 (`node-label`) は数えない = 箱は図の中の 1 つにすぎず、話題を名乗る場所が他に無い。
|
|
182
|
+
*/
|
|
183
|
+
const 図が話題を描く = useMemo(() => {
|
|
184
|
+
const 話題 = laid.topic.trim();
|
|
185
|
+
if (話題 === "") return false;
|
|
186
|
+
return laid.nodes.some((n) => drawsFigureTitle(n.kind) && (n.title ?? "").trim() === 話題);
|
|
187
|
+
}, [laid.nodes, laid.topic]);
|
|
188
|
+
|
|
173
189
|
return (
|
|
174
190
|
<div
|
|
175
191
|
ref={isInteractive ? interactive.containerRef : undefined}
|
|
@@ -193,6 +209,7 @@ export function CdlDiagramView({ diagram, laid: laidProp, hideHeader = false, hi
|
|
|
193
209
|
timeline.play();
|
|
194
210
|
}}
|
|
195
211
|
headingLevel={headingLevel}
|
|
212
|
+
showTopic={!図が話題を描く}
|
|
196
213
|
/>
|
|
197
214
|
)}
|
|
198
215
|
{/* interactive panel = input widget / formula readout / scroll readout (SVG の上に配置)、
|