@cardenelabs/cdl 0.61.0 → 0.63.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardenelabs/cdl",
3
- "version": "0.61.0",
3
+ "version": "0.63.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/lang.ts CHANGED
@@ -236,6 +236,18 @@ const en = {
236
236
  "readout.kanban.inprogress": "In Progress",
237
237
  /** `kanban-board` の列の見出し (値は `done` で読む) */
238
238
  "readout.kanban.done": "Done",
239
+ /** `status-timeline` の区間の字 (値は `active` で読む) */
240
+ "readout.statusTimeline.active": "ACTIVE",
241
+ /** `status-timeline` の区間の字 (値は `idle` で読む) */
242
+ "readout.statusTimeline.idle": "IDLE",
243
+ /** `status-timeline` の区間の字 (値は `error` で読む) */
244
+ "readout.statusTimeline.error": "ERROR",
245
+ /** `user-presence` の状態の字 (値は `online` で読む) */
246
+ "readout.presence.online": "online",
247
+ /** `user-presence` の状態の字 (値は `away` で読む) */
248
+ "readout.presence.away": "away",
249
+ /** `user-presence` の状態の字 (値は `offline` で読む) */
250
+ "readout.presence.offline": "offline",
239
251
  /** `traffic-light` の赤の灯の見出し (値は `red` で読む) */
240
252
  "readout.trafficLight.red": "red",
241
253
  /** `traffic-light` の黄の灯の見出し (値は `yellow` / `amber` で読む) */
@@ -355,6 +367,12 @@ const ja: Record<CdlTextKey, string> = {
355
367
  "readout.kanban.todo": "未着手",
356
368
  "readout.kanban.inprogress": "進行中",
357
369
  "readout.kanban.done": "完了",
370
+ "readout.statusTimeline.active": "稼働",
371
+ "readout.statusTimeline.idle": "待機",
372
+ "readout.statusTimeline.error": "異常",
373
+ "readout.presence.online": "オンライン",
374
+ "readout.presence.away": "離席",
375
+ "readout.presence.offline": "オフライン",
358
376
  "readout.trafficLight.red": "赤",
359
377
  "readout.trafficLight.yellow": "黄",
360
378
  "readout.trafficLight.green": "緑",
package/src/presets.ts CHANGED
@@ -1030,7 +1030,9 @@ export type StateMachineBuilder = {
1030
1030
  export function stateMachine(preset: StateMachinePreset): StateMachineBuilder {
1031
1031
  const stateW = resolveStateW(preset.stateWidth, "stateMachine");
1032
1032
  const tone: Tone = preset.defaultTone ?? "accent";
1033
- const b = diagram(preset.id, { topic: preset.topic, type: "state" });
1033
+ // 図の型と最後の段の札は同じ綴り (#859)。 札を別の字にすると、消費側が型の一覧で引けない
1034
+ const diagramType = "state";
1035
+ const b = diagram(preset.id, { topic: preset.topic, type: diagramType });
1034
1036
 
1035
1037
  const phaseActivate: string[] = [];
1036
1038
  const stateOrder = new Map<string, number>();
@@ -1159,7 +1161,7 @@ export function stateMachine(preset: StateMachinePreset): StateMachineBuilder {
1159
1161
  b.phase(
1160
1162
  "fsm",
1161
1163
  { duration: 2400, title: preset.topic, body: "すべての状態と遷移を並べた姿。" },
1162
- (p) => p.activate(...phaseActivate).badge("fsm"),
1164
+ (p) => p.activate(...phaseActivate).badge(diagramType),
1163
1165
  );
1164
1166
  return b.build();
1165
1167
  },
@@ -1810,7 +1812,10 @@ export type MindMapBuilder = {
1810
1812
  export function mindMap(preset: MindMapPreset): MindMapBuilder {
1811
1813
  const canvasW = preset.branchWidth ? preset.branchWidth * 2 : 720;
1812
1814
  const canvasH = 480;
1813
- const b = diagram(preset.id, { topic: preset.topic, type: "mindmap" });
1815
+ // 型は他の組み立て関数と同じく短い名前 (`state` / `class` / `journey` と並ぶ `mind`)。
1816
+ // 最後の段の札も同じ綴り (#859)
1817
+ const diagramType = "mind";
1818
+ const b = diagram(preset.id, { topic: preset.topic, type: diagramType });
1814
1819
  const branches: MindBranch[] = [];
1815
1820
 
1816
1821
  const api: MindMapBuilder = {
@@ -1845,7 +1850,7 @@ export function mindMap(preset: MindMapPreset): MindMapBuilder {
1845
1850
  b.phase(
1846
1851
  "mindmap",
1847
1852
  { duration: 2400, title: preset.topic, body: "中心の主題から、すべての枝を放射状に広げた姿。" },
1848
- (p) => p.activate(nodeId).badge("mindmap"),
1853
+ (p) => p.activate(nodeId).badge(diagramType),
1849
1854
  );
1850
1855
  return b.build();
1851
1856
  },
@@ -2581,7 +2586,9 @@ export function stateMachine2(preset: StateMachine2Preset): StateMachine2Builder
2581
2586
  const stateW = resolveStateW(preset.stateWidth, "stateMachine2");
2582
2587
  const laneW = boxLaneW(stateW);
2583
2588
  const tone: Tone = preset.defaultTone ?? "accent";
2584
- const b = diagram(preset.id, { topic: preset.topic, type: "state" });
2589
+ // 入れ子を持つ状態の図も型は `state`。 最後の段の札も同じ綴りで、1 つ目の図との見分けは題が持つ (#859)
2590
+ const diagramType = "state";
2591
+ const b = diagram(preset.id, { topic: preset.topic, type: diagramType });
2585
2592
 
2586
2593
  const stateOrder = new Map<string, number>();
2587
2594
  const phaseActivate: string[] = [];
@@ -2645,7 +2652,7 @@ export function stateMachine2(preset: StateMachine2Preset): StateMachine2Builder
2645
2652
  title: preset.topic,
2646
2653
  body: "入れ子の状態と、入る時・出る時の処理を含めた、すべての状態と遷移。",
2647
2654
  },
2648
- (p) => p.activate(...phaseActivate).badge("statemachine2"),
2655
+ (p) => p.activate(...phaseActivate).badge(diagramType),
2649
2656
  );
2650
2657
  const d = b.build();
2651
2658
  // 入れ子の札に親の題を足す。 識別子 (`active`) を出すと、図のどこにも無い字になる
@@ -19,6 +19,7 @@ import type { Signal, Computed } from "../reactive";
19
19
  import { effect } from "../reactive";
20
20
  import { textWidth } from "../kinds/text-width";
21
21
  import { 桁で割る, 桁で省く } from "../kinds/row-align";
22
+ import { 幅で切る } from "../kinds/box-lines";
22
23
 
23
24
  /**
24
25
  * interactive primitive (input widget / formula / scroll trigger / event handler) を SVG diagram に
@@ -7734,12 +7735,24 @@ function StatusTimelineReadout({
7734
7735
  // silent skip
7735
7736
  }
7736
7737
  }
7738
+ const 引く = use字引();
7737
7739
  const colorLookup = new Map(colorMap.map((c) => [c.status.toLowerCase(), c.color]));
7738
7740
  const shown = events.slice(0, max);
7739
7741
  const stripHeight = 28;
7740
7742
  const width = 320;
7741
7743
  const cellW = shown.length > 0 ? (width - 20) / shown.length : 0;
7742
7744
  const height = stripHeight + 40;
7745
+ /*
7746
+ * 区間の字 (#857)。 既定の対応に並ぶ 3 つの値は辞書で引き、それ以外は値を大文字にする。
7747
+ * 色は値の綴りで選ぶので、辞書の字では引かない。
7748
+ *
7749
+ * 字は区間の幅に収まるだけ描く。 4 字で切っていた形は字数で幅を見積もっており、収まる幅があっても
7750
+ * `active` を `ACTI` と描き、和文の字には切る根拠が無かった (#851 と同じ理由)。
7751
+ */
7752
+ const 区間の字 = (status: string): string =>
7753
+ status === "active" || status === "idle" || status === "error"
7754
+ ? 引く(`readout.statusTimeline.${status}`)
7755
+ : status.toUpperCase();
7743
7756
  return (
7744
7757
  <div className="cdl-ip-item cdl-ip-readout-status-timeline" data-cdl-readout={id}>
7745
7758
  <span className="cdl-ip-label">{label}</span>
@@ -7752,8 +7765,11 @@ function StatusTimelineReadout({
7752
7765
  {shown.map((ev, i) => {
7753
7766
  const x = 10 + i * cellW;
7754
7767
  const c = colorLookup.get(ev.status) ?? "#cbd5e1";
7768
+ const 字 = 区間の字(ev.status);
7769
+ // 左右に 3px ずつ余白を取る (区間の枠は幅 - 2 で描く)
7770
+ const 描く字 = 幅で切る(字, 10, cellW - 8);
7755
7771
  return (
7756
- <g key={i} data-cdl-status-event={i}>
7772
+ <g key={i} data-cdl-status-event={i} data-cdl-status={ev.status}>
7757
7773
  <rect x={x} y={10} width={cellW - 2} height={stripHeight} fill={c} rx={2} />
7758
7774
  <text
7759
7775
  x={x + cellW / 2}
@@ -7764,7 +7780,8 @@ function StatusTimelineReadout({
7764
7780
  fontWeight={600}
7765
7781
  style={{ userSelect: "none" }}
7766
7782
  >
7767
- {ev.status.length > 5 ? ev.status.slice(0, 4).toUpperCase() : ev.status.toUpperCase()}
7783
+ {描く字 !== 字 ? <title>{字}</title> : null}
7784
+ {描く字}
7768
7785
  </text>
7769
7786
  <text
7770
7787
  x={x + cellW / 2}
@@ -8096,6 +8113,10 @@ function UserPresenceReadout({
8096
8113
  const width = 260;
8097
8114
  const height = shown.length * rowH + (overflow > 0 ? 20 : 0) + 8;
8098
8115
  const statusColor = (s: string) => (s === "online" ? "#22c55e" : s === "away" ? "#eab308" : "#94a3b8");
8116
+ const 引く = use字引();
8117
+ // 色を選ぶ 3 つの値は辞書で引き、それ以外は値のまま描く (#857)。 色は値の綴りで選ぶ
8118
+ const 状態の字 = (s: string): string =>
8119
+ s === "online" || s === "away" || s === "offline" ? 引く(`readout.presence.${s}`) : s;
8099
8120
  return (
8100
8121
  <div className="cdl-ip-item cdl-ip-readout-user-presence" data-cdl-readout={id}>
8101
8122
  <span className="cdl-ip-label">{label}</span>
@@ -8108,7 +8129,7 @@ function UserPresenceReadout({
8108
8129
  {shown.map((u, i) => {
8109
8130
  const y = 4 + i * rowH;
8110
8131
  return (
8111
- <g key={i} data-cdl-presence-user={i}>
8132
+ <g key={i} data-cdl-presence-user={i} data-cdl-presence-status={u.status}>
8112
8133
  <circle cx={12} cy={y + rowH / 2} r={6} fill={statusColor(u.status)} />
8113
8134
  <text
8114
8135
  x={26}
@@ -8128,7 +8149,7 @@ function UserPresenceReadout({
8128
8149
  fill="#64748b"
8129
8150
  style={{ userSelect: "none" }}
8130
8151
  >
8131
- {u.status}
8152
+ {状態の字(u.status)}
8132
8153
  </text>
8133
8154
  </g>
8134
8155
  );