@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/CHANGELOG.md CHANGED
@@ -5,6 +5,39 @@ CDL (Chainome Diagram Language) の主要変更履歴。
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.63.0] - 2026-09-13
9
+
10
+ ### Changed
11
+
12
+ - **状態の図と発想の図の段の札を、図の型と同じ綴りにした** (#859)
13
+
14
+ 組み立て関数は最後の段に図の型と同じ綴りの札を付けるが、`stateMachine` は `fsm`、`stateMachine2` は
15
+ `statemachine2` を付けており、図の型 (`state`) と食い違っていた。 消費側は型の一覧で札を引けず、札だけが
16
+ 型の名前に無い英語として残った。 2 つとも札を `state` にした (2 つの図の見分けは図の題が持つ)。
17
+
18
+ `mindMap` は図の型を `mindmap` から `mind` にし、札も `mind` にした。 他の組み立て関数と同じく短い名前
19
+ (`state` / `class` / `journey`) の並びに揃える。 **図の根の `data-cdl-type` が `mind` になる** ので、
20
+ `[data-cdl-type="mindmap"]` で見た目を決めている消費側は書き換えが要る。
21
+
22
+ グラフ (`chart`) は描き方の種類 (`pie` / `bar` / `line`) を札にする形のまま変えない。 札を族の名前
23
+ (`chart`) にすると、全てのグラフが同じ字になり見出しの役に立たない。
24
+
25
+ ## [0.62.0] - 2026-09-13
26
+
27
+ ### Changed
28
+
29
+ - **稼働の時系列と在席の状態の字を、図の言語の辞書で描くようにした** (#857)
30
+
31
+ `status-timeline` と `user-presence` は、色を選ぶための状態の語 (`active` / `idle` / `error` と
32
+ `online` / `away` / `offline`) を字にもそのまま使っており、`lang: "ja"` の図でもこの字だけ英語で残っていた。
33
+ 6 つの語を辞書で引き、日本語の図は `稼働` / `待機` / `異常` と `オンライン` / `離席` / `オフライン` を描く。
34
+ 色は変わらず値の綴りで選び、描いた状態の値を `data-cdl-status` / `data-cdl-presence-status` の目印に出す。
35
+ 辞書に無い状態の値は、`status-timeline` は大文字で、`user-presence` はそのまま描く。
36
+
37
+ `status-timeline` の区間の字は、6 字以上を 4 字で切る形をやめ、区間の幅に収まるだけ描く (#851 と同じ理由)。
38
+ 収まらない時は `…` で省き、区間の見出し (`title`) に省く前の字を出す。 英語の図は `active` の区間を幅が
39
+ 足りれば `ACTIVE` と描く (変更前は `ACTI`)。
40
+
8
41
  ## [0.61.0] - 2026-09-13
9
42
 
10
43
  ### Added
@@ -2645,7 +2678,9 @@ Initial OSS release.
2645
2678
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
2646
2679
  行き止まりになる。
2647
2680
 
2648
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.61.0...HEAD
2681
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.63.0...HEAD
2682
+ [0.63.0]: https://github.com/cardene777/cdl/compare/v0.62.0...v0.63.0
2683
+ [0.62.0]: https://github.com/cardene777/cdl/compare/v0.61.0...v0.62.0
2649
2684
  [0.61.0]: https://github.com/cardene777/cdl/compare/v0.60.0...v0.61.0
2650
2685
  [0.60.0]: https://github.com/cardene777/cdl/compare/v0.59.1...v0.60.0
2651
2686
  [0.59.1]: https://github.com/cardene777/cdl/compare/v0.59.0...v0.59.1
package/dist/index.cjs CHANGED
@@ -560,6 +560,18 @@ var en = {
560
560
  "readout.kanban.inprogress": "In Progress",
561
561
  /** `kanban-board` の列の見出し (値は `done` で読む) */
562
562
  "readout.kanban.done": "Done",
563
+ /** `status-timeline` の区間の字 (値は `active` で読む) */
564
+ "readout.statusTimeline.active": "ACTIVE",
565
+ /** `status-timeline` の区間の字 (値は `idle` で読む) */
566
+ "readout.statusTimeline.idle": "IDLE",
567
+ /** `status-timeline` の区間の字 (値は `error` で読む) */
568
+ "readout.statusTimeline.error": "ERROR",
569
+ /** `user-presence` の状態の字 (値は `online` で読む) */
570
+ "readout.presence.online": "online",
571
+ /** `user-presence` の状態の字 (値は `away` で読む) */
572
+ "readout.presence.away": "away",
573
+ /** `user-presence` の状態の字 (値は `offline` で読む) */
574
+ "readout.presence.offline": "offline",
563
575
  /** `traffic-light` の赤の灯の見出し (値は `red` で読む) */
564
576
  "readout.trafficLight.red": "red",
565
577
  /** `traffic-light` の黄の灯の見出し (値は `yellow` / `amber` で読む) */
@@ -668,6 +680,12 @@ var ja = {
668
680
  "readout.kanban.todo": "\u672A\u7740\u624B",
669
681
  "readout.kanban.inprogress": "\u9032\u884C\u4E2D",
670
682
  "readout.kanban.done": "\u5B8C\u4E86",
683
+ "readout.statusTimeline.active": "\u7A3C\u50CD",
684
+ "readout.statusTimeline.idle": "\u5F85\u6A5F",
685
+ "readout.statusTimeline.error": "\u7570\u5E38",
686
+ "readout.presence.online": "\u30AA\u30F3\u30E9\u30A4\u30F3",
687
+ "readout.presence.away": "\u96E2\u5E2D",
688
+ "readout.presence.offline": "\u30AA\u30D5\u30E9\u30A4\u30F3",
671
689
  "readout.trafficLight.red": "\u8D64",
672
690
  "readout.trafficLight.yellow": "\u9EC4",
673
691
  "readout.trafficLight.green": "\u7DD1"
@@ -1697,6 +1715,111 @@ function requiredRowsWidth(rows, kind) {
1697
1715
  if (kind === void 0) return Math.ceil(Math.max(storage, generic));
1698
1716
  return Math.ceil(kind === "storage" ? storage : generic);
1699
1717
  }
1718
+
1719
+ // src/kinds/compact-title.ts
1720
+ function estimateTextWidth(text, fontSize) {
1721
+ let w = 0;
1722
+ for (const ch of text) {
1723
+ const isFullWidth = /[\u3000-\u9FFF\uFF00-\uFFEF]/.test(ch);
1724
+ w += fontSize * (isFullWidth ? 1.05 : 0.62);
1725
+ }
1726
+ return w;
1727
+ }
1728
+ function fitTextSize(text, maxWidth, targetSize, minSize) {
1729
+ let size = targetSize;
1730
+ while (size > minSize && estimateTextWidth(text, size) > maxWidth) {
1731
+ size -= 1;
1732
+ }
1733
+ return size;
1734
+ }
1735
+ var COMPACT_MAX_H = 100;
1736
+ var COMPACT_PADDING_X = 16;
1737
+ var MIN_TEXT_SIZE = 11;
1738
+ var ASCENT = 0.72;
1739
+ var DESCENT = 0.25;
1740
+ var MIN_BAND_H = MIN_TEXT_SIZE * (ASCENT + DESCENT);
1741
+ var EYEBROW_BASELINE = 38;
1742
+ var EYEBROW_SIZE = 18;
1743
+ var EYEBROW_GAP = 8;
1744
+ var BOTTOM_INSET = 4;
1745
+ var eyebrowBottom = () => EYEBROW_BASELINE + EYEBROW_SIZE * DESCENT;
1746
+ var titleBandTop = (hasEyebrow) => eyebrowBottom() + EYEBROW_GAP ;
1747
+ var isCompactBox = (h) => h < COMPACT_MAX_H;
1748
+ function titlePlacement(node, \u901A\u5E38, opts = {}) {
1749
+ if (!isCompactBox(node.h)) {
1750
+ return { x: \u901A\u5E38.x, y: \u901A\u5E38.y, size: \u901A\u5E38.size, anchor: "start" };
1751
+ }
1752
+ const \u9AD8\u3055 = Math.max(0, node.h);
1753
+ const \u76EE\u5370\u3042\u308A = opts.hasEyebrow === true;
1754
+ const \u4E0A = \u76EE\u5370\u3042\u308A && \u9AD8\u3055 >= eyebrowBottom() ? titleBandTop() : 0;
1755
+ const \u751F\u306E\u5E2F = Math.max(0, \u9AD8\u3055 - \u4E0A);
1756
+ const \u4E0B\u4F59\u767D = \u751F\u306E\u5E2F >= MIN_BAND_H + BOTTOM_INSET ? BOTTOM_INSET : 0;
1757
+ const \u5E2F = \u751F\u306E\u5E2F - \u4E0B\u4F59\u767D;
1758
+ const \u5E45\u3067 = fitTextSize(
1759
+ node.title,
1760
+ Math.max(0, node.w - COMPACT_PADDING_X),
1761
+ \u901A\u5E38.size,
1762
+ MIN_TEXT_SIZE
1763
+ );
1764
+ const \u5E2F\u3067 = Math.floor(\u5E2F / (ASCENT + DESCENT));
1765
+ const size = Math.max(MIN_TEXT_SIZE, Math.min(\u5E45\u3067, \u5E2F\u3067));
1766
+ const \u5B57\u9AD8 = size * (ASCENT + DESCENT);
1767
+ const y = \u5B57\u9AD8 <= \u5E2F ? \u4E0A + \u5E2F / 2 + size * (ASCENT - DESCENT) / 2 : \u4E0A > 0 ? \u4E0A + size * ASCENT : (\u9AD8\u3055 - \u5B57\u9AD8) / 2 + size * ASCENT;
1768
+ return { x: node.w / 2, y, size, anchor: "middle" };
1769
+ }
1770
+
1771
+ // src/kinds/box-lines.ts
1772
+ var \u884C\u9001\u308A\u306E\u6BD4 = 1.15;
1773
+ var \u5B57\u306E\u9AD8\u3055\u306E\u6BD4 = 0.72;
1774
+ var \u4E0A\u4E0B\u306E\u4F59\u767D = 2;
1775
+ var \u5DE6\u53F3\u306E\u4F59\u767D = 8;
1776
+ function \u4F7F\u3048\u308B\u5E45(\u7BB1\u306E\u5E45) {
1777
+ return \u7BB1\u306E\u5E45 - \u5DE6\u53F3\u306E\u4F59\u767D * 2;
1778
+ }
1779
+ function \u5E45\u3067\u5207\u308B(text, fontSize, \u4F7F\u3048\u308B\u5E452, \u6E2C\u308B = textWidth) {
1780
+ if (\u4F7F\u3048\u308B\u5E452 <= 0) return "";
1781
+ if (\u6E2C\u308B(text, fontSize) <= \u4F7F\u3048\u308B\u5E452) return text;
1782
+ const \u7701\u7565 = "\u2026";
1783
+ const \u7701\u7565\u306E\u5E45 = \u6E2C\u308B(\u7701\u7565, fontSize);
1784
+ if (\u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E452) return "";
1785
+ let \u51FA = "";
1786
+ let \u5E45 = 0;
1787
+ for (const c of \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text)) {
1788
+ const \u5B57\u306E\u5E452 = \u6E2C\u308B(c, fontSize);
1789
+ if (\u5E45 + \u5B57\u306E\u5E452 + \u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E452) break;
1790
+ \u5E45 += \u5B57\u306E\u5E452;
1791
+ \u51FA += c;
1792
+ }
1793
+ return `${\u51FA}${\u7701\u7565}`;
1794
+ }
1795
+ var \u7E2E\u3081\u306E\u4E0B\u9650 = MIN_TEXT_SIZE;
1796
+ function \u5E45\u306B\u53CE\u3081\u308B(text, fontSize, \u4F7F\u3048\u308B\u5E452, \u6E2C\u308B = textWidth) {
1797
+ let size = fontSize;
1798
+ while (size > \u7E2E\u3081\u306E\u4E0B\u9650 && \u6E2C\u308B(text, size) > \u4F7F\u3048\u308B\u5E452) size -= 1;
1799
+ return { text: \u5E45\u3067\u5207\u308B(text, size, \u4F7F\u3048\u308B\u5E452, \u6E2C\u308B), fontSize: size };
1800
+ }
1801
+ function \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text) {
1802
+ const \u533A\u5207\u308A = Intl.Segmenter;
1803
+ if (typeof \u533A\u5207\u308A !== "function") return [...text];
1804
+ return [...new \u533A\u5207\u308A(void 0, { granularity: "grapheme" }).segment(text)].map((g) => g.segment);
1805
+ }
1806
+ function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u30553) {
1807
+ const \u5019\u88DC = \u884C.filter((r, i) => i === 0 || r.text.trim() !== "");
1808
+ if (\u5019\u88DC.length === 0) return [];
1809
+ const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u30553 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
1810
+ const \u9AD8\u3055 = (rs) => rs.reduce((a, r) => a + r.fontSize * \u884C\u9001\u308A\u306E\u6BD4, 0);
1811
+ const \u6B8B\u3059 = [...\u5019\u88DC];
1812
+ while (\u6B8B\u3059.length > 1 && \u9AD8\u3055(\u6B8B\u3059) > \u4F7F\u3048\u308B\u9AD8\u3055) \u6B8B\u3059.pop();
1813
+ const \u5E45 = \u4F7F\u3048\u308B\u5E45(\u7BB1\u306E\u5E45);
1814
+ const \u53CE\u3081\u305F = \u6B8B\u3059.map((r) => ({ ...r, ...\u5E45\u306B\u53CE\u3081\u308B(r.text, r.fontSize, \u5E45) }));
1815
+ const \u7DCF\u9AD8 = \u9AD8\u3055(\u53CE\u3081\u305F);
1816
+ let \u7A4D\u307F = -\u7DCF\u9AD8 / 2;
1817
+ return \u53CE\u3081\u305F.map((r) => {
1818
+ const dy = \u7A4D\u307F + (\u884C\u9001\u308A\u306E\u6BD4 + \u5B57\u306E\u9AD8\u3055\u306E\u6BD4) / 2 * r.fontSize;
1819
+ \u7A4D\u307F += r.fontSize * \u884C\u9001\u308A\u306E\u6BD4;
1820
+ return { ...r, dy };
1821
+ });
1822
+ }
1700
1823
  var \u64CD\u4F5C\u90E8\u306E\u8A00\u8A9E = react.createContext("en");
1701
1824
  function use\u5B57\u5F15() {
1702
1825
  const lang = react.useContext(\u64CD\u4F5C\u90E8\u306E\u8A00\u8A9E);
@@ -7828,12 +7951,14 @@ function StatusTimelineReadout({
7828
7951
  } catch {
7829
7952
  }
7830
7953
  }
7954
+ const \u5F15\u304F = use\u5B57\u5F15();
7831
7955
  const colorLookup = new Map(colorMap.map((c) => [c.status.toLowerCase(), c.color]));
7832
7956
  const shown = events.slice(0, max);
7833
7957
  const stripHeight = 28;
7834
7958
  const width = 320;
7835
7959
  const cellW = shown.length > 0 ? (width - 20) / shown.length : 0;
7836
7960
  const height = stripHeight + 40;
7961
+ const \u533A\u9593\u306E\u5B57 = (status) => status === "active" || status === "idle" || status === "error" ? \u5F15\u304F(`readout.statusTimeline.${status}`) : status.toUpperCase();
7837
7962
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cdl-ip-item cdl-ip-readout-status-timeline", "data-cdl-readout": id, children: [
7838
7963
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cdl-ip-label", children: label }),
7839
7964
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -7846,9 +7971,11 @@ function StatusTimelineReadout({
7846
7971
  children: shown.map((ev, i) => {
7847
7972
  const x = 10 + i * cellW;
7848
7973
  const c = colorLookup.get(ev.status) ?? "#cbd5e1";
7849
- return /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-cdl-status-event": i, children: [
7974
+ const \u5B572 = \u533A\u9593\u306E\u5B57(ev.status);
7975
+ const \u63CF\u304F\u5B57 = \u5E45\u3067\u5207\u308B(\u5B572, 10, cellW - 8);
7976
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-cdl-status-event": i, "data-cdl-status": ev.status, children: [
7850
7977
  /* @__PURE__ */ jsxRuntime.jsx("rect", { x, y: 10, width: cellW - 2, height: stripHeight, fill: c, rx: 2 }),
7851
- /* @__PURE__ */ jsxRuntime.jsx(
7978
+ /* @__PURE__ */ jsxRuntime.jsxs(
7852
7979
  "text",
7853
7980
  {
7854
7981
  x: x + cellW / 2,
@@ -7858,7 +7985,10 @@ function StatusTimelineReadout({
7858
7985
  fill: "#ffffff",
7859
7986
  fontWeight: 600,
7860
7987
  style: { userSelect: "none" },
7861
- children: ev.status.length > 5 ? ev.status.slice(0, 4).toUpperCase() : ev.status.toUpperCase()
7988
+ children: [
7989
+ \u63CF\u304F\u5B57 !== \u5B572 ? /* @__PURE__ */ jsxRuntime.jsx("title", { children: \u5B572 }) : null,
7990
+ \u63CF\u304F\u5B57
7991
+ ]
7862
7992
  }
7863
7993
  ),
7864
7994
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8176,6 +8306,8 @@ function UserPresenceReadout({
8176
8306
  const width = 260;
8177
8307
  const height = shown.length * rowH + (overflow > 0 ? 20 : 0) + 8;
8178
8308
  const statusColor = (s) => s === "online" ? "#22c55e" : s === "away" ? "#eab308" : "#94a3b8";
8309
+ const \u5F15\u304F = use\u5B57\u5F15();
8310
+ const \u72B6\u614B\u306E\u5B57 = (s) => s === "online" || s === "away" || s === "offline" ? \u5F15\u304F(`readout.presence.${s}`) : s;
8179
8311
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cdl-ip-item cdl-ip-readout-user-presence", "data-cdl-readout": id, children: [
8180
8312
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cdl-ip-label", children: label }),
8181
8313
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -8188,7 +8320,7 @@ function UserPresenceReadout({
8188
8320
  children: [
8189
8321
  shown.map((u, i) => {
8190
8322
  const y = 4 + i * rowH;
8191
- return /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-cdl-presence-user": i, children: [
8323
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-cdl-presence-user": i, "data-cdl-presence-status": u.status, children: [
8192
8324
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 12, cy: y + rowH / 2, r: 6, fill: statusColor(u.status) }),
8193
8325
  /* @__PURE__ */ jsxRuntime.jsx(
8194
8326
  "text",
@@ -8211,7 +8343,7 @@ function UserPresenceReadout({
8211
8343
  textAnchor: "end",
8212
8344
  fill: "#64748b",
8213
8345
  style: { userSelect: "none" },
8214
- children: u.status
8346
+ children: \u72B6\u614B\u306E\u5B57(u.status)
8215
8347
  }
8216
8348
  )
8217
8349
  ] }, i);
@@ -14288,8 +14420,8 @@ var TITLE_RATIO = 0.17;
14288
14420
  var SUB_RATIO = 0.72;
14289
14421
  var LINE_GAP = 3;
14290
14422
  var BOTTOM_PAD = 4;
14291
- var ASCENT = 0.72;
14292
- var DESCENT = 0.25;
14423
+ var ASCENT2 = 0.72;
14424
+ var DESCENT2 = 0.25;
14293
14425
  var ART_GAP = 4;
14294
14426
  var ART_MIN_BAND = 45;
14295
14427
  var \u843D\u3068\u3057\u3066\u3082\u63CF\u304F\u7A2E\u5225 = {
@@ -14347,9 +14479,9 @@ function labelPlan(node) {
14347
14479
  y -= \u540D\u524D\u5927 + LINE_GAP;
14348
14480
  const \u80A9\u66F8 = \u80A9\u66F8\u3042\u308A2 ? { y, size: \u5C0F\u3055\u3044\u5B57 } : null;
14349
14481
  const \u4E0A\u306E\u884C = \u80A9\u66F8 ?? \u540D\u524D;
14350
- return { \u540D\u524D, \u8AAC\u660E, \u80A9\u66F8, \u4E0A\u7AEF: \u4E0A\u306E\u884C.y - \u4E0A\u306E\u884C.size * ASCENT };
14482
+ return { \u540D\u524D, \u8AAC\u660E, \u80A9\u66F8, \u4E0A\u7AEF: \u4E0A\u306E\u884C.y - \u4E0A\u306E\u884C.size * ASCENT2 };
14351
14483
  };
14352
- const \u5165\u308B = (\u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2) => \u7A4D\u3080(1, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, 1 * DESCENT).\u4E0A\u7AEF >= \u5929;
14484
+ const \u5165\u308B = (\u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2) => \u7A4D\u3080(1, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, 1 * DESCENT2).\u4E0A\u7AEF >= \u5929;
14353
14485
  let \u8AAC\u660E\u3042\u308A = Boolean(node.subtitle);
14354
14486
  let \u80A9\u66F8\u3042\u308A = Boolean(node.eyebrow);
14355
14487
  const \u843D\u3068\u3057\u305F = [];
@@ -14367,14 +14499,14 @@ function labelPlan(node) {
14367
14499
  for (let size = \u4E0A\u9650; size >= 1; size--) {
14368
14500
  const \u5C0F\u3055\u3044\u5B572 = Math.max(1, Math.round(size * SUB_RATIO));
14369
14501
  const \u4E0B\u306E\u884C\u5927 = \u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B572 : size;
14370
- if (\u7A4D\u3080(size, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u306E\u884C\u5927 * DESCENT).\u4E0A\u7AEF >= \u5929) {
14502
+ if (\u7A4D\u3080(size, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u306E\u884C\u5927 * DESCENT2).\u4E0A\u7AEF >= \u5929) {
14371
14503
  \u540D\u524D\u5927 = size;
14372
14504
  break;
14373
14505
  }
14374
14506
  }
14375
- if (\u540D\u524D\u5927 === 0) \u540D\u524D\u5927 = \u9AD8\u3055 / (ASCENT + DESCENT);
14507
+ if (\u540D\u524D\u5927 === 0) \u540D\u524D\u5927 = \u9AD8\u3055 / (ASCENT2 + DESCENT2);
14376
14508
  const \u5C0F\u3055\u3044\u5B57 = Math.max(1, Math.round(\u540D\u524D\u5927 * SUB_RATIO));
14377
- const \u5F35\u308A\u51FA\u3057 = (\u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B57 : \u540D\u524D\u5927) * DESCENT;
14509
+ const \u5F35\u308A\u51FA\u3057 = (\u8AAC\u660E\u3042\u308A2 ? \u5C0F\u3055\u3044\u5B57 : \u540D\u524D\u5927) * DESCENT2;
14378
14510
  const \u4F59\u308A = Math.max(0, \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u5F35\u308A\u51FA\u3057).\u4E0A\u7AEF - \u5929);
14379
14511
  const \u4E0B\u4F59\u767D = Math.min(Math.max(BOTTOM_PAD, \u5F35\u308A\u51FA\u3057), \u5F35\u308A\u51FA\u3057 + \u4F59\u308A);
14380
14512
  return \u7A4D\u3080(\u540D\u524D\u5927, \u8AAC\u660E\u3042\u308A2, \u80A9\u66F8\u3042\u308A2, \u4E0B\u4F59\u767D);
@@ -14464,111 +14596,6 @@ function fitArt(region, extent, art) {
14464
14596
  return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${dx} ${dy}) scale(${s})`, children: art });
14465
14597
  }
14466
14598
 
14467
- // src/kinds/compact-title.ts
14468
- function estimateTextWidth(text, fontSize) {
14469
- let w = 0;
14470
- for (const ch of text) {
14471
- const isFullWidth = /[\u3000-\u9FFF\uFF00-\uFFEF]/.test(ch);
14472
- w += fontSize * (isFullWidth ? 1.05 : 0.62);
14473
- }
14474
- return w;
14475
- }
14476
- function fitTextSize(text, maxWidth, targetSize, minSize) {
14477
- let size = targetSize;
14478
- while (size > minSize && estimateTextWidth(text, size) > maxWidth) {
14479
- size -= 1;
14480
- }
14481
- return size;
14482
- }
14483
- var COMPACT_MAX_H = 100;
14484
- var COMPACT_PADDING_X = 16;
14485
- var MIN_TEXT_SIZE = 11;
14486
- var ASCENT2 = 0.72;
14487
- var DESCENT2 = 0.25;
14488
- var MIN_BAND_H = MIN_TEXT_SIZE * (ASCENT2 + DESCENT2);
14489
- var EYEBROW_BASELINE = 38;
14490
- var EYEBROW_SIZE = 18;
14491
- var EYEBROW_GAP = 8;
14492
- var BOTTOM_INSET = 4;
14493
- var eyebrowBottom = () => EYEBROW_BASELINE + EYEBROW_SIZE * DESCENT2;
14494
- var titleBandTop = (hasEyebrow) => eyebrowBottom() + EYEBROW_GAP ;
14495
- var isCompactBox = (h) => h < COMPACT_MAX_H;
14496
- function titlePlacement(node, \u901A\u5E38, opts = {}) {
14497
- if (!isCompactBox(node.h)) {
14498
- return { x: \u901A\u5E38.x, y: \u901A\u5E38.y, size: \u901A\u5E38.size, anchor: "start" };
14499
- }
14500
- const \u9AD8\u3055 = Math.max(0, node.h);
14501
- const \u76EE\u5370\u3042\u308A = opts.hasEyebrow === true;
14502
- const \u4E0A = \u76EE\u5370\u3042\u308A && \u9AD8\u3055 >= eyebrowBottom() ? titleBandTop() : 0;
14503
- const \u751F\u306E\u5E2F = Math.max(0, \u9AD8\u3055 - \u4E0A);
14504
- const \u4E0B\u4F59\u767D = \u751F\u306E\u5E2F >= MIN_BAND_H + BOTTOM_INSET ? BOTTOM_INSET : 0;
14505
- const \u5E2F = \u751F\u306E\u5E2F - \u4E0B\u4F59\u767D;
14506
- const \u5E45\u3067 = fitTextSize(
14507
- node.title,
14508
- Math.max(0, node.w - COMPACT_PADDING_X),
14509
- \u901A\u5E38.size,
14510
- MIN_TEXT_SIZE
14511
- );
14512
- const \u5E2F\u3067 = Math.floor(\u5E2F / (ASCENT2 + DESCENT2));
14513
- const size = Math.max(MIN_TEXT_SIZE, Math.min(\u5E45\u3067, \u5E2F\u3067));
14514
- const \u5B57\u9AD8 = size * (ASCENT2 + DESCENT2);
14515
- const y = \u5B57\u9AD8 <= \u5E2F ? \u4E0A + \u5E2F / 2 + size * (ASCENT2 - DESCENT2) / 2 : \u4E0A > 0 ? \u4E0A + size * ASCENT2 : (\u9AD8\u3055 - \u5B57\u9AD8) / 2 + size * ASCENT2;
14516
- return { x: node.w / 2, y, size, anchor: "middle" };
14517
- }
14518
-
14519
- // src/kinds/box-lines.ts
14520
- var \u884C\u9001\u308A\u306E\u6BD4 = 1.15;
14521
- var \u5B57\u306E\u9AD8\u3055\u306E\u6BD4 = 0.72;
14522
- var \u4E0A\u4E0B\u306E\u4F59\u767D = 2;
14523
- var \u5DE6\u53F3\u306E\u4F59\u767D = 8;
14524
- function \u4F7F\u3048\u308B\u5E45(\u7BB1\u306E\u5E45) {
14525
- return \u7BB1\u306E\u5E45 - \u5DE6\u53F3\u306E\u4F59\u767D * 2;
14526
- }
14527
- function \u5E45\u3067\u5207\u308B(text, fontSize, \u4F7F\u3048\u308B\u5E452, \u6E2C\u308B = textWidth) {
14528
- if (\u4F7F\u3048\u308B\u5E452 <= 0) return "";
14529
- if (\u6E2C\u308B(text, fontSize) <= \u4F7F\u3048\u308B\u5E452) return text;
14530
- const \u7701\u7565 = "\u2026";
14531
- const \u7701\u7565\u306E\u5E45 = \u6E2C\u308B(\u7701\u7565, fontSize);
14532
- if (\u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E452) return "";
14533
- let \u51FA = "";
14534
- let \u5E45 = 0;
14535
- for (const c of \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text)) {
14536
- const \u5B57\u306E\u5E452 = \u6E2C\u308B(c, fontSize);
14537
- if (\u5E45 + \u5B57\u306E\u5E452 + \u7701\u7565\u306E\u5E45 > \u4F7F\u3048\u308B\u5E452) break;
14538
- \u5E45 += \u5B57\u306E\u5E452;
14539
- \u51FA += c;
14540
- }
14541
- return `${\u51FA}${\u7701\u7565}`;
14542
- }
14543
- var \u7E2E\u3081\u306E\u4E0B\u9650 = MIN_TEXT_SIZE;
14544
- function \u5E45\u306B\u53CE\u3081\u308B(text, fontSize, \u4F7F\u3048\u308B\u5E452, \u6E2C\u308B = textWidth) {
14545
- let size = fontSize;
14546
- while (size > \u7E2E\u3081\u306E\u4E0B\u9650 && \u6E2C\u308B(text, size) > \u4F7F\u3048\u308B\u5E452) size -= 1;
14547
- return { text: \u5E45\u3067\u5207\u308B(text, size, \u4F7F\u3048\u308B\u5E452, \u6E2C\u308B), fontSize: size };
14548
- }
14549
- function \u66F8\u8A18\u7D20\u306B\u5206\u3051\u308B(text) {
14550
- const \u533A\u5207\u308A = Intl.Segmenter;
14551
- if (typeof \u533A\u5207\u308A !== "function") return [...text];
14552
- return [...new \u533A\u5207\u308A(void 0, { granularity: "grapheme" }).segment(text)].map((g) => g.segment);
14553
- }
14554
- function \u7BB1\u306B\u7A4D\u3080(\u884C, \u7BB1\u306E\u5E45, \u7BB1\u306E\u9AD8\u30553) {
14555
- const \u5019\u88DC = \u884C.filter((r, i) => i === 0 || r.text.trim() !== "");
14556
- if (\u5019\u88DC.length === 0) return [];
14557
- const \u4F7F\u3048\u308B\u9AD8\u3055 = \u7BB1\u306E\u9AD8\u30553 - \u4E0A\u4E0B\u306E\u4F59\u767D * 2;
14558
- const \u9AD8\u3055 = (rs) => rs.reduce((a, r) => a + r.fontSize * \u884C\u9001\u308A\u306E\u6BD4, 0);
14559
- const \u6B8B\u3059 = [...\u5019\u88DC];
14560
- while (\u6B8B\u3059.length > 1 && \u9AD8\u3055(\u6B8B\u3059) > \u4F7F\u3048\u308B\u9AD8\u3055) \u6B8B\u3059.pop();
14561
- const \u5E45 = \u4F7F\u3048\u308B\u5E45(\u7BB1\u306E\u5E45);
14562
- const \u53CE\u3081\u305F = \u6B8B\u3059.map((r) => ({ ...r, ...\u5E45\u306B\u53CE\u3081\u308B(r.text, r.fontSize, \u5E45) }));
14563
- const \u7DCF\u9AD8 = \u9AD8\u3055(\u53CE\u3081\u305F);
14564
- let \u7A4D\u307F = -\u7DCF\u9AD8 / 2;
14565
- return \u53CE\u3081\u305F.map((r) => {
14566
- const dy = \u7A4D\u307F + (\u884C\u9001\u308A\u306E\u6BD4 + \u5B57\u306E\u9AD8\u3055\u306E\u6BD4) / 2 * r.fontSize;
14567
- \u7A4D\u307F += r.fontSize * \u884C\u9001\u308A\u306E\u6BD4;
14568
- return { ...r, dy };
14569
- });
14570
- }
14571
-
14572
14599
  // src/render/tone.ts
14573
14600
  var TONE = {
14574
14601
  accent: "var(--cdl-tone-accent, #2d6a8f)",
@@ -23866,7 +23893,7 @@ function CardNode({ node, active }) {
23866
23893
  const textAnchor = compact ? "middle" : "start";
23867
23894
  const subtitleY = 124 - \u305A\u3089\u3057;
23868
23895
  const \u6700\u5927\u306E\u884C\u9001\u308A = SUBTITLE_SIZE * \u884C\u9001\u308A\u306E\u500D\u7387;
23869
- const \u4E8C\u884C\u304C\u5165\u308B = !compact && subtitleY - \u6700\u5927\u306E\u884C\u9001\u308A / 2 - SUBTITLE_SIZE * ASCENT2 > titleY + titleSize * DESCENT2 && subtitleY + \u6700\u5927\u306E\u884C\u9001\u308A / 2 + SUBTITLE_SIZE * DESCENT2 <= node.h - 4;
23896
+ const \u4E8C\u884C\u304C\u5165\u308B = !compact && subtitleY - \u6700\u5927\u306E\u884C\u9001\u308A / 2 - SUBTITLE_SIZE * ASCENT > titleY + titleSize * DESCENT && subtitleY + \u6700\u5927\u306E\u884C\u9001\u308A / 2 + SUBTITLE_SIZE * DESCENT <= node.h - 4;
23870
23897
  const \u8AAC\u660E = node.subtitle ? \u8AAC\u660E\u6587\u3092\u5272\u308A\u4ED8\u3051\u308B(node.subtitle, availableW, { \u4E8C\u884C\u307E\u3067: \u4E8C\u884C\u304C\u5165\u308B }) : void 0;
23871
23898
  const subtitleSize = \u8AAC\u660E?.size ?? 21;
23872
23899
  const \u884C\u9001\u308A = subtitleSize * \u884C\u9001\u308A\u306E\u500D\u7387;
@@ -27678,8 +27705,8 @@ var EYEBROW_TRACKING = 2;
27678
27705
  var SUB_SIZE = 11;
27679
27706
  var SUB_GAP = 4;
27680
27707
  function labelBlock(node, pos, size, band) {
27681
- const \u4E0A = node.eyebrow ? size + EYEBROW_GAP2 + EYEBROW_SIZE2 * ASCENT : size * ASCENT;
27682
- const \u4E0B = node.subtitle ? size + SUB_GAP + SUB_SIZE * DESCENT : size * DESCENT;
27708
+ const \u4E0A = node.eyebrow ? size + EYEBROW_GAP2 + EYEBROW_SIZE2 * ASCENT2 : size * ASCENT2;
27709
+ const \u4E0B = node.subtitle ? size + SUB_GAP + SUB_SIZE * DESCENT2 : size * DESCENT2;
27683
27710
  const \u5E45 = Math.max(
27684
27711
  textWidth(node.title ?? "", size),
27685
27712
  node.eyebrow ? textWidth(node.eyebrow, EYEBROW_SIZE2, EYEBROW_TRACKING) : 0,
@@ -32902,7 +32929,8 @@ var FSM_ACTION_MARK = {
32902
32929
  function stateMachine(preset) {
32903
32930
  const stateW = resolveStateW(preset.stateWidth, "stateMachine");
32904
32931
  const tone = preset.defaultTone ?? "accent";
32905
- const b = diagram(preset.id, { topic: preset.topic, type: "state" });
32932
+ const diagramType = "state";
32933
+ const b = diagram(preset.id, { topic: preset.topic, type: diagramType });
32906
32934
  const phaseActivate = [];
32907
32935
  const stateOrder = /* @__PURE__ */ new Map();
32908
32936
  const \u72B6\u614B = [];
@@ -33003,7 +33031,7 @@ function stateMachine(preset) {
33003
33031
  b.phase(
33004
33032
  "fsm",
33005
33033
  { duration: 2400, title: preset.topic, body: "\u3059\u3079\u3066\u306E\u72B6\u614B\u3068\u9077\u79FB\u3092\u4E26\u3079\u305F\u59FF\u3002" },
33006
- (p) => p.activate(...phaseActivate).badge("fsm")
33034
+ (p) => p.activate(...phaseActivate).badge(diagramType)
33007
33035
  );
33008
33036
  return b.build();
33009
33037
  }
@@ -33262,7 +33290,8 @@ function userJourney(preset) {
33262
33290
  function mindMap(preset) {
33263
33291
  const canvasW = preset.branchWidth ? preset.branchWidth * 2 : 720;
33264
33292
  const canvasH = 480;
33265
- const b = diagram(preset.id, { topic: preset.topic, type: "mindmap" });
33293
+ const diagramType = "mind";
33294
+ const b = diagram(preset.id, { topic: preset.topic, type: diagramType });
33266
33295
  const branches = [];
33267
33296
  const api = {
33268
33297
  branch(br) {
@@ -33296,7 +33325,7 @@ function mindMap(preset) {
33296
33325
  b.phase(
33297
33326
  "mindmap",
33298
33327
  { duration: 2400, title: preset.topic, body: "\u4E2D\u5FC3\u306E\u4E3B\u984C\u304B\u3089\u3001\u3059\u3079\u3066\u306E\u679D\u3092\u653E\u5C04\u72B6\u306B\u5E83\u3052\u305F\u59FF\u3002" },
33299
- (p) => p.activate(nodeId).badge("mindmap")
33328
+ (p) => p.activate(nodeId).badge(diagramType)
33300
33329
  );
33301
33330
  return b.build();
33302
33331
  }
@@ -33629,7 +33658,8 @@ function stateMachine2(preset) {
33629
33658
  const stateW = resolveStateW(preset.stateWidth, "stateMachine2");
33630
33659
  const laneW = boxLaneW(stateW);
33631
33660
  const tone = preset.defaultTone ?? "accent";
33632
- const b = diagram(preset.id, { topic: preset.topic, type: "state" });
33661
+ const diagramType = "state";
33662
+ const b = diagram(preset.id, { topic: preset.topic, type: diagramType });
33633
33663
  const stateOrder = /* @__PURE__ */ new Map();
33634
33664
  const phaseActivate = [];
33635
33665
  let transIdx = 0;
@@ -33685,7 +33715,7 @@ function stateMachine2(preset) {
33685
33715
  title: preset.topic,
33686
33716
  body: "\u5165\u308C\u5B50\u306E\u72B6\u614B\u3068\u3001\u5165\u308B\u6642\u30FB\u51FA\u308B\u6642\u306E\u51E6\u7406\u3092\u542B\u3081\u305F\u3001\u3059\u3079\u3066\u306E\u72B6\u614B\u3068\u9077\u79FB\u3002"
33687
33717
  },
33688
- (p) => p.activate(...phaseActivate).badge("statemachine2")
33718
+ (p) => p.activate(...phaseActivate).badge(diagramType)
33689
33719
  );
33690
33720
  const d = b.build();
33691
33721
  return {