@cardenelabs/dragon 0.13.0 → 0.15.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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NODE_KINDS, TONES, layout, applyDerivedValues, diagram, rendersRows, requiredRowsHeight, requiredRowsWidth, sequence, flow, swimlane, er, stateMachine, topology, parseFormula } from '@cardenelabs/cdl';
1
+ import { NODE_KINDS, TONES, parseFormula, extractIdentifiers, inputDefaultValue, layout, applyDerivedValues, diagram, rendersRows, requiredRowsHeight, requiredRowsWidth, sequence, flow, swimlane, er, stateMachine, topology } from '@cardenelabs/cdl';
2
2
 
3
3
  // src/keywords.ts
4
4
  var HEADERS = {
@@ -1752,6 +1752,135 @@ var \u90E8\u54C1\u306E\u7D44\u306E\u8868 = {
1752
1752
  }
1753
1753
  };
1754
1754
 
1755
+ // src/v05/input-table.generated.ts
1756
+ var \u3064\u307E\u307F\u306E\u8868 = {
1757
+ color: {
1758
+ \u5FC5\u9808: ["defaultValue"],
1759
+ \u6B04: {
1760
+ defaultValue: "\u6587\u5B57\u5217",
1761
+ label: "\u6587\u5B57\u5217"
1762
+ }
1763
+ },
1764
+ datetime: {
1765
+ \u5FC5\u9808: ["defaultValue"],
1766
+ \u6B04: {
1767
+ defaultValue: "\u6587\u5B57\u5217",
1768
+ label: "\u6587\u5B57\u5217"
1769
+ }
1770
+ },
1771
+ dropdown: {
1772
+ \u5FC5\u9808: ["options", "defaultValue"],
1773
+ \u6B04: {
1774
+ options: "\u6587\u5B57\u5217\u306E\u4E26\u3073",
1775
+ defaultValue: "\u6587\u5B57\u5217",
1776
+ label: "\u6587\u5B57\u5217"
1777
+ }
1778
+ },
1779
+ "multi-select": {
1780
+ \u5FC5\u9808: ["options", "defaultValues"],
1781
+ \u6B04: {
1782
+ options: "\u6587\u5B57\u5217\u306E\u4E26\u3073",
1783
+ defaultValues: "\u6587\u5B57\u5217\u306E\u4E26\u3073",
1784
+ label: "\u6587\u5B57\u5217"
1785
+ }
1786
+ },
1787
+ number: {
1788
+ \u5FC5\u9808: ["defaultValue"],
1789
+ \u6B04: {
1790
+ min: "\u6570",
1791
+ max: "\u6570",
1792
+ defaultValue: "\u6570",
1793
+ label: "\u6587\u5B57\u5217"
1794
+ }
1795
+ },
1796
+ radio: {
1797
+ \u5FC5\u9808: ["options", "defaultValue"],
1798
+ \u6B04: {
1799
+ options: "\u6587\u5B57\u5217\u306E\u4E26\u3073",
1800
+ defaultValue: "\u6587\u5B57\u5217",
1801
+ label: "\u6587\u5B57\u5217"
1802
+ }
1803
+ },
1804
+ range: {
1805
+ \u5FC5\u9808: ["min", "max", "defaultLo", "defaultHi"],
1806
+ \u6B04: {
1807
+ min: "\u6570",
1808
+ max: "\u6570",
1809
+ step: "\u6570",
1810
+ defaultLo: "\u6570",
1811
+ defaultHi: "\u6570",
1812
+ label: "\u6587\u5B57\u5217"
1813
+ }
1814
+ },
1815
+ slider: {
1816
+ \u5FC5\u9808: ["min", "max", "defaultValue"],
1817
+ \u6B04: {
1818
+ min: "\u6570",
1819
+ max: "\u6570",
1820
+ step: "\u6570",
1821
+ defaultValue: "\u6570",
1822
+ label: "\u6587\u5B57\u5217"
1823
+ }
1824
+ },
1825
+ stepper: {
1826
+ \u5FC5\u9808: ["defaultValue"],
1827
+ \u6B04: {
1828
+ min: "\u6570",
1829
+ max: "\u6570",
1830
+ step: "\u6570",
1831
+ defaultValue: "\u6570",
1832
+ label: "\u6587\u5B57\u5217"
1833
+ }
1834
+ },
1835
+ tabs: {
1836
+ \u5FC5\u9808: ["options", "defaultValue"],
1837
+ \u6B04: {
1838
+ options: "\u6587\u5B57\u5217\u306E\u4E26\u3073",
1839
+ defaultValue: "\u6587\u5B57\u5217",
1840
+ label: "\u6587\u5B57\u5217"
1841
+ }
1842
+ },
1843
+ text: {
1844
+ \u5FC5\u9808: ["defaultValue"],
1845
+ \u6B04: {
1846
+ defaultValue: "\u6587\u5B57\u5217",
1847
+ placeholder: "\u6587\u5B57\u5217",
1848
+ maxLength: "\u6570",
1849
+ label: "\u6587\u5B57\u5217"
1850
+ }
1851
+ },
1852
+ timeline: {
1853
+ \u5FC5\u9808: ["duration"],
1854
+ \u6B04: {
1855
+ duration: "\u6570",
1856
+ autoplay: "\u771F\u507D",
1857
+ loop: "\u771F\u507D",
1858
+ speeds: "\u6570\u306E\u4E26\u3073",
1859
+ defaultSpeedIdx: "\u6570",
1860
+ label: "\u6587\u5B57\u5217"
1861
+ }
1862
+ },
1863
+ toggle: {
1864
+ \u5FC5\u9808: ["defaultValue"],
1865
+ \u6B04: {
1866
+ defaultValue: "\u771F\u507D",
1867
+ label: "\u6587\u5B57\u5217"
1868
+ }
1869
+ },
1870
+ xypad: {
1871
+ \u5FC5\u9808: ["xMin", "xMax", "yMin", "yMax", "defaultX", "defaultY"],
1872
+ \u6B04: {
1873
+ xMin: "\u6570",
1874
+ xMax: "\u6570",
1875
+ yMin: "\u6570",
1876
+ yMax: "\u6570",
1877
+ defaultX: "\u6570",
1878
+ defaultY: "\u6570",
1879
+ label: "\u6587\u5B57\u5217"
1880
+ }
1881
+ }
1882
+ };
1883
+
1755
1884
  // src/v05/parser.ts
1756
1885
  var EDGE_SIDE_VALUES = ["top", "right", "bottom", "left"];
1757
1886
  var TOP_LEVEL_KEYS = [
@@ -1770,7 +1899,15 @@ var TOP_LEVEL_KEYS = [
1770
1899
  // 2 軸で仕分ける図の軸の名前 (#1251)
1771
1900
  "axes",
1772
1901
  // 値を見せる部品 (#1374)
1773
- "readouts"
1902
+ "readouts",
1903
+ // 読む人が動かすつまみ (#1389)
1904
+ "inputs",
1905
+ // つまみの値から決まる値 (#1391)
1906
+ "formulas",
1907
+ // 押下などの出来事で動く仕掛け (#1393)
1908
+ "events",
1909
+ // 巻き上げに応じて進む値 (#1393)
1910
+ "scrolls"
1774
1911
  ];
1775
1912
  var LANE_ID_ENTRY = /^([\p{L}\p{N}_-]+)\s*:\s*\{([^}]*)\}\s*$/u;
1776
1913
  function \u540D\u524D\u3068\u4E2D\u62EC\u5F27\u306B\u5272\u308B(\u884C) {
@@ -1808,6 +1945,39 @@ function \u540D\u524D\u3068\u4E2D\u62EC\u5F27\u306B\u5272\u308B(\u884C) {
1808
1945
  }
1809
1946
  return void 0;
1810
1947
  }
1948
+ function \u672B\u5C3E\u306E\u4E2D\u62EC\u5F27\u3092\u5207\u308A\u51FA\u3059(rest) {
1949
+ const t = rest.trimEnd();
1950
+ if (!t.endsWith("}")) return void 0;
1951
+ let \u6DF1\u3055 = 0;
1952
+ let \u5F15\u7528 = null;
1953
+ let \u76F4\u524D = null;
1954
+ let \u59CB = -1;
1955
+ for (let i = 0; i < t.length; i += 1) {
1956
+ const c = t[i];
1957
+ if (\u5F15\u7528 !== null) {
1958
+ if (\u5F15\u7528 === '"' && c === "\\" && i + 1 < t.length) {
1959
+ i += 1;
1960
+ continue;
1961
+ }
1962
+ if (c === \u5F15\u7528) \u5F15\u7528 = null;
1963
+ continue;
1964
+ }
1965
+ if ((c === '"' || c === "'") && (\u76F4\u524D === null || ":,{[".includes(\u76F4\u524D))) {
1966
+ \u5F15\u7528 = c;
1967
+ \u76F4\u524D = c;
1968
+ continue;
1969
+ }
1970
+ if (c === "{") {
1971
+ if (\u6DF1\u3055 === 0) \u59CB = i;
1972
+ \u6DF1\u3055 += 1;
1973
+ } else if (c === "}") {
1974
+ \u6DF1\u3055 -= 1;
1975
+ if (\u6DF1\u3055 === 0 && i === t.length - 1) return { \u524D: t.slice(0, \u59CB), \u4E2D\u8EAB: t.slice(\u59CB + 1, i) };
1976
+ }
1977
+ if (!/\s/u.test(c)) \u76F4\u524D = c;
1978
+ }
1979
+ return void 0;
1980
+ }
1811
1981
  function isTopLevelKey(key) {
1812
1982
  return TOP_LEVEL_KEYS.includes(key);
1813
1983
  }
@@ -1901,6 +2071,11 @@ function parseTextDslV05(src) {
1901
2071
  let viewport = void 0;
1902
2072
  let lanesMap = void 0;
1903
2073
  let readoutsList = void 0;
2074
+ let inputsList = void 0;
2075
+ let formulasList = void 0;
2076
+ let eventsList = void 0;
2077
+ let scrollsList = void 0;
2078
+ let scrollLines = /* @__PURE__ */ new Map();
1904
2079
  let groupsMap = void 0;
1905
2080
  let i = 0;
1906
2081
  while (i < lines.length) {
@@ -2160,6 +2335,112 @@ function parseTextDslV05(src) {
2160
2335
  i = next;
2161
2336
  continue;
2162
2337
  }
2338
+ if (head.key === "inputs") {
2339
+ if (head.value !== null && head.value.trim() !== "") {
2340
+ errors.push({
2341
+ line: line.no,
2342
+ message: "inputs \u306F 1 \u884C\u306B\u307E\u3068\u3081\u3066\u66F8\u3051\u306A\u3044",
2343
+ hint: "\u6B21\u306E\u884C\u304B\u3089\u5B57\u4E0B\u3052\u3057\u3066 `value: { kind: slider, min: 0, max: 100, defaultValue: 50 }` \u306E\u5F62\u3067\u4E26\u3079\u308B"
2344
+ });
2345
+ i += 1;
2346
+ continue;
2347
+ }
2348
+ const { items, next } = collectIndentedRaw(lines, i + 1, line.indent);
2349
+ inputsList = [];
2350
+ for (const it of items) {
2351
+ const m = \u540D\u524D\u3068\u4E2D\u62EC\u5F27\u306B\u5272\u308B(it.trimmed);
2352
+ if (m) {
2353
+ const \u8AAD\u3081\u305F = \u3064\u307E\u307F\u3068\u3057\u3066\u8AAD\u3080(m[0], m[1], it.no, errors);
2354
+ if (\u8AAD\u3081\u305F) inputsList.push(\u8AAD\u3081\u305F);
2355
+ } else {
2356
+ errors.push({
2357
+ line: it.no,
2358
+ message: `invalid input entry: "${it.trimmed}"`,
2359
+ hint: "use `id: { kind: slider, min: 0, max: 100, defaultValue: 50 }`"
2360
+ });
2361
+ }
2362
+ }
2363
+ i = next;
2364
+ continue;
2365
+ }
2366
+ if (head.key === "formulas") {
2367
+ if (head.value !== null && head.value.trim() !== "") {
2368
+ errors.push({
2369
+ line: line.no,
2370
+ message: "formulas \u306F 1 \u884C\u306B\u307E\u3068\u3081\u3066\u66F8\u3051\u306A\u3044",
2371
+ hint: '\u5F0F\u306B `,` \u304C\u5165\u308B\u305F\u3081\u3002 \u6B21\u306E\u884C\u304B\u3089\u5B57\u4E0B\u3052\u3057\u3066 `doubled: "input * 2"` \u306E\u5F62\u3067\u4E26\u3079\u308B'
2372
+ });
2373
+ i += 1;
2374
+ continue;
2375
+ }
2376
+ const { items, next } = collectIndentedRaw(lines, i + 1, line.indent);
2377
+ formulasList = [];
2378
+ for (const it of items) {
2379
+ const f = \u5F0F\u3068\u3057\u3066\u8AAD\u3080(it.trimmed.replace(/^-\s*/, ""), it.no, errors);
2380
+ if (f) formulasList.push(f);
2381
+ }
2382
+ i = next;
2383
+ continue;
2384
+ }
2385
+ if (head.key === "events") {
2386
+ if (head.value !== null && head.value.trim() !== "") {
2387
+ errors.push({
2388
+ line: line.no,
2389
+ message: "events \u306F 1 \u884C\u306B\u307E\u3068\u3081\u3066\u66F8\u3051\u306A\u3044",
2390
+ hint: "\u6B21\u306E\u884C\u304B\u3089\u5B57\u4E0B\u3052\u3057\u3066 `- { on: click, box: Button, handler: toggle }` \u306E\u5F62\u3067\u4E26\u3079\u308B"
2391
+ });
2392
+ i += 1;
2393
+ continue;
2394
+ }
2395
+ const { items, next } = collectIndentedRaw(lines, i + 1, line.indent);
2396
+ eventsList = [];
2397
+ for (const it of items) {
2398
+ const e = \u51FA\u6765\u4E8B\u3068\u3057\u3066\u8AAD\u3080(it.trimmed.replace(/^-\s*/, ""), it.no, errors);
2399
+ if (e) eventsList.push(e);
2400
+ }
2401
+ i = next;
2402
+ continue;
2403
+ }
2404
+ if (head.key === "scrolls") {
2405
+ if (head.value !== null && head.value.trim() !== "") {
2406
+ errors.push({
2407
+ line: line.no,
2408
+ message: "scrolls \u306F 1 \u884C\u306B\u307E\u3068\u3081\u3066\u66F8\u3051\u306A\u3044",
2409
+ hint: "\u6B21\u306E\u884C\u304B\u3089\u5B57\u4E0B\u3052\u3057\u3066 `intro: { start: 0.9, end: 0.1 }` \u306E\u5F62\u3067\u4E26\u3079\u308B"
2410
+ });
2411
+ i += 1;
2412
+ continue;
2413
+ }
2414
+ const { items, next } = collectIndentedRaw(lines, i + 1, line.indent);
2415
+ scrollsList = [];
2416
+ scrollLines = /* @__PURE__ */ new Map();
2417
+ for (const it of items) {
2418
+ const m = \u540D\u524D\u3068\u4E2D\u62EC\u5F27\u306B\u5272\u308B(it.trimmed);
2419
+ if (m) {
2420
+ const \u8AAD\u3081\u305F = \u5DFB\u304D\u4E0A\u3052\u3068\u3057\u3066\u8AAD\u3080(m[0], m[1], it.no, errors);
2421
+ if (\u8AAD\u3081\u305F) {
2422
+ if (scrollLines.has(\u8AAD\u3081\u305F.id)) {
2423
+ errors.push({
2424
+ line: it.no,
2425
+ message: `\u5DFB\u304D\u4E0A\u3052\u306E\u540D\u524D "${\u8AAD\u3081\u305F.id}" \u304C\u91CD\u8907\u3057\u3066\u3044\u307E\u3059`,
2426
+ hint: "scrolls \u306E\u540D\u524D\u306F 1 \u5EA6\u3060\u3051\u66F8\u304F"
2427
+ });
2428
+ } else {
2429
+ scrollsList.push(\u8AAD\u3081\u305F);
2430
+ scrollLines.set(\u8AAD\u3081\u305F.id, it.no);
2431
+ }
2432
+ }
2433
+ } else {
2434
+ errors.push({
2435
+ line: it.no,
2436
+ message: `invalid scroll entry: "${it.trimmed}"`,
2437
+ hint: "use `id: { start: 0.9, end: 0.1, scrub: 1 }`"
2438
+ });
2439
+ }
2440
+ }
2441
+ i = next;
2442
+ continue;
2443
+ }
2163
2444
  if (head.key === "groups") {
2164
2445
  const { items, next } = collectIndentedList(lines, i + 1, line.indent);
2165
2446
  groupsMap = {};
@@ -2196,6 +2477,18 @@ function parseTextDslV05(src) {
2196
2477
  message: "type is required",
2197
2478
  hint: "add `type: sequence|flow|swimlane|er|state|topology|solidity|gantt|class|pie|c4|mind`"
2198
2479
  });
2480
+ const \u65E2\u306B\u5024\u3092\u4F5C\u308B\u540D\u524D = /* @__PURE__ */ new Set([
2481
+ ...(inputsList ?? []).map((input) => input.id),
2482
+ ...(formulasList ?? []).map((formula) => formula.id)
2483
+ ]);
2484
+ for (const scroll of scrollsList ?? []) {
2485
+ if (!\u65E2\u306B\u5024\u3092\u4F5C\u308B\u540D\u524D.has(scroll.id)) continue;
2486
+ errors.push({
2487
+ line: scrollLines.get(scroll.id) ?? 1,
2488
+ message: `\u5DFB\u304D\u4E0A\u3052\u306E\u540D\u524D "${scroll.id}" \u304C inputs \u307E\u305F\u306F formulas \u3068\u91CD\u306A\u3063\u3066\u3044\u307E\u3059`,
2489
+ hint: "inputs / formulas / scrolls \u3067\u306F\u91CD\u306A\u3089\u306A\u3044\u540D\u524D\u3092\u4F7F\u3046"
2490
+ });
2491
+ }
2199
2492
  if (errors.length > 0) return { ok: false, errors };
2200
2493
  return {
2201
2494
  ok: true,
@@ -2211,6 +2504,10 @@ function parseTextDslV05(src) {
2211
2504
  viewport,
2212
2505
  lanes: lanesMap,
2213
2506
  readouts: readoutsList,
2507
+ inputs: inputsList,
2508
+ formulas: formulasList,
2509
+ events: eventsList,
2510
+ scrolls: scrollsList,
2214
2511
  groups: groupsMap,
2215
2512
  pos: { line: 1 }
2216
2513
  }
@@ -2563,6 +2860,18 @@ function \u8868\u306B\u5F93\u3063\u3066\u8AAD\u3080(\u5B9A\u7FA9, opts, \u63A5\u
2563
2860
  out[\u6B04] = n !== void 0 ? n : \u5024;
2564
2861
  } else if (\u5F62 === "\u6587\u5B57\u5217\u306E\u4E26\u3073") {
2565
2862
  out[\u6B04] = \u4E26\u3073\u3068\u3057\u3066\u8AAD\u3080(\u5024);
2863
+ } else if (\u5F62 === "\u6570\u306E\u4E26\u3073") {
2864
+ const \u751F = \u4E26\u3073\u3068\u3057\u3066\u8AAD\u3080(\u5024);
2865
+ const \u6570 = \u751F.map((x) => numberOrUndef(x));
2866
+ if (\u6570.some((n) => n === void 0)) {
2867
+ errors.push({
2868
+ line,
2869
+ message: `${\u63A5\u982D}${\u6B04} \u306B\u6570\u3067\u306A\u3044\u5024\u304C\u3042\u308A\u307E\u3059: "${\u5024}"`,
2870
+ hint: "`[0.5, 1, 2, 4]` \u306E\u5F62\u3067\u6570\u3060\u3051\u3092\u4E26\u3079\u308B"
2871
+ });
2872
+ } else {
2873
+ out[\u6B04] = \u6570;
2874
+ }
2566
2875
  } else if (\u5F62 === "\u7D44\u306E\u4E26\u3073") {
2567
2876
  const \u7D44 = \u7D44\u306E\u4E26\u3073\u3068\u3057\u3066\u8AAD\u3080(\u5024);
2568
2877
  if (\u7D44 !== void 0) out[\u6B04] = \u7D44;
@@ -2619,11 +2928,49 @@ function \u51FA\u3059\u6761\u4EF6\u3068\u3057\u3066\u8AAD\u3080(raw, line, error
2619
2928
  }
2620
2929
  return \u5024;
2621
2930
  }
2931
+ function \u5024\u306B\u8FFD\u968F\u3059\u308B\u6B04\u3068\u3057\u3066\u8AAD\u3080(raw, \u63A5\u982D, line, errors) {
2932
+ if (raw === void 0) return void 0;
2933
+ const \u5024 = raw.trim();
2934
+ if (\u5024 === "") {
2935
+ errors.push({
2936
+ line,
2937
+ message: `${\u63A5\u982D}\u304C\u7A7A\u3067\u3059`,
2938
+ hint: '`{\u72B6\u614B\u306E\u540D\u524D}` \u304B\u6570\u3092\u66F8\u304F (\u4F8B `opacity: "{fade}"` / `opacity: 0.5`)'
2939
+ });
2940
+ return void 0;
2941
+ }
2942
+ const n = numberOrUndef(\u5024);
2943
+ return n !== void 0 ? n : \u5024;
2944
+ }
2945
+ function \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(raw, \u63A5\u982D, line, errors) {
2946
+ if (raw === void 0) return void 0;
2947
+ const \u5024 = raw.trim();
2948
+ if (\u5024 === "") {
2949
+ errors.push({
2950
+ line,
2951
+ message: `${\u63A5\u982D}\u304C\u7A7A\u3067\u3059`,
2952
+ hint: '`{\u72B6\u614B\u306E\u540D\u524D}` \u3092\u66F8\u304F (\u4F8B `wBind: "{barW}"`)'
2953
+ });
2954
+ return void 0;
2955
+ }
2956
+ return \u5024;
2957
+ }
2958
+ var \u5024\u306B\u8FFD\u968F\u3059\u308B\u7BB1\u306E\u6B04 = [
2959
+ "wBind",
2960
+ "hBind",
2961
+ "opacity",
2962
+ "renderOffsetX",
2963
+ "renderOffsetY"
2964
+ ];
2965
+ var \u7A7A\u3092\u77E5\u3089\u305B\u308B\u7BB1\u306E\u6B04 = new Set(\u5024\u306B\u8FFD\u968F\u3059\u308B\u7BB1\u306E\u6B04);
2966
+ function \u8868\u304B\u3089\u5B9A\u7FA9\u3092\u5F15\u304F(\u8868, kind) {
2967
+ return Object.hasOwn(\u8868, kind) ? \u8868[kind] : void 0;
2968
+ }
2622
2969
  function \u56F3\u5F62\u3068\u3057\u3066\u8AAD\u3080(raw, line, errors) {
2623
2970
  const \u4E2D\u8EAB = raw.trim().replace(/^\{|\}$/g, "");
2624
2971
  const opts = parseInlineMapping(\u4E2D\u8EAB);
2625
2972
  const kind = (opts.kind ?? "").toLowerCase();
2626
- const \u5B9A\u7FA9 = \u56F3\u5F62\u306E\u8868[kind];
2973
+ const \u5B9A\u7FA9 = \u8868\u304B\u3089\u5B9A\u7FA9\u3092\u5F15\u304F(\u56F3\u5F62\u306E\u8868, kind);
2627
2974
  if (\u5B9A\u7FA9 === void 0) {
2628
2975
  errors.push({
2629
2976
  line,
@@ -2639,7 +2986,7 @@ function \u56F3\u5F62\u3068\u3057\u3066\u8AAD\u3080(raw, line, errors) {
2639
2986
  function \u90E8\u54C1\u3068\u3057\u3066\u8AAD\u3080(id, raw, line, errors) {
2640
2987
  const opts = parseInlineMapping(raw);
2641
2988
  const kind = (opts.kind ?? "").toLowerCase();
2642
- const \u5B9A\u7FA9 = \u90E8\u54C1\u306E\u8868[kind];
2989
+ const \u5B9A\u7FA9 = \u8868\u304B\u3089\u5B9A\u7FA9\u3092\u5F15\u304F(\u90E8\u54C1\u306E\u8868, kind);
2643
2990
  if (\u5B9A\u7FA9 === void 0) {
2644
2991
  errors.push({
2645
2992
  line,
@@ -2653,6 +3000,194 @@ function \u90E8\u54C1\u3068\u3057\u3066\u8AAD\u3080(id, raw, line, errors) {
2653
3000
  for (const \u6B04 of \u5B9A\u7FA9.\u5FC5\u9808) if (\u8AAD\u3081\u305F[\u6B04] === void 0) return void 0;
2654
3001
  return { id, kind, ...\u8AAD\u3081\u305F };
2655
3002
  }
3003
+ var EVENT_KINDS = [
3004
+ "click",
3005
+ "hover",
3006
+ "double-click",
3007
+ "long-press",
3008
+ "drag",
3009
+ "drop",
3010
+ "keydown",
3011
+ "focus",
3012
+ "blur"
3013
+ ];
3014
+ var EVENT_TARGET_KEYS = ["box", "lane", "arrow", "diagram"];
3015
+ function \u51FA\u6765\u4E8B\u3068\u3057\u3066\u8AAD\u3080(raw, line, errors) {
3016
+ const t = raw.trim();
3017
+ if (!t.startsWith("{") || !t.endsWith("}")) {
3018
+ errors.push({
3019
+ line,
3020
+ message: `\u51FA\u6765\u4E8B\u306E\u884C\u304C\u8AAD\u3081\u307E\u305B\u3093: "${t}"`,
3021
+ hint: "`- { on: click, box: Button, handler: toggle }` \u306E\u5F62\u3067\u66F8\u304F"
3022
+ });
3023
+ return void 0;
3024
+ }
3025
+ const opts = parseInlineMapping(t.slice(1, -1));
3026
+ for (const k of Object.keys(opts)) {
3027
+ if (k === "on" || k === "handler" || EVENT_TARGET_KEYS.includes(k))
3028
+ continue;
3029
+ errors.push({
3030
+ line,
3031
+ message: `\u51FA\u6765\u4E8B\u306E\u9805\u76EE\u540D\u304C\u8AAD\u3081\u307E\u305B\u3093: "${k}"`,
3032
+ hint: `\u4F7F\u3048\u308B\u9805\u76EE = on, handler, ${EVENT_TARGET_KEYS.join(", ")}`
3033
+ });
3034
+ return void 0;
3035
+ }
3036
+ const on = opts.on ?? "";
3037
+ if (!EVENT_KINDS.includes(on)) {
3038
+ errors.push({
3039
+ line,
3040
+ message: `\u51FA\u6765\u4E8B\u306E\u7A2E\u985E\u304C\u8AAD\u3081\u307E\u305B\u3093: "${on}"`,
3041
+ hint: `\u4F7F\u3048\u308B\u7A2E\u985E = ${EVENT_KINDS.join(", ")}`
3042
+ });
3043
+ return void 0;
3044
+ }
3045
+ const handlerId = (opts.handler ?? "").trim();
3046
+ if (handlerId === "") {
3047
+ errors.push({
3048
+ line,
3049
+ message: "\u51FA\u6765\u4E8B\u306E handler \u304C\u7A7A\u3067\u3059",
3050
+ hint: "`handler: toggle-active` \u306E\u3088\u3046\u306B\u3001\u547C\u3073\u51FA\u3059\u4ED5\u639B\u3051\u306E\u540D\u524D\u3092\u66F8\u304F"
3051
+ });
3052
+ return void 0;
3053
+ }
3054
+ const \u66F8\u3044\u305F\u76F8\u624B = EVENT_TARGET_KEYS.filter((k) => opts[k] !== void 0);
3055
+ if (\u66F8\u3044\u305F\u76F8\u624B.length !== 1) {
3056
+ errors.push({
3057
+ line,
3058
+ message: \u66F8\u3044\u305F\u76F8\u624B.length === 0 ? "\u51FA\u6765\u4E8B\u306E\u76F8\u624B\u304C\u66F8\u304B\u308C\u3066\u3044\u307E\u305B\u3093" : `\u51FA\u6765\u4E8B\u306E\u76F8\u624B\u3092 2 \u3064\u4EE5\u4E0A\u66F8\u3044\u3066\u3044\u307E\u3059: ${\u66F8\u3044\u305F\u76F8\u624B.join(", ")}`,
3059
+ hint: `${EVENT_TARGET_KEYS.join(" / ")} \u306E\u3069\u308C\u304B 1 \u3064\u3060\u3051\u3092\u66F8\u304F`
3060
+ });
3061
+ return void 0;
3062
+ }
3063
+ const \u9375 = \u66F8\u3044\u305F\u76F8\u624B[0];
3064
+ const \u5024 = (opts[\u9375] ?? "").trim();
3065
+ let target;
3066
+ if (\u9375 === "diagram") {
3067
+ if (\u5024 !== "true") {
3068
+ errors.push({
3069
+ line,
3070
+ message: `\u51FA\u6765\u4E8B\u306E diagram \u304C\u8AAD\u3081\u307E\u305B\u3093: "${\u5024}"`,
3071
+ hint: "\u56F3\u5168\u4F53\u3092\u6307\u3059\u6642\u306F `diagram: true` \u3068\u66F8\u304F"
3072
+ });
3073
+ return void 0;
3074
+ }
3075
+ target = { kind: "diagram" };
3076
+ } else if (\u9375 === "arrow") {
3077
+ const m = \u5024.split("->");
3078
+ if (m.length !== 2 || m[0].trim() === "" || m[1].trim() === "") {
3079
+ errors.push({
3080
+ line,
3081
+ message: `\u51FA\u6765\u4E8B\u306E\u77E2\u5370\u304C\u8AAD\u3081\u307E\u305B\u3093: "${\u5024}"`,
3082
+ hint: "`arrow: A -> B` \u306E\u5F62\u3067\u3001\u77E2\u5370\u306E\u4E21\u7AEF\u306E\u540D\u524D\u3092\u66F8\u304F"
3083
+ });
3084
+ return void 0;
3085
+ }
3086
+ target = { kind: "edge", from: stripQuotes(m[0].trim()), to: stripQuotes(m[1].trim()) };
3087
+ } else {
3088
+ if (\u5024 === "") {
3089
+ errors.push({
3090
+ line,
3091
+ message: `\u51FA\u6765\u4E8B\u306E ${\u9375} \u304C\u7A7A\u3067\u3059`,
3092
+ hint: "\u6307\u3059\u76F8\u624B\u306E\u540D\u524D\u3092\u66F8\u304F"
3093
+ });
3094
+ return void 0;
3095
+ }
3096
+ target = { kind: \u9375 === "box" ? "node" : "lane", name: stripQuotes(\u5024) };
3097
+ }
3098
+ return { event: on, target, handlerId, pos: { line } };
3099
+ }
3100
+ var SCROLL_VALUE_KINDS = {
3101
+ start: "\u6570",
3102
+ end: "\u6570",
3103
+ scrub: "\u6570"
3104
+ };
3105
+ function \u5DFB\u304D\u4E0A\u3052\u3068\u3057\u3066\u8AAD\u3080(id, raw, line, errors) {
3106
+ if (!isValueName(id)) {
3107
+ errors.push({ line, ...valueNameIssue(id) });
3108
+ return void 0;
3109
+ }
3110
+ const opts = parseInlineMapping(raw);
3111
+ const \u4F7F\u3048\u308B = [...Object.keys(SCROLL_VALUE_KINDS), "label"];
3112
+ for (const k of Object.keys(opts)) {
3113
+ if (\u4F7F\u3048\u308B.includes(k)) continue;
3114
+ errors.push({
3115
+ line,
3116
+ message: `\u5DFB\u304D\u4E0A\u3052 ${id} \u306E\u9805\u76EE\u540D\u304C\u8AAD\u3081\u307E\u305B\u3093: "${k}"`,
3117
+ hint: `\u4F7F\u3048\u308B\u9805\u76EE = ${\u4F7F\u3048\u308B.join(", ")}`
3118
+ });
3119
+ return void 0;
3120
+ }
3121
+ const \u6570 = \u8868\u3067\u8AAD\u3080(SCROLL_VALUE_KINDS, opts, `\u5DFB\u304D\u4E0A\u3052 ${id} \u306E `, line, errors);
3122
+ for (const \u6B04 of ["start", "end", "scrub"]) {
3123
+ const \u5024 = \u6570[\u6B04];
3124
+ if (\u5024 === void 0 || \u5024 >= 0 && \u5024 <= 1) continue;
3125
+ errors.push({
3126
+ line,
3127
+ message: `\u5DFB\u304D\u4E0A\u3052 ${id} \u306E ${\u6B04} \u306F 0 \u304B\u3089 1 \u306E\u9593\u3067\u66F8\u304D\u307E\u3059: "${\u5024}"`,
3128
+ hint: "0 \u306F\u753B\u9762\u306E\u4E0A\u7AEF\u307E\u305F\u306F\u6BB5\u968E\u7684\u306A\u8FFD\u968F\u30011 \u306F\u4E0B\u7AEF\u307E\u305F\u306F\u9023\u7D9A\u8FFD\u968F"
3129
+ });
3130
+ }
3131
+ return {
3132
+ id,
3133
+ ...\u6570.start !== void 0 ? { start: \u6570.start } : {},
3134
+ ...\u6570.end !== void 0 ? { end: \u6570.end } : {},
3135
+ ...\u6570.scrub !== void 0 ? { scrub: \u6570.scrub } : {},
3136
+ ...opts.label !== void 0 ? { label: opts.label } : {}
3137
+ };
3138
+ }
3139
+ function \u5F0F\u3068\u3057\u3066\u8AAD\u3080(\u884C, line, errors) {
3140
+ const c = \u884C.indexOf(":");
3141
+ if (c < 0) {
3142
+ errors.push({
3143
+ line,
3144
+ message: `\u5F0F\u306E\u884C\u304C\u8AAD\u3081\u307E\u305B\u3093: "${\u884C}"`,
3145
+ hint: '`\u540D\u524D: "\u5F0F"` \u306E\u5F62\u3067\u66F8\u304F (\u4F8B `doubled: "input * 2"`)'
3146
+ });
3147
+ return void 0;
3148
+ }
3149
+ const \u540D\u524D = \u884C.slice(0, c).trim();
3150
+ const \u5F0F = stripQuotes(\u884C.slice(c + 1).trim());
3151
+ if (!isValueName(\u540D\u524D)) {
3152
+ errors.push({ line, ...valueNameIssue(\u540D\u524D) });
3153
+ return void 0;
3154
+ }
3155
+ if (\u5F0F === "") {
3156
+ errors.push({
3157
+ line,
3158
+ message: `\u5F0F "${\u540D\u524D}" \u304C\u7A7A\u3067\u3059`,
3159
+ hint: '`doubled: "input * 2"` \u306E\u3088\u3046\u306B\u5F0F\u3092\u66F8\u304F'
3160
+ });
3161
+ return void 0;
3162
+ }
3163
+ try {
3164
+ parseFormula(\u5F0F);
3165
+ } catch (e) {
3166
+ errors.push({
3167
+ line,
3168
+ message: `\u5F0F "${\u540D\u524D}" \u3092\u8AAD\u3081\u307E\u305B\u3093: ${e.message}`,
3169
+ hint: "\u4F7F\u3048\u308B\u306E\u306F\u56DB\u5247\u3068\u62EC\u5F27\u3001\u6BD4\u8F03\u3001\u4E09\u9805 (`a > 1 ? 2 : 3`)\u3001`Math.min` \u306A\u3069\u306E\u95A2\u6570"
3170
+ });
3171
+ return void 0;
3172
+ }
3173
+ return { id: \u540D\u524D, expression: \u5F0F, pos: { line } };
3174
+ }
3175
+ function \u3064\u307E\u307F\u3068\u3057\u3066\u8AAD\u3080(id, raw, line, errors) {
3176
+ const opts = parseInlineMapping(raw);
3177
+ const kind = (opts.kind ?? "").toLowerCase();
3178
+ const \u5B9A\u7FA9 = \u8868\u304B\u3089\u5B9A\u7FA9\u3092\u5F15\u304F(\u3064\u307E\u307F\u306E\u8868, kind);
3179
+ if (\u5B9A\u7FA9 === void 0) {
3180
+ errors.push({
3181
+ line,
3182
+ message: `\u3064\u307E\u307F\u306E\u7A2E\u985E\u304C\u8AAD\u3081\u307E\u305B\u3093: "${opts.kind ?? ""}"`,
3183
+ hint: `\u4F7F\u3048\u308B\u7A2E\u985E = ${Object.keys(\u3064\u307E\u307F\u306E\u8868).join(", ")}`
3184
+ });
3185
+ return void 0;
3186
+ }
3187
+ const \u8AAD\u3081\u305F = \u8868\u306B\u5F93\u3063\u3066\u8AAD\u3080(\u5B9A\u7FA9, opts, `\u3064\u307E\u307F ${id} \u306E `, line, errors);
3188
+ for (const \u6B04 of \u5B9A\u7FA9.\u5FC5\u9808) if (\u8AAD\u3081\u305F[\u6B04] === void 0) return void 0;
3189
+ return { id, kind, ...\u8AAD\u3081\u305F };
3190
+ }
2656
3191
  var ACTOR_NODE_VALUE_KINDS = {
2657
3192
  posX: "\u6570",
2658
3193
  posY: "\u6570",
@@ -2852,6 +3387,7 @@ function applyContinuationLines(actor, rest, errors) {
2852
3387
  const scaleLines = /* @__PURE__ */ new Map();
2853
3388
  const \u56F3\u7A2E\u3054\u3068\u306E\u6B04 = /* @__PURE__ */ new Map();
2854
3389
  const unknownKeys = [];
3390
+ const \u8FFD\u968F\u3059\u308B\u6B04\u306E\u751F\u5024 = /* @__PURE__ */ new Map();
2855
3391
  for (const ln of rest) {
2856
3392
  const idx = ln.trimmed.indexOf(":");
2857
3393
  if (idx < 0) continue;
@@ -2864,7 +3400,7 @@ function applyContinuationLines(actor, rest, errors) {
2864
3400
  unknownKeys.push({ key, line: ln.no });
2865
3401
  continue;
2866
3402
  }
2867
- if (!raw) continue;
3403
+ if (!raw && !\u7A7A\u3092\u77E5\u3089\u305B\u308B\u7BB1\u306E\u6B04.has(key)) continue;
2868
3404
  if (COLOR_KEYS.has(key)) {
2869
3405
  const { tone, hex } = splitColorValue(raw);
2870
3406
  if (tone) out.tone = tone;
@@ -2903,6 +3439,23 @@ function applyContinuationLines(actor, rest, errors) {
2903
3439
  case "\u984C":
2904
3440
  out.title = stripQuotes(raw);
2905
3441
  break;
3442
+ /*
3443
+ * 値に追随する 5 欄 (#1392)。 日本語の別名は置かない = 描画側の欄名がそのまま
3444
+ * 状態の名前と並ぶ場所なので、英字 1 種に絞って書き方の揺れを作らない。
3445
+ *
3446
+ * **ここでは読まずに書かれた字だけを控える**。 見本 (parts) では同じ名前が状態の
3447
+ * 上書きになり、中括弧の形は生の字を `coerceStateValue` に通す。 ここで先に読むと
3448
+ * `wBind: 120` が中括弧では数、縦に並べると文字列になって書き方で割れる。
3449
+ * 見本かどうかは `kind` で決まり、それが後ろの行に書かれることがあるため、
3450
+ * 全行を読み終えてから振り分ける。
3451
+ */
3452
+ case "wBind":
3453
+ case "hBind":
3454
+ case "opacity":
3455
+ case "renderOffsetX":
3456
+ case "renderOffsetY":
3457
+ \u8FFD\u968F\u3059\u308B\u6B04\u306E\u751F\u5024.set(key, { \u5024: stripQuotes(raw), line: ln.no });
3458
+ break;
2906
3459
  case "rows":
2907
3460
  case "\u884C":
2908
3461
  out.rows = raw.replace(/^\[|\]$/g, "").split(/,(?![^[]*\])/).map((x) => stripQuotes(x.trim())).filter(Boolean);
@@ -2990,9 +3543,20 @@ function applyContinuationLines(actor, rest, errors) {
2990
3543
  else out.end = v;
2991
3544
  }
2992
3545
  if (out.partId !== void 0) {
3546
+ for (const [\u6B04, { \u5024 }] of \u8FFD\u968F\u3059\u308B\u6B04\u306E\u751F\u5024) {
3547
+ state[\u6B04] = coerceStateValue(\u5024);
3548
+ touchedState = true;
3549
+ }
2993
3550
  if (touchedState) out.stateOverride = state;
2994
3551
  return out;
2995
3552
  }
3553
+ for (const [\u6B04, { \u5024, line }] of \u8FFD\u968F\u3059\u308B\u6B04\u306E\u751F\u5024) {
3554
+ if (\u6B04 === "wBind" || \u6B04 === "hBind") {
3555
+ out[\u6B04] = \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(\u5024, `\u7BB1\u306E ${\u6B04} `, line, errors);
3556
+ } else if (\u6B04 === "opacity" || \u6B04 === "renderOffsetX" || \u6B04 === "renderOffsetY") {
3557
+ out[\u6B04] = \u5024\u306B\u8FFD\u968F\u3059\u308B\u6B04\u3068\u3057\u3066\u8AAD\u3080(\u5024, `\u7BB1\u306E ${\u6B04} `, line, errors);
3558
+ }
3559
+ }
2996
3560
  for (const u of unknownKeys) {
2997
3561
  errors.push({
2998
3562
  line: u.line,
@@ -3021,6 +3585,12 @@ var ACTOR_ITEM_KEYS = /* @__PURE__ */ new Set([
3021
3585
  // 箱に出す題 (#1381)
3022
3586
  "title",
3023
3587
  "\u984C",
3588
+ // 値に追随する 5 欄 (#1392)
3589
+ "wBind",
3590
+ "hBind",
3591
+ "opacity",
3592
+ "renderOffsetX",
3593
+ "renderOffsetY",
3024
3594
  "\u4F4D\u7F6E",
3025
3595
  "pos",
3026
3596
  "posX",
@@ -3272,6 +3842,12 @@ var INLINE_ACTOR_KEYS = /* @__PURE__ */ new Set([
3272
3842
  "visibleIf",
3273
3843
  // 箱に出す題 (#1381)。 名前と切り離して書ける
3274
3844
  "title",
3845
+ // 値に追随する 5 欄 (#1392)
3846
+ "wBind",
3847
+ "hBind",
3848
+ "opacity",
3849
+ "renderOffsetX",
3850
+ "renderOffsetY",
3275
3851
  // 倍率は別経路 (`reportScaleOnNonPart`) が知らせる。 ここでも読める扱いにしないと
3276
3852
  // 同じ名前で 2 度知らせることになる
3277
3853
  "scale",
@@ -3279,12 +3855,24 @@ var INLINE_ACTOR_KEYS = /* @__PURE__ */ new Set([
3279
3855
  // 英語が読める欄の日本語別名 (#1301)。 一覧は `INLINE_ACTOR_ALIASES` が持つ
3280
3856
  ...Object.keys(INLINE_ACTOR_ALIASES)
3281
3857
  ]);
3858
+ var EDGE_BIND_INLINE_READERS = {
3859
+ widthBind: (v) => v,
3860
+ strokeBind: (v) => v,
3861
+ dashOffsetBind: (v) => v
3862
+ };
3282
3863
  var FLOW_INLINE_READERS = {
3283
3864
  sub: (v) => v,
3284
3865
  guard: (v) => v,
3285
3866
  cardinality: (v) => v,
3286
3867
  // 矢印がどの辺から出るか (#1385)。 描画側は 4 方向を取り、書かなければ自動で選ぶ
3287
3868
  side: (v) => v !== void 0 && EDGE_SIDE_VALUES.includes(v) ? v : void 0,
3869
+ /*
3870
+ * 矢印を値に追随させる 3 欄 (#1396)。 箱の `wBind` (#1392) と同じく文字列だけを取る。
3871
+ *
3872
+ * ここでは字をそのまま通し、空かどうかは呼出側が知らせる (表の読み手は行番号を
3873
+ * 持たないため、知らせを出せる場所で見る)。
3874
+ */
3875
+ ...EDGE_BIND_INLINE_READERS,
3288
3876
  // 数と真偽の欄は `FLOW_INLINE_VALUE_KINDS` の表が読む (#1306)。 ここでは名前だけを持つ =
3289
3877
  // 読める欄の一覧 (`FLOW_INLINE_KEYS`) は本表から導くため、載せないと欄ごと消える
3290
3878
  labelOffsetX: null,
@@ -3350,6 +3938,13 @@ function parseActor2(line, errors) {
3350
3938
  visibleIf: isPart ? void 0 : \u51FA\u3059\u6761\u4EF6\u3068\u3057\u3066\u8AAD\u3080(opts.visibleIf, line.no, errors),
3351
3939
  // 箱に出す題 (#1381)。 空文字も意味を持つ (題を出さない箱) ため undefined と分ける
3352
3940
  title: isPart ? void 0 : opts.title,
3941
+ // 値に追随する 5 欄 (#1392)。 図形や出す条件と同じく、パーツでは状態の上書きとして
3942
+ // 意味を持つため横取りしない
3943
+ wBind: isPart ? void 0 : \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(opts.wBind, "\u7BB1\u306E wBind ", line.no, errors),
3944
+ hBind: isPart ? void 0 : \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(opts.hBind, "\u7BB1\u306E hBind ", line.no, errors),
3945
+ opacity: isPart ? void 0 : \u5024\u306B\u8FFD\u968F\u3059\u308B\u6B04\u3068\u3057\u3066\u8AAD\u3080(opts.opacity, "\u7BB1\u306E opacity ", line.no, errors),
3946
+ renderOffsetX: isPart ? void 0 : \u5024\u306B\u8FFD\u968F\u3059\u308B\u6B04\u3068\u3057\u3066\u8AAD\u3080(opts.renderOffsetX, "\u7BB1\u306E renderOffsetX ", line.no, errors),
3947
+ renderOffsetY: isPart ? void 0 : \u5024\u306B\u8FFD\u968F\u3059\u308B\u6B04\u3068\u3057\u3066\u8AAD\u3080(opts.renderOffsetY, "\u7BB1\u306E renderOffsetY ", line.no, errors),
3353
3948
  ...\u8868\u3067\u8AAD\u3080(ACTOR_INLINE_VALUE_KINDS, opts, "\u7BB1\u306E ", line.no, errors),
3354
3949
  // parts では `tone` を状態の上書きとして従来から使えるため、 色として横取りしない
3355
3950
  tone: isPart ? void 0 : resolveTone(opts.tone),
@@ -3408,10 +4003,17 @@ function parseFlowStep(line, no, errors) {
3408
4003
  let tone;
3409
4004
  let style;
3410
4005
  const \u4E2D\u62EC\u5F27 = {};
3411
- const mapMatch = rest.match(/\s*\{([^}]*)\}\s*$/);
4006
+ const \u584A = \u672B\u5C3E\u306E\u4E2D\u62EC\u5F27\u3092\u5207\u308A\u51FA\u3059(rest);
3412
4007
  let \u6570\u3068\u771F\u507D;
3413
- if (mapMatch) {
3414
- const opts = parseInlineMapping(mapMatch[1]);
4008
+ if (\u584A) {
4009
+ const opts = parseInlineMapping(\u584A.\u4E2D\u8EAB);
4010
+ for (const field of splitInlineFields(\u584A.\u4E2D\u8EAB)) {
4011
+ const idx = field.indexOf(":");
4012
+ if (idx < 0) continue;
4013
+ const key = field.slice(0, idx).trim();
4014
+ if (!Object.hasOwn(EDGE_BIND_INLINE_READERS, key)) continue;
4015
+ opts[key] = stripQuotes(field.slice(idx + 1).trim());
4016
+ }
3415
4017
  for (const k of FLOW_INLINE_KEYS) {
3416
4018
  const \u8AAD\u307F\u624B = FLOW_INLINE_READERS[k];
3417
4019
  if (\u8AAD\u307F\u624B === null) continue;
@@ -3425,12 +4027,30 @@ function parseFlowStep(line, no, errors) {
3425
4027
  });
3426
4028
  }
3427
4029
  \u6570\u3068\u771F\u507D = \u8868\u3067\u8AAD\u3080(FLOW_INLINE_VALUE_KINDS, opts, "\u77E2\u5370\u306E ", line.no, errors);
3428
- rest = rest.slice(0, mapMatch.index ?? 0).trim();
4030
+ rest = \u584A.\u524D.trim();
3429
4031
  }
3430
4032
  const sub = \u4E2D\u62EC\u5F27.sub;
3431
4033
  const guard = \u4E2D\u62EC\u5F27.guard;
3432
4034
  const cardinality = \u4E2D\u62EC\u5F27.cardinality;
3433
4035
  const side = \u4E2D\u62EC\u5F27.side;
4036
+ const widthBind = \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(
4037
+ \u4E2D\u62EC\u5F27.widthBind,
4038
+ "\u77E2\u5370\u306E widthBind ",
4039
+ line.no,
4040
+ errors
4041
+ );
4042
+ const strokeBind = \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(
4043
+ \u4E2D\u62EC\u5F27.strokeBind,
4044
+ "\u77E2\u5370\u306E strokeBind ",
4045
+ line.no,
4046
+ errors
4047
+ );
4048
+ const dashOffsetBind = \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(
4049
+ \u4E2D\u62EC\u5F27.dashOffsetBind,
4050
+ "\u77E2\u5370\u306E dashOffsetBind ",
4051
+ line.no,
4052
+ errors
4053
+ );
3434
4054
  const labelOffsetX = \u6570\u3068\u771F\u507D?.labelOffsetX;
3435
4055
  const labelOffsetY = \u6570\u3068\u771F\u507D?.labelOffsetY;
3436
4056
  const overlay = \u6570\u3068\u771F\u507D?.overlay;
@@ -3482,6 +4102,9 @@ function parseFlowStep(line, no, errors) {
3482
4102
  guard,
3483
4103
  cardinality,
3484
4104
  side,
4105
+ widthBind,
4106
+ strokeBind,
4107
+ dashOffsetBind,
3485
4108
  labelOffsetX,
3486
4109
  labelOffsetY,
3487
4110
  overlay,
@@ -4039,14 +4662,22 @@ var PAINT_KEYS = /* @__PURE__ */ new Set([
4039
4662
  var SAFE_PAINT = "none";
4040
4663
  function stripExternalPaint(diagram2) {
4041
4664
  const stripped = [];
4042
- walk(diagram2, "", false, stripped);
4665
+ walk(diagram2, "", false, stripped, false);
4043
4666
  return stripped;
4044
4667
  }
4045
- function walk(node, path, inStateValue, out) {
4668
+ var INPUT_VALUE_KEYS = /* @__PURE__ */ new Set(["defaultvalue", "defaultvalues", "options"]);
4669
+ function walk(node, path, inStateValue, out, inInputs) {
4046
4670
  if (node === null || typeof node !== "object") return;
4047
4671
  if (Array.isArray(node)) {
4048
4672
  for (let i = 0; i < node.length; i++) {
4049
- walk(node[i], `${path}[${i}]`, inStateValue, out);
4673
+ const here = `${path}[${i}]`;
4674
+ const value = node[i];
4675
+ if (inStateValue && typeof value === "string" && pointsOutside(value)) {
4676
+ node[i] = SAFE_PAINT;
4677
+ out.push({ path: here, value });
4678
+ } else {
4679
+ walk(value, here, inStateValue, out, inInputs);
4680
+ }
4050
4681
  }
4051
4682
  return;
4052
4683
  }
@@ -4054,7 +4685,8 @@ function walk(node, path, inStateValue, out) {
4054
4685
  for (const [key, value] of Object.entries(obj)) {
4055
4686
  const here = path ? `${path}.${key}` : key;
4056
4687
  const lower = key.toLowerCase();
4057
- const nextInState = inStateValue || lower === "states" || lower === "sets" || lower === "tweens";
4688
+ const nextInState = inStateValue || lower === "states" || lower === "sets" || lower === "tweens" || inInputs && INPUT_VALUE_KEYS.has(lower);
4689
+ const nextInInputs = inInputs || lower === "inputs";
4058
4690
  if (typeof value === "string") {
4059
4691
  const isPaint = PAINT_KEYS.has(lower) || nextInState && (lower === "initial" || lower === "to" || lower === "from" || !isReservedStateKey(lower));
4060
4692
  if (isPaint && pointsOutside(value)) {
@@ -4063,7 +4695,7 @@ function walk(node, path, inStateValue, out) {
4063
4695
  }
4064
4696
  continue;
4065
4697
  }
4066
- walk(value, here, nextInState, out);
4698
+ walk(value, here, nextInState, out, nextInInputs);
4067
4699
  }
4068
4700
  }
4069
4701
  function isReservedStateKey(lowerKey) {
@@ -4081,7 +4713,15 @@ function countDocElements(doc) {
4081
4713
  );
4082
4714
  return doc.actors.length + doc.flow.length + phases.length + phaseChildren + (doc.animate?.states.length ?? 0) + (doc.values?.length ?? 0) + // 値を見せる部品も描画時に 1 widget ずつ展開される (#1374)。 数えないと、 actors が
4083
4715
  // 少ないまま readouts だけを大量に並べた入力が組み立て前の上限をすり抜ける。
4084
- (doc.readouts?.length ?? 0) + (doc.groups ? Object.keys(doc.groups).length : 0) + (doc.lanes ? Object.keys(doc.lanes).length : 0);
4716
+ (doc.readouts?.length ?? 0) + // 読む人が動かすつまみも 1 widget ずつ展開される (#1389) readouts と同じ上限で守る。
4717
+ (doc.inputs?.length ?? 0) + /*
4718
+ * 式 (#1391) と、押下 / 巻き上げ (#1393) も数える。
4719
+ *
4720
+ * **図の側 (`countDiagramElements`) は既に数えている**。 記法側だけ数えないと、
4721
+ * 箱が少ないままこれらを大量に並べた入力が組み立て前の上限をすり抜け、
4722
+ * 組み立て終わってから (= 時間をかけてから) 図の側で弾かれる。
4723
+ */
4724
+ (doc.formulas?.length ?? 0) + (doc.events?.length ?? 0) + (doc.scrolls?.length ?? 0) + (doc.groups ? Object.keys(doc.groups).length : 0) + (doc.lanes ? Object.keys(doc.lanes).length : 0);
4085
4725
  }
4086
4726
  function countDiagramElements(diagram2) {
4087
4727
  const phases = Array.isArray(diagram2.phases) ? diagram2.phases : [];
@@ -4112,6 +4752,21 @@ function describeOversizeSource(src) {
4112
4752
  }
4113
4753
 
4114
4754
  // src/compile.ts
4755
+ var \u8A18\u6CD5\u3060\u3051\u306E\u7A2E\u985E\u306E\u8AAD\u307F\u66FF\u3048 = {
4756
+ entity: "storage",
4757
+ state: "card",
4758
+ contract: "card",
4759
+ proxy: "card",
4760
+ library: "card",
4761
+ interface: "card",
4762
+ eoa: "person",
4763
+ multisig: "signer"
4764
+ };
4765
+ function \u63CF\u3051\u308B\u7A2E\u5225(kind) {
4766
+ if (kind === void 0) return "actor";
4767
+ const \u8AAD\u307F\u66FF\u3048\u5148 = \u8A18\u6CD5\u3060\u3051\u306E\u7A2E\u985E\u306E\u8AAD\u307F\u66FF\u3048[kind];
4768
+ return \u8AAD\u307F\u66FF\u3048\u5148 ?? kind;
4769
+ }
4115
4770
  function compileToCdl(doc, opts) {
4116
4771
  const oversize = describeOversize({ elements: countDocElements(doc), bytes: 0 });
4117
4772
  if (oversize) throw new Error(oversize);
@@ -4227,6 +4882,100 @@ function compileToCdl(doc, opts) {
4227
4882
  );
4228
4883
  merged.readouts = [...merged.readouts ?? [], ...ownReadouts];
4229
4884
  }
4885
+ if (doc.inputs && doc.inputs.length > 0) {
4886
+ const ownInputs = doc.inputs.map(
4887
+ (input) => deepRewriteStrings(input, (value) => value)
4888
+ );
4889
+ merged.inputs = [...merged.inputs ?? [], ...ownInputs];
4890
+ }
4891
+ if (doc.formulas && doc.formulas.length > 0) {
4892
+ const ownFormulas = doc.formulas.map((formula) => ({
4893
+ id: formula.id,
4894
+ expression: formula.expression,
4895
+ line: formula.pos?.line ?? 0
4896
+ }));
4897
+ const \u3064\u307E\u307F = new Map((merged.inputs ?? []).map((input) => [input.id, input]));
4898
+ const \u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F = new Set((merged.formulas ?? []).map((formula) => formula.id));
4899
+ const \u8F09\u305B\u308B\u5F0F = [...merged.formulas ?? []];
4900
+ for (const formula of ownFormulas) {
4901
+ if (\u3064\u307E\u307F.has(formula.id) || \u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F.has(formula.id)) {
4902
+ opts?.onNotice?.({
4903
+ kind: "formula-unresolved",
4904
+ actor: formula.id,
4905
+ line: formula.line,
4906
+ message: `\u5F0F "${formula.id}" \u306E\u540D\u524D\u304C\u3001\u5148\u306B\u66F8\u304B\u308C\u305F\u3064\u307E\u307F\u307E\u305F\u306F\u5F0F\u3068\u91CD\u306A\u3063\u3066\u3044\u307E\u3059`,
4907
+ hint: "`inputs:` \u3068 `formulas:` \u3067\u306F\u91CD\u306A\u3089\u306A\u3044\u540D\u524D\u3092\u4F7F\u3046"
4908
+ });
4909
+ continue;
4910
+ }
4911
+ let \u540D\u524D\u305F\u3061;
4912
+ try {
4913
+ \u540D\u524D\u305F\u3061 = extractIdentifiers(parseFormula(formula.expression));
4914
+ } catch {
4915
+ continue;
4916
+ }
4917
+ let \u89E3\u3051\u306A\u3044 = false;
4918
+ for (const \u540D of \u540D\u524D\u305F\u3061) {
4919
+ if (\u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F.has(\u540D)) continue;
4920
+ const input = \u3064\u307E\u307F.get(\u540D);
4921
+ if (input) {
4922
+ const \u521D\u671F\u5024 = inputDefaultValue(input);
4923
+ if (typeof \u521D\u671F\u5024 === "number" || typeof \u521D\u671F\u5024 === "boolean") continue;
4924
+ \u89E3\u3051\u306A\u3044 = true;
4925
+ opts?.onNotice?.({
4926
+ kind: "formula-unresolved",
4927
+ actor: formula.id,
4928
+ line: formula.line,
4929
+ message: `\u5F0F "${formula.id}" \u304C\u3001\u6570\u3067\u3082\u771F\u507D\u3067\u3082\u306A\u3044\u3064\u307E\u307F "${\u540D}" \u3092\u8AAD\u3093\u3067\u3044\u307E\u3059`,
4930
+ hint: "\u5F0F\u304C\u8AAD\u3081\u308B\u3064\u307E\u307F\u306F slider / number / stepper / timeline / toggle"
4931
+ });
4932
+ continue;
4933
+ }
4934
+ \u89E3\u3051\u306A\u3044 = true;
4935
+ opts?.onNotice?.({
4936
+ kind: "formula-unresolved",
4937
+ actor: formula.id,
4938
+ line: formula.line,
4939
+ message: `\u5F0F "${formula.id}" \u304C\u3001\u3064\u307E\u307F\u307E\u305F\u306F\u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F\u3067\u306F\u306A\u3044\u540D\u524D "${\u540D}" \u3092\u8AAD\u3093\u3067\u3044\u307E\u3059`,
4940
+ hint: "`inputs:` \u306B\u66F8\u304F\u304B\u3001\u53C2\u7167\u3055\u308C\u308B\u5F0F\u3092\u3053\u306E\u5F0F\u3088\u308A\u524D\u306B\u66F8\u304F"
4941
+ });
4942
+ }
4943
+ if (\u89E3\u3051\u306A\u3044) continue;
4944
+ \u8F09\u305B\u308B\u5F0F.push({ id: formula.id, expression: formula.expression });
4945
+ \u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F.add(formula.id);
4946
+ }
4947
+ if (\u8F09\u305B\u308B\u5F0F.length > 0) merged.formulas = \u8F09\u305B\u308B\u5F0F;
4948
+ else delete merged.formulas;
4949
+ }
4950
+ if (doc.events && doc.events.length > 0) {
4951
+ const \u8F09\u305B\u308B = [...merged.eventBindings ?? []];
4952
+ for (const e of doc.events) {
4953
+ const \u76F8\u624B = \u51FA\u6765\u4E8B\u306E\u76F8\u624B\u3092\u89E3\u304F(merged, doc, e);
4954
+ if (\u76F8\u624B === void 0) {
4955
+ opts?.onNotice?.({
4956
+ kind: "event-target-missing",
4957
+ actor: e.handlerId,
4958
+ line: e.pos.line,
4959
+ message: `\u51FA\u6765\u4E8B "${e.handlerId}" \u304C\u6307\u3059\u76F8\u624B\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`,
4960
+ hint: "box \u306F\u7BB1\u306E\u540D\u524D\u3001 lane \u306F\u7E26\u5217\u306E\u540D\u524D\u3001 arrow \u306F `A -> B` \u3067\u66F8\u304F"
4961
+ });
4962
+ continue;
4963
+ }
4964
+ \u8F09\u305B\u308B.push({
4965
+ id: `evt-${\u8F09\u305B\u308B.length + 1}`,
4966
+ event: e.event,
4967
+ target: \u76F8\u624B,
4968
+ handlerId: e.handlerId
4969
+ });
4970
+ }
4971
+ if (\u8F09\u305B\u308B.length > 0) merged.eventBindings = \u8F09\u305B\u308B;
4972
+ }
4973
+ if (doc.scrolls && doc.scrolls.length > 0) {
4974
+ merged.scrollTriggers = [
4975
+ ...merged.scrollTriggers ?? [],
4976
+ ...doc.scrolls.map((x) => ({ ...x }))
4977
+ ];
4978
+ }
4230
4979
  const \u5916\u3057\u305F\u90E8\u54C1\u306E\u914D\u8272 = stripExternalReadoutPalettes(merged);
4231
4980
  for (const dropped of [...stripExternalPaint(merged), ...\u5916\u3057\u305F\u90E8\u54C1\u306E\u914D\u8272]) {
4232
4981
  opts?.onNotice?.({
@@ -4561,6 +5310,23 @@ function disambiguateActorIds(doc, onNotice) {
4561
5310
  const from = \u76F4\u3059(s.from);
4562
5311
  const to = \u76F4\u3059(s.to);
4563
5312
  return from === s.from && to === s.to ? s : { ...s, from, to };
5313
+ }),
5314
+ events: doc.events?.map((event) => {
5315
+ const target = event.target;
5316
+ if (target.kind === "node") {
5317
+ const name = \u76F4\u3059(target.name);
5318
+ return name === target.name ? event : { ...event, target: { ...target, name } };
5319
+ }
5320
+ if (target.kind === "edge") {
5321
+ const from = \u76F4\u3059(target.from);
5322
+ const to = \u76F4\u3059(target.to);
5323
+ return from === target.from && to === target.to ? event : { ...event, target: { ...target, from, to } };
5324
+ }
5325
+ if (target.kind === "lane" && (doc.type === "sequence" || doc.type === "solidity")) {
5326
+ const name = \u76F4\u3059(target.name);
5327
+ return name === target.name ? event : { ...event, target: { ...target, name } };
5328
+ }
5329
+ return event;
4564
5330
  })
4565
5331
  };
4566
5332
  if (\u6B21.animate) {
@@ -5602,6 +6368,35 @@ function applyEdgeInlineOptions(diagram2, doc, sourceLines) {
5602
6368
  \u77E2\u5370\u3078\u66F8\u304D\u5199\u3059(target, s, doc);
5603
6369
  });
5604
6370
  }
6371
+ function \u51FA\u6765\u4E8B\u306E\u76F8\u624B\u3092\u89E3\u304F(diagram2, doc, e) {
6372
+ if (e.target.kind === "diagram") return { kind: "diagram" };
6373
+ if (e.target.kind === "edge") {
6374
+ const from = slugify(e.target.from);
6375
+ const to = slugify(e.target.to);
6376
+ let \u77E2\u5370;
6377
+ if (doc.type === "sequence" || doc.type === "solidity") {
6378
+ const stepIdx = doc.flow.findIndex(
6379
+ (step) => slugify(step.from) === from && slugify(step.to) === to
6380
+ );
6381
+ if (stepIdx >= 0) {
6382
+ \u77E2\u5370 = diagram2.edges.find(
6383
+ (x) => (x.from === `s${stepIdx}-${from}` || x.from === from) && (x.to === `s${stepIdx}-${to}` || x.from === x.to)
6384
+ );
6385
+ }
6386
+ } else {
6387
+ \u77E2\u5370 = diagram2.edges.find((x) => x.from === from && x.to === to);
6388
+ }
6389
+ return \u77E2\u5370 ? { kind: "edge", id: \u77E2\u5370.id } : void 0;
6390
+ }
6391
+ const \u540D = e.target.name;
6392
+ const slug = slugify(\u540D);
6393
+ if (e.target.kind === "node") {
6394
+ const \u7BB1 = diagram2.nodes.find((n) => n.id === slug || n.id === \u540D || n.title === \u540D);
6395
+ return \u7BB1 ? { kind: "node", id: \u7BB1.id } : void 0;
6396
+ }
6397
+ const \u5217 = (diagram2.lanes ?? []).find((l) => l.id === slug || l.id === \u540D || l.label === \u540D);
6398
+ return \u5217 ? { kind: "lane", id: \u5217.id } : void 0;
6399
+ }
5605
6400
  function \u77E2\u5370\u3078\u66F8\u304D\u5199\u3059(target, s, doc) {
5606
6401
  if (s.sub !== void 0) target.sub = s.sub;
5607
6402
  if (s.guard !== void 0) {
@@ -5618,6 +6413,9 @@ function \u77E2\u5370\u3078\u66F8\u304D\u5199\u3059(target, s, doc) {
5618
6413
  if (s.labelOffsetX !== void 0) target.labelOffsetX = s.labelOffsetX;
5619
6414
  if (s.labelOffsetY !== void 0) target.labelOffsetY = s.labelOffsetY;
5620
6415
  if (s.overlay !== void 0) target.overlay = s.overlay;
6416
+ if (s.widthBind !== void 0) target.widthBind = s.widthBind;
6417
+ if (s.strokeBind !== void 0) target.strokeBind = s.strokeBind;
6418
+ if (s.dashOffsetBind !== void 0) target.dashOffsetBind = s.dashOffsetBind;
5621
6419
  }
5622
6420
  function \u9396\u3067\u3064\u306A\u3050\u5F62\u304B(doc) {
5623
6421
  if (doc.type !== "flow") return false;
@@ -6787,7 +7585,7 @@ function compileC4(doc) {
6787
7585
  b.node(x.id, {
6788
7586
  lane: lid,
6789
7587
  stack,
6790
- kind: x.actor.kind,
7588
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(x.actor.kind),
6791
7589
  title: x.actor.name
6792
7590
  });
6793
7591
  }
@@ -6832,7 +7630,12 @@ var \u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u306E\u540D\u524D = {
6832
7630
  nodes: "\u4E2D\u306E\u7BB1\u3054\u3068\u306E\u6307\u5B9A",
6833
7631
  layoutPos: "\u914D\u7F6E\u306E\u305A\u3089\u3057",
6834
7632
  shape: "\u7BB1\u306E\u4E2D\u306E\u56F3\u5F62",
6835
- visibleIf: "\u51FA\u3059\u6761\u4EF6"
7633
+ visibleIf: "\u51FA\u3059\u6761\u4EF6",
7634
+ wBind: "\u5024\u306B\u8FFD\u968F\u3059\u308B\u5927\u304D\u3055",
7635
+ hBind: "\u5024\u306B\u8FFD\u968F\u3059\u308B\u5927\u304D\u3055",
7636
+ opacity: "\u6FC3\u3055",
7637
+ renderOffsetX: "\u63CF\u304F\u6642\u306E\u305A\u3089\u3057",
7638
+ renderOffsetY: "\u63CF\u304F\u6642\u306E\u305A\u3089\u3057"
6836
7639
  };
6837
7640
  function \u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u3092\u66F8\u3044\u305F\u304B(a, \u6B04) {
6838
7641
  if (\u6B04 === "kind") return a.kindWritten === true;
@@ -7077,6 +7880,11 @@ function applyV05Extensions(diagram2, doc, \u8FFD\u52A0\u3057\u305F\u7E26\u5217o
7077
7880
  if (footer) footer.visibleIf = a.visibleIf;
7078
7881
  }
7079
7882
  }
7883
+ if (a.wBind !== void 0) node.wBind = a.wBind;
7884
+ if (a.hBind !== void 0) node.hBind = a.hBind;
7885
+ if (a.opacity !== void 0) node.opacity = a.opacity;
7886
+ if (a.renderOffsetX !== void 0) node.renderOffsetX = a.renderOffsetX;
7887
+ if (a.renderOffsetY !== void 0) node.renderOffsetY = a.renderOffsetY;
7080
7888
  }
7081
7889
  }
7082
7890
  alignSeqHeaderHeights(diagram2, doc);
@@ -7361,7 +8169,7 @@ function compileFlow(doc) {
7361
8169
  flowBuilder.step(
7362
8170
  {
7363
8171
  id: slugify(a.name),
7364
- kind: a.kind,
8172
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(a.kind),
7365
8173
  title: \u7BB1\u306E\u984C(a)
7366
8174
  },
7367
8175
  edgeLabel
@@ -7391,7 +8199,7 @@ function compileSwimlane(doc) {
7391
8199
  swim.node(nodeId, {
7392
8200
  lane: laneId,
7393
8201
  stack,
7394
- kind: actor?.kind ?? "actor",
8202
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(actor?.kind),
7395
8203
  title: actorName
7396
8204
  });
7397
8205
  laneStackCount.set(laneId, stack + 1);
@@ -7413,7 +8221,7 @@ function compileSwimlane(doc) {
7413
8221
  swim.node(slugify(a.name), {
7414
8222
  lane: swim.laneId(a.name),
7415
8223
  stack: 0,
7416
- kind: a.kind ?? "actor",
8224
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(a.kind),
7417
8225
  title: \u7BB1\u306E\u984C(a)
7418
8226
  });
7419
8227
  });
@@ -7502,7 +8310,7 @@ function compileTopology(doc) {
7502
8310
  for (const a of doc.actors) {
7503
8311
  groupBuilder.add({
7504
8312
  id: slugify(a.name),
7505
- kind: a.kind,
8313
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(a.kind),
7506
8314
  title: \u7BB1\u306E\u984C(a)
7507
8315
  });
7508
8316
  }
@@ -7535,22 +8343,45 @@ function compileGenericWithAnimate(doc, opts) {
7535
8343
  const { kind, laneWidth } = opts;
7536
8344
  const actorToNodeId = /* @__PURE__ */ new Map();
7537
8345
  if (\u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F(kind, doc)) {
7538
- const \u4E26\u3073 = [];
8346
+ const \u4F7F\u3063\u305F = [];
7539
8347
  for (const a of doc.actors) {
7540
8348
  const lid = a.lane;
7541
- if (lid !== void 0 && !\u4E26\u3073.includes(lid)) \u4E26\u3073.push(lid);
8349
+ if (lid !== void 0 && !\u4F7F\u3063\u305F.includes(lid)) \u4F7F\u3063\u305F.push(lid);
7542
8350
  }
8351
+ const \u66F8\u3044\u305F\u9806 = doc.lanes ? Object.keys(doc.lanes) : [];
8352
+ const \u4E26\u3073 = [
8353
+ ...\u66F8\u3044\u305F\u9806.filter((lid) => \u4F7F\u3063\u305F.includes(lid)),
8354
+ ...\u4F7F\u3063\u305F.filter((lid) => !\u66F8\u3044\u305F\u9806.includes(lid))
8355
+ ];
7543
8356
  for (const lid of \u4E26\u3073) {
7544
8357
  b.lane(lid, { width: laneWidth, ...kind === "topology" ? { contain: true } : {} });
7545
8358
  }
7546
- const \u7A4D\u3093\u3060\u6570 = /* @__PURE__ */ new Map();
8359
+ const \u57CB\u307E\u3063\u305F\u6BB5 = /* @__PURE__ */ new Map();
8360
+ const \u57CB\u3081\u308B = (lid, stack) => {
8361
+ const \u96C6\u5408 = \u57CB\u307E\u3063\u305F\u6BB5.get(lid) ?? /* @__PURE__ */ new Set();
8362
+ \u96C6\u5408.add(stack);
8363
+ \u57CB\u307E\u3063\u305F\u6BB5.set(lid, \u96C6\u5408);
8364
+ };
8365
+ for (const a of doc.actors) {
8366
+ if (a.lane !== void 0 && a.stack !== void 0) \u57CB\u3081\u308B(a.lane, a.stack);
8367
+ }
7547
8368
  doc.actors.forEach((a, idx) => {
7548
8369
  const id = slugify(a.name);
7549
8370
  actorToNodeId.set(a.name, id);
7550
8371
  const lid = a.lane;
7551
- const stack = \u7A4D\u3093\u3060\u6570.get(lid) ?? 0;
7552
- \u7A4D\u3093\u3060\u6570.set(lid, stack + 1);
7553
- b.node(id, { lane: lid, stack, kind: a.kind, title: \u7BB1\u306E\u984C(a) });
8372
+ let stack = a.stack;
8373
+ if (stack === void 0) {
8374
+ stack = 0;
8375
+ const \u96C6\u5408 = \u57CB\u307E\u3063\u305F\u6BB5.get(lid);
8376
+ while (\u96C6\u5408?.has(stack)) stack += 1;
8377
+ \u57CB\u3081\u308B(lid, stack);
8378
+ }
8379
+ b.node(id, {
8380
+ lane: lid,
8381
+ stack,
8382
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(a.kind),
8383
+ title: \u7BB1\u306E\u984C(a)
8384
+ });
7554
8385
  });
7555
8386
  } else if (kind === "flow" || kind === "topology") {
7556
8387
  const lid = opts.laneId ?? "main";
@@ -7562,7 +8393,12 @@ function compileGenericWithAnimate(doc, opts) {
7562
8393
  doc.actors.forEach((a, idx) => {
7563
8394
  const id = slugify(a.name);
7564
8395
  actorToNodeId.set(a.name, id);
7565
- b.node(id, { lane: lid, stack: idx, kind: a.kind, title: \u7BB1\u306E\u984C(a) });
8396
+ b.node(id, {
8397
+ lane: lid,
8398
+ stack: idx,
8399
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(a.kind),
8400
+ title: \u7BB1\u306E\u984C(a)
8401
+ });
7566
8402
  });
7567
8403
  } else {
7568
8404
  const \u898B\u51FA\u3057\u3092\u4ED8\u3051\u308B = kind === "swimlane";
@@ -7577,7 +8413,7 @@ function compileGenericWithAnimate(doc, opts) {
7577
8413
  b.node(id, {
7578
8414
  lane: lid,
7579
8415
  stack: 0,
7580
- kind: a.kind,
8416
+ kind: \u63CF\u3051\u308B\u7A2E\u5225(a.kind),
7581
8417
  title: \u7BB1\u306E\u984C(a),
7582
8418
  ...isInitial ? { eyebrow: "\u521D\u671F" } : {},
7583
8419
  ...isFinal ? { eyebrow: "\u6700\u7D42" } : {}
@@ -8267,8 +9103,6 @@ function \u533A\u9593\u306B\u5E83\u3052\u308B(src, tokens) {
8267
9103
  if (\u4F4D\u7F6E < src.length) out.push({ \u6587\u5B57: src.slice(\u4F4D\u7F6E) });
8268
9104
  return out;
8269
9105
  }
8270
-
8271
- // src/json-parser.ts
8272
9106
  var VALID_KIND_SET = NODE_KIND_VALID;
8273
9107
  var VALID_PRESETS = [...PRESET_TYPES];
8274
9108
  var ACCEPTED_KEYS = {
@@ -8286,7 +9120,14 @@ var ACCEPTED_KEYS = {
8286
9120
  "lanes",
8287
9121
  "groups",
8288
9122
  // 値を見せる部品 (#1374)
8289
- "readouts"
9123
+ "readouts",
9124
+ // 読む人が動かすつまみ (#1389)
9125
+ "inputs",
9126
+ // つまみの値から決まる値 (#1391)
9127
+ "formulas",
9128
+ // 押下などの出来事で動く仕掛けと、巻き上げに応じて進む値 (#1393)
9129
+ "events",
9130
+ "scrolls"
8290
9131
  ],
8291
9132
  actor: [
8292
9133
  "name",
@@ -8318,7 +9159,13 @@ var ACCEPTED_KEYS = {
8318
9159
  // その箱を出すかどうかの条件 (#1381)
8319
9160
  "visibleIf",
8320
9161
  // 箱に出す題 (#1381)
8321
- "title"
9162
+ "title",
9163
+ // 値に追随する 5 欄 (#1392)
9164
+ "wBind",
9165
+ "hBind",
9166
+ "opacity",
9167
+ "renderOffsetX",
9168
+ "renderOffsetY"
8322
9169
  ],
8323
9170
  step: [
8324
9171
  "from",
@@ -8331,6 +9178,10 @@ var ACCEPTED_KEYS = {
8331
9178
  "style",
8332
9179
  "guard",
8333
9180
  "cardinality",
9181
+ // 値に追随する 3 欄 (#1396)
9182
+ "widthBind",
9183
+ "strokeBind",
9184
+ "dashOffsetBind",
8334
9185
  "labelOffsetX",
8335
9186
  "labelOffsetY",
8336
9187
  "overlay",
@@ -8361,7 +9212,14 @@ var \u6B04\u306E\u578B\u8868 = {
8361
9212
  lanes: "object",
8362
9213
  groups: "object",
8363
9214
  // 値を見せる部品 (#1374)。 中身は下の検査が種類ごとに見る
8364
- readouts: "\u4E26\u3073"
9215
+ readouts: "\u4E26\u3073",
9216
+ // 読む人が動かすつまみ (#1389)。 部品と同じく中身は下の検査が種類ごとに見る
9217
+ inputs: "\u4E26\u3073",
9218
+ // つまみの値から決まる値 (#1391)。 中身は下の検査が式ごとに見る
9219
+ formulas: "object",
9220
+ // 押下と巻き上げ (#1393)。 中身は下の検査が 1 件ずつ見る
9221
+ events: "\u4E26\u3073",
9222
+ scrolls: "object"
8365
9223
  },
8366
9224
  actor: {
8367
9225
  name: "\u5FC5\u9808\u306E\u975E\u7A7A\u6587\u5B57\u5217",
@@ -8393,7 +9251,13 @@ var \u6B04\u306E\u578B\u8868 = {
8393
9251
  // その箱を出すかどうかの条件 (#1381)
8394
9252
  visibleIf: "\u6587\u5B57\u5217",
8395
9253
  // 箱に出す題 (#1381)
8396
- title: "\u6587\u5B57\u5217"
9254
+ title: "\u6587\u5B57\u5217",
9255
+ // 値に追随する 5 欄 (#1392)。 大きさは文字列だけ、濃さとずらしは数も受ける
9256
+ wBind: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9257
+ hBind: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9258
+ opacity: "\u6570\u304B\u6587\u5B57\u5217",
9259
+ renderOffsetX: "\u6570\u304B\u6587\u5B57\u5217",
9260
+ renderOffsetY: "\u6570\u304B\u6587\u5B57\u5217"
8397
9261
  },
8398
9262
  step: {
8399
9263
  from: "\u5FC5\u9808\u306E\u6587\u5B57\u5217",
@@ -8406,6 +9270,10 @@ var \u6B04\u306E\u578B\u8868 = {
8406
9270
  style: "\u7DDA\u7A2E",
8407
9271
  guard: "\u6587\u5B57\u5217",
8408
9272
  cardinality: "\u6587\u5B57\u5217",
9273
+ // 値に追随する 3 欄 (#1396)。 描画側は文字列だけを取る
9274
+ widthBind: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9275
+ strokeBind: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9276
+ dashOffsetBind: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
8409
9277
  labelOffsetX: "\u6570",
8410
9278
  labelOffsetY: "\u6570",
8411
9279
  overlay: "\u771F\u507D",
@@ -8466,7 +9334,13 @@ var \u898B\u672C\u306B\u52B9\u304B\u306A\u3044\u6B04 = [
8466
9334
  // その箱を出すかどうかの条件 (#1381)。 見本は自分の出方を持つ
8467
9335
  "visibleIf",
8468
9336
  // 箱に出す題 (#1381)。 見本は自分の題を持つ
8469
- "title"
9337
+ "title",
9338
+ // 値に追随する 5 欄 (#1392)。 見本は自分の大きさと出方を持つ
9339
+ "wBind",
9340
+ "hBind",
9341
+ "opacity",
9342
+ "renderOffsetX",
9343
+ "renderOffsetY"
8470
9344
  ];
8471
9345
  function \u5024\u3092\u691C\u67FB(v, \u578B, path, \u540D\u524D, errors) {
8472
9346
  const \u578B\u9055\u3044 = (\u671F\u5F85, \u88DC\u8DB3) => {
@@ -8485,7 +9359,7 @@ function \u5024\u3092\u691C\u67FB(v, \u578B, path, \u540D\u524D, errors) {
8485
9359
  return;
8486
9360
  case "\u975E\u7A7A\u306E\u6587\u5B57\u5217":
8487
9361
  if (v === void 0) return;
8488
- if (typeof v !== "string" || v.length === 0) \u578B\u9055\u3044("a non-empty string if present");
9362
+ if (typeof v !== "string" || v.trim().length === 0) \u578B\u9055\u3044("a non-empty string if present");
8489
9363
  return;
8490
9364
  case "\u6587\u5B57\u5217":
8491
9365
  if (v === void 0) return;
@@ -8521,6 +9395,19 @@ function \u5024\u3092\u691C\u67FB(v, \u578B, path, \u540D\u524D, errors) {
8521
9395
  \u578B\u9055\u3044("a finite number", typeof v === "number" ? `got ${String(v)}` : void 0);
8522
9396
  }
8523
9397
  return;
9398
+ case "\u6570\u304B\u6587\u5B57\u5217":
9399
+ if (v === void 0) return;
9400
+ if (typeof v === "string") {
9401
+ if (v.trim().length === 0) \u578B\u9055\u3044("a non-empty string if present");
9402
+ return;
9403
+ }
9404
+ if (typeof v !== "number" || !Number.isFinite(v)) {
9405
+ \u578B\u9055\u3044(
9406
+ "a finite number or a non-empty string if present",
9407
+ typeof v === "number" ? `got ${String(v)}` : void 0
9408
+ );
9409
+ }
9410
+ return;
8524
9411
  case "\u771F\u507D":
8525
9412
  if (v === void 0) return;
8526
9413
  if (typeof v !== "boolean") \u578B\u9055\u3044("true or false if present");
@@ -8698,7 +9585,7 @@ function validateViewport(v, errors) {
8698
9585
  }
8699
9586
  function \u8868\u3067\u4E2D\u8EAB\u3092\u691C\u67FB\u3059\u308B(o, \u8868, path, \u4F55, errors) {
8700
9587
  const kind = typeof o.kind === "string" ? o.kind : "";
8701
- const \u5B9A\u7FA9 = \u8868[kind];
9588
+ const \u5B9A\u7FA9 = Object.hasOwn(\u8868, kind) ? \u8868[kind] : void 0;
8702
9589
  if (\u5B9A\u7FA9 === void 0) {
8703
9590
  errors.push({
8704
9591
  path: `${path}.kind`,
@@ -8720,7 +9607,7 @@ function \u8868\u3067\u4E2D\u8EAB\u3092\u691C\u67FB\u3059\u308B(o, \u8868, path,
8720
9607
  });
8721
9608
  continue;
8722
9609
  }
8723
- const \u578B\u304C\u5408\u3046 = \u5F62 === "\u6570" ? typeof \u5024 === "number" && Number.isFinite(\u5024) : \u5F62 === "\u6570\u304B\u6587\u5B57\u5217" ? typeof \u5024 === "number" && Number.isFinite(\u5024) || typeof \u5024 === "string" : \u5F62 === "\u6587\u5B57\u5217\u306E\u4E26\u3073" ? Array.isArray(\u5024) && \u5024.every((x) => typeof x === "string") : \u5F62 === "\u771F\u507D" ? typeof \u5024 === "boolean" : \u5F62 === "\u7D44\u306E\u4E26\u3073" ? Array.isArray(\u5024) && \u5024.length > 0 && \u5024.every(
9610
+ const \u578B\u304C\u5408\u3046 = \u5F62 === "\u6570" ? typeof \u5024 === "number" && Number.isFinite(\u5024) : \u5F62 === "\u6570\u304B\u6587\u5B57\u5217" ? typeof \u5024 === "number" && Number.isFinite(\u5024) || typeof \u5024 === "string" : \u5F62 === "\u6587\u5B57\u5217\u306E\u4E26\u3073" ? Array.isArray(\u5024) && \u5024.every((x) => typeof x === "string") : \u5F62 === "\u6570\u306E\u4E26\u3073" ? Array.isArray(\u5024) && \u5024.every((x) => typeof x === "number" && Number.isFinite(x)) : \u5F62 === "\u771F\u507D" ? typeof \u5024 === "boolean" : \u5F62 === "\u7D44\u306E\u4E26\u3073" ? Array.isArray(\u5024) && \u5024.length > 0 && \u5024.every(
8724
9611
  (x) => typeof x === "object" && x !== null && !Array.isArray(x) && Object.keys(x).length > 0 && Object.values(x).every(
8725
9612
  (y) => typeof y === "string" || typeof y === "number" && Number.isFinite(y)
8726
9613
  )
@@ -8801,6 +9688,238 @@ function validateReadouts(v, errors) {
8801
9688
  }
8802
9689
  });
8803
9690
  }
9691
+ function validateInputs(v, errors) {
9692
+ if (v === void 0) return;
9693
+ if (!Array.isArray(v)) {
9694
+ errors.push({
9695
+ path: "$.inputs",
9696
+ message: "inputs must be an array of input objects",
9697
+ hint: `got ${v === null ? "null" : typeof v}`
9698
+ });
9699
+ return;
9700
+ }
9701
+ v.forEach((r, i) => {
9702
+ const path = `$.inputs[${i}]`;
9703
+ if (!r || typeof r !== "object" || Array.isArray(r)) {
9704
+ errors.push({ path, message: "input must be a plain object", hint: `got ${typeof r}` });
9705
+ return;
9706
+ }
9707
+ const o = r;
9708
+ if (typeof o.id !== "string" || o.id === "") {
9709
+ errors.push({ path: `${path}.id`, message: "id is required", hint: "\u7A7A\u3067\u306A\u3044\u6587\u5B57\u5217\u3067\u66F8\u304F" });
9710
+ }
9711
+ \u8868\u3067\u4E2D\u8EAB\u3092\u691C\u67FB\u3059\u308B(o, \u3064\u307E\u307F\u306E\u8868, path, "input", errors);
9712
+ });
9713
+ }
9714
+ function validateFormulas(v, inputs, errors) {
9715
+ if (v === void 0) return;
9716
+ if (!v || typeof v !== "object" || Array.isArray(v)) {
9717
+ errors.push({
9718
+ path: "$.formulas",
9719
+ message: "formulas must be an object of name to expression",
9720
+ hint: `got ${v === null ? "null" : Array.isArray(v) ? "array" : typeof v}`
9721
+ });
9722
+ return;
9723
+ }
9724
+ const \u3064\u307E\u307F = /* @__PURE__ */ new Map();
9725
+ if (Array.isArray(inputs)) {
9726
+ for (const input of inputs) {
9727
+ if (input && typeof input === "object" && !Array.isArray(input)) {
9728
+ const candidate = input;
9729
+ if (typeof candidate.id === "string" && typeof candidate.kind === "string") {
9730
+ \u3064\u307E\u307F.set(candidate.id, candidate.kind);
9731
+ }
9732
+ }
9733
+ }
9734
+ }
9735
+ const \u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F = /* @__PURE__ */ new Set();
9736
+ for (const [\u540D\u524D, \u5F0F] of Object.entries(v)) {
9737
+ const path = `$.formulas.${\u540D\u524D}`;
9738
+ if (!isValueName(\u540D\u524D)) {
9739
+ errors.push({ path, ...valueNameIssue(\u540D\u524D) });
9740
+ continue;
9741
+ }
9742
+ if (typeof \u5F0F !== "string" || \u5F0F.trim() === "") {
9743
+ errors.push({
9744
+ path,
9745
+ message: `${\u540D\u524D} must be a non-empty expression string`,
9746
+ hint: `got ${Array.isArray(\u5F0F) ? "array" : \u5F0F === null ? "null" : typeof \u5F0F}`
9747
+ });
9748
+ continue;
9749
+ }
9750
+ try {
9751
+ const names = extractIdentifiers(parseFormula(\u5F0F));
9752
+ if (\u3064\u307E\u307F.has(\u540D\u524D) || \u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F.has(\u540D\u524D)) {
9753
+ errors.push({
9754
+ path,
9755
+ message: `${\u540D\u524D} collides with an input or an earlier formula`,
9756
+ hint: "inputs \u3068 formulas \u3067\u306F\u91CD\u306A\u3089\u306A\u3044\u540D\u524D\u3092\u4F7F\u3046"
9757
+ });
9758
+ continue;
9759
+ }
9760
+ let valid = true;
9761
+ for (const name of names) {
9762
+ if (\u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F.has(name)) continue;
9763
+ const kind = \u3064\u307E\u307F.get(name);
9764
+ if (["slider", "number", "stepper", "timeline", "toggle"].includes(kind ?? "")) continue;
9765
+ valid = false;
9766
+ errors.push({
9767
+ path,
9768
+ message: `${\u540D\u524D} references an unavailable formula identifier`,
9769
+ hint: `${name} \u306F\u6570\u5024/\u771F\u507D\u306E input \u306B\u3059\u308B\u304B\u3001\u3053\u306E\u5F0F\u3088\u308A\u524D\u306E formula \u306B\u66F8\u304F`
9770
+ });
9771
+ }
9772
+ if (valid) \u5148\u306B\u66F8\u304B\u308C\u305F\u5F0F.add(\u540D\u524D);
9773
+ } catch (e) {
9774
+ errors.push({
9775
+ path,
9776
+ message: `${\u540D\u524D} is not a readable expression`,
9777
+ hint: e.message
9778
+ });
9779
+ }
9780
+ }
9781
+ }
9782
+ function validateEvents(v, errors) {
9783
+ if (v === void 0) return;
9784
+ if (!Array.isArray(v)) {
9785
+ errors.push({
9786
+ path: "$.events",
9787
+ message: "events must be an array of event objects",
9788
+ hint: `got ${v === null ? "null" : typeof v}`
9789
+ });
9790
+ return;
9791
+ }
9792
+ const \u76F8\u624B\u306E\u9375 = ["box", "lane", "arrow", "diagram"];
9793
+ v.forEach((e, i) => {
9794
+ const path = `$.events[${i}]`;
9795
+ if (!e || typeof e !== "object" || Array.isArray(e)) {
9796
+ errors.push({ path, message: "event must be a plain object", hint: `got ${typeof e}` });
9797
+ return;
9798
+ }
9799
+ const o = e;
9800
+ for (const k of Object.keys(o)) {
9801
+ if (k === "on" || k === "handler" || \u76F8\u624B\u306E\u9375.includes(k)) continue;
9802
+ errors.push({
9803
+ path: `${path}.${k}`,
9804
+ message: `unknown key "${k}"`,
9805
+ hint: `\u4F7F\u3048\u308B\u9805\u76EE = on, handler, ${\u76F8\u624B\u306E\u9375.join(", ")}`
9806
+ });
9807
+ }
9808
+ if (typeof o.on !== "string" || !EVENT_KINDS.includes(o.on)) {
9809
+ errors.push({
9810
+ path: `${path}.on`,
9811
+ message: "on must be a known event kind",
9812
+ hint: `\u4F7F\u3048\u308B\u7A2E\u985E = ${EVENT_KINDS.join(", ")}`
9813
+ });
9814
+ }
9815
+ if (typeof o.handler !== "string" || o.handler.trim() === "") {
9816
+ errors.push({
9817
+ path: `${path}.handler`,
9818
+ message: "handler is required",
9819
+ hint: "\u7A7A\u3067\u306A\u3044\u6587\u5B57\u5217\u3067\u66F8\u304F"
9820
+ });
9821
+ }
9822
+ const \u66F8\u3044\u305F = \u76F8\u624B\u306E\u9375.filter((k) => o[k] !== void 0);
9823
+ if (\u66F8\u3044\u305F.length !== 1) {
9824
+ errors.push({
9825
+ path,
9826
+ message: \u66F8\u3044\u305F.length === 0 ? "event target is required" : "event target must be written once",
9827
+ hint: `${\u76F8\u624B\u306E\u9375.join(" / ")} \u306E\u3069\u308C\u304B 1 \u3064\u3060\u3051\u3092\u66F8\u304F`
9828
+ });
9829
+ return;
9830
+ }
9831
+ const \u9375 = \u66F8\u3044\u305F[0];
9832
+ if (\u9375 === "diagram") {
9833
+ if (o.diagram !== true) {
9834
+ errors.push({
9835
+ path: `${path}.diagram`,
9836
+ message: "diagram must be true",
9837
+ hint: "\u56F3\u5168\u4F53\u3092\u6307\u3059\u6642\u3060\u3051\u66F8\u304F"
9838
+ });
9839
+ }
9840
+ return;
9841
+ }
9842
+ if (typeof o[\u9375] !== "string" || o[\u9375].trim() === "") {
9843
+ errors.push({ path: `${path}.${\u9375}`, message: `${\u9375} must be a non-empty string` });
9844
+ return;
9845
+ }
9846
+ if (\u9375 === "arrow") {
9847
+ const \u4E21\u7AEF = o.arrow.split("->");
9848
+ if (\u4E21\u7AEF.length !== 2 || \u4E21\u7AEF.some((x) => x.trim() === "")) {
9849
+ errors.push({
9850
+ path: `${path}.arrow`,
9851
+ message: "arrow must be `A -> B`",
9852
+ hint: "\u77E2\u5370\u306E\u4E21\u7AEF\u306E\u540D\u524D\u3092\u66F8\u304F"
9853
+ });
9854
+ }
9855
+ }
9856
+ });
9857
+ }
9858
+ function validateScrolls(v, inputs, formulas, errors) {
9859
+ if (v === void 0) return;
9860
+ if (!v || typeof v !== "object" || Array.isArray(v)) {
9861
+ errors.push({
9862
+ path: "$.scrolls",
9863
+ message: "scrolls must be an object of name to spec",
9864
+ hint: `got ${v === null ? "null" : Array.isArray(v) ? "array" : typeof v}`
9865
+ });
9866
+ return;
9867
+ }
9868
+ const \u65E2\u306B\u5024\u3092\u4F5C\u308B\u540D\u524D = /* @__PURE__ */ new Set();
9869
+ if (Array.isArray(inputs)) {
9870
+ for (const input of inputs) {
9871
+ if (!input || typeof input !== "object" || Array.isArray(input)) continue;
9872
+ const id = input.id;
9873
+ if (typeof id === "string") \u65E2\u306B\u5024\u3092\u4F5C\u308B\u540D\u524D.add(id);
9874
+ }
9875
+ }
9876
+ if (formulas && typeof formulas === "object" && !Array.isArray(formulas)) {
9877
+ for (const id of Object.keys(formulas)) \u65E2\u306B\u5024\u3092\u4F5C\u308B\u540D\u524D.add(id);
9878
+ }
9879
+ for (const [\u540D\u524D, spec] of Object.entries(v)) {
9880
+ const path = `$.scrolls.${\u540D\u524D}`;
9881
+ if (!isValueName(\u540D\u524D)) {
9882
+ errors.push({ path, ...valueNameIssue(\u540D\u524D) });
9883
+ continue;
9884
+ }
9885
+ if (\u65E2\u306B\u5024\u3092\u4F5C\u308B\u540D\u524D.has(\u540D\u524D)) {
9886
+ errors.push({
9887
+ path,
9888
+ message: `${\u540D\u524D} collides with an input or formula`,
9889
+ hint: "inputs / formulas / scrolls \u3067\u306F\u91CD\u306A\u3089\u306A\u3044\u540D\u524D\u3092\u4F7F\u3046"
9890
+ });
9891
+ }
9892
+ if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
9893
+ errors.push({ path, message: `${\u540D\u524D} must be a plain object`, hint: `got ${typeof spec}` });
9894
+ continue;
9895
+ }
9896
+ for (const [k, x] of Object.entries(spec)) {
9897
+ if (k === "label") {
9898
+ if (typeof x !== "string") {
9899
+ errors.push({ path: `${path}.label`, message: "label must be a string" });
9900
+ }
9901
+ continue;
9902
+ }
9903
+ if (k !== "start" && k !== "end" && k !== "scrub") {
9904
+ errors.push({
9905
+ path: `${path}.${k}`,
9906
+ message: `unknown key "${k}"`,
9907
+ hint: "\u4F7F\u3048\u308B\u9805\u76EE = start, end, scrub, label"
9908
+ });
9909
+ continue;
9910
+ }
9911
+ if (typeof x !== "number" || !Number.isFinite(x)) {
9912
+ errors.push({ path: `${path}.${k}`, message: `${k} must be a finite number` });
9913
+ } else if (x < 0 || x > 1) {
9914
+ errors.push({
9915
+ path: `${path}.${k}`,
9916
+ message: `${k} must be between 0 and 1`,
9917
+ hint: "0 \u3068 1 \u3092\u542B\u3080\u7BC4\u56F2\u3067\u66F8\u304F"
9918
+ });
9919
+ }
9920
+ }
9921
+ }
9922
+ }
8804
9923
  function validateActorShape(v, path, errors) {
8805
9924
  if (v === void 0) return;
8806
9925
  if (!v || typeof v !== "object" || Array.isArray(v)) {
@@ -8975,6 +10094,10 @@ function validateJson(json) {
8975
10094
  const j = \u5199\u3057.value;
8976
10095
  checkUnknownKeys(j, "root", "$", errors);
8977
10096
  validateReadouts(j.readouts, errors);
10097
+ validateInputs(j.inputs, errors);
10098
+ validateFormulas(j.formulas, j.inputs, errors);
10099
+ validateEvents(j.events, errors);
10100
+ validateScrolls(j.scrolls, j.inputs, j.formulas, errors);
8978
10101
  \u8868\u3067\u691C\u67FB(j, "root", "$", "", errors);
8979
10102
  if (!Array.isArray(j.actors) || j.actors.length === 0) {
8980
10103
  errors.push({ path: "$.actors", message: "actors must be a non-empty array" });
@@ -9211,6 +10334,12 @@ function jsonToDoc(json) {
9211
10334
  shape: isPart ? void 0 : a.shape,
9212
10335
  visibleIf: isPart ? void 0 : a.visibleIf,
9213
10336
  title: isPart ? void 0 : a.title,
10337
+ // 値に追随する 5 欄 (#1392)。 記法と同じく見本には渡さない
10338
+ wBind: isPart ? void 0 : a.wBind,
10339
+ hBind: isPart ? void 0 : a.hBind,
10340
+ opacity: isPart ? void 0 : a.opacity,
10341
+ renderOffsetX: isPart ? void 0 : a.renderOffsetX,
10342
+ renderOffsetY: isPart ? void 0 : a.renderOffsetY,
9214
10343
  // 普通の箱にしか効かない欄は見本では落とす。 落とす欄の一覧は `見本に効かない欄` が
9215
10344
  // 唯一の出どころで、検査 (#1308) も同じ表を見る = 「検査は通すが組み立てが捨てる」
9216
10345
  // 状態が作れない
@@ -9258,6 +10387,10 @@ function jsonToDoc(json) {
9258
10387
  style: s.style,
9259
10388
  guard: s.guard,
9260
10389
  cardinality: s.cardinality,
10390
+ // 値に追随する 3 欄 (#1396)
10391
+ widthBind: s.widthBind,
10392
+ strokeBind: s.strokeBind,
10393
+ dashOffsetBind: s.dashOffsetBind,
9261
10394
  labelOffsetX: s.labelOffsetX,
9262
10395
  labelOffsetY: s.labelOffsetY,
9263
10396
  overlay: s.overlay,
@@ -9266,6 +10399,19 @@ function jsonToDoc(json) {
9266
10399
  pos: p0
9267
10400
  }));
9268
10401
  const readouts = json.readouts ? [...json.readouts] : void 0;
10402
+ const inputs = json.inputs ? [...json.inputs] : void 0;
10403
+ const events = json.events?.map((e) => ({
10404
+ event: e.on,
10405
+ target: e.diagram === true ? { kind: "diagram" } : e.arrow !== void 0 ? {
10406
+ kind: "edge",
10407
+ from: e.arrow.split("->")[0]?.trim() ?? "",
10408
+ to: e.arrow.split("->")[1]?.trim() ?? ""
10409
+ } : e.lane !== void 0 ? { kind: "lane", name: e.lane } : { kind: "node", name: e.box ?? "" },
10410
+ handlerId: e.handler.trim(),
10411
+ pos: p0
10412
+ }));
10413
+ const scrolls = json.scrolls ? Object.entries(json.scrolls).map(([id, spec]) => ({ id, ...spec })) : void 0;
10414
+ const formulas = json.formulas ? Object.entries(json.formulas).map(([id, expression]) => ({ id, expression, pos: p0 })) : void 0;
9269
10415
  const states = Object.entries(json.states ?? {}).map(([name, initial]) => ({
9270
10416
  name,
9271
10417
  initial,
@@ -9323,6 +10469,10 @@ function jsonToDoc(json) {
9323
10469
  ])
9324
10470
  ) : void 0,
9325
10471
  readouts,
10472
+ inputs,
10473
+ formulas,
10474
+ events,
10475
+ scrolls,
9326
10476
  pos: p0
9327
10477
  };
9328
10478
  }
@@ -9711,6 +10861,36 @@ var diagram_default = {
9711
10861
  required: ["sides"]
9712
10862
  }
9713
10863
  ]
10864
+ },
10865
+ wBind: {
10866
+ type: "string",
10867
+ minLength: 1,
10868
+ pattern: "\\S",
10869
+ description: "\u7BB1\u306E\u5E45\u3092\u5024\u306B\u8FFD\u968F\u3055\u305B\u308B\u3002 \u72B6\u614B\u306E\u540D\u524D\u3092 {\u540D\u524D} \u306E\u5F62\u3067\u66F8\u304F\u3002 \u914D\u7F6E\u8A08\u7B97\u306F\u8FFD\u968F\u524D\u306E\u5927\u304D\u3055\u3092\u4F7F\u3046"
10870
+ },
10871
+ hBind: {
10872
+ type: "string",
10873
+ minLength: 1,
10874
+ pattern: "\\S",
10875
+ description: "\u7BB1\u306E\u9AD8\u3055\u3092\u5024\u306B\u8FFD\u968F\u3055\u305B\u308B\u3002 wBind \u3068\u540C\u3058\u8AAD\u307F\u65B9"
10876
+ },
10877
+ opacity: {
10878
+ type: ["number", "string"],
10879
+ minLength: 1,
10880
+ pattern: "\\S",
10881
+ description: "\u7BB1\u306E\u6FC3\u3055\u3002 0 \u304B\u3089 1 \u306E\u6570\u304B\u3001\u72B6\u614B\u306E\u540D\u524D\u3002 \u66F8\u304B\u306A\u3051\u308C\u3070\u5B8C\u5168\u306B\u898B\u3048\u308B"
10882
+ },
10883
+ renderOffsetX: {
10884
+ type: ["number", "string"],
10885
+ minLength: 1,
10886
+ pattern: "\\S",
10887
+ description: "\u63CF\u304F\u6642\u3060\u3051\u7BB1\u3092\u6A2A\u3078\u305A\u3089\u3059\u91CF\u3002 \u914D\u7F6E\u8A08\u7B97\u3068\u77E2\u5370\u306F\u305A\u3089\u3059\u524D\u306E\u4F4D\u7F6E\u3092\u4F7F\u3046"
10888
+ },
10889
+ renderOffsetY: {
10890
+ type: ["number", "string"],
10891
+ minLength: 1,
10892
+ pattern: "\\S",
10893
+ description: "\u63CF\u304F\u6642\u3060\u3051\u7BB1\u3092\u7E26\u3078\u305A\u3089\u3059\u91CF\u3002 renderOffsetX \u3068\u540C\u3058\u8AAD\u307F\u65B9"
9714
10894
  }
9715
10895
  }
9716
10896
  }
@@ -9802,6 +10982,24 @@ var diagram_default = {
9802
10982
  type: "number"
9803
10983
  }
9804
10984
  }
10985
+ },
10986
+ widthBind: {
10987
+ type: "string",
10988
+ minLength: 1,
10989
+ pattern: "\\S",
10990
+ description: "\u7DDA\u306E\u592A\u3055\u3092\u5024\u306B\u8FFD\u968F\u3055\u305B\u308B\u3002 \u72B6\u614B\u3084\u3064\u307E\u307F\u306E\u540D\u524D\u3092 {\u540D\u524D} \u306E\u5F62\u3067\u66F8\u304F"
10991
+ },
10992
+ strokeBind: {
10993
+ type: "string",
10994
+ minLength: 1,
10995
+ pattern: "\\S",
10996
+ description: "\u7DDA\u306E\u8272\u3092\u5024\u306B\u8FFD\u968F\u3055\u305B\u308B\u3002 widthBind \u3068\u540C\u3058\u8AAD\u307F\u65B9"
10997
+ },
10998
+ dashOffsetBind: {
10999
+ type: "string",
11000
+ minLength: 1,
11001
+ pattern: "\\S",
11002
+ description: "\u7834\u7DDA\u306E\u4F4D\u7F6E\u3092\u5024\u306B\u8FFD\u968F\u3055\u305B\u308B (\u6D41\u308C\u3066\u3044\u308B\u3088\u3046\u306B\u898B\u305B\u308B)\u3002 widthBind \u3068\u540C\u3058\u8AAD\u307F\u65B9"
9805
11003
  }
9806
11004
  }
9807
11005
  }
@@ -10828,6 +12026,314 @@ var diagram_default = {
10828
12026
  }
10829
12027
  ]
10830
12028
  }
12029
+ },
12030
+ inputs: {
12031
+ type: "array",
12032
+ description: "\u8AAD\u3080\u4EBA\u304C\u52D5\u304B\u3059\u3064\u307E\u307F\u3002 \u5024\u3092\u63E1\u308A\u3001\u7BB1\u306E\u6587\u5B57\u3084\u90E8\u54C1\u304C\u305D\u306E\u5024\u3092\u8FFD\u3044\u304B\u3051\u308B\u3002 \u7BB1\u3067\u306F\u306A\u3044\u306E\u3067\u7E26\u5217\u306B\u8F09\u3089\u305A\u3001\u56F3\u5168\u4F53\u306B 1 \u3064\u306E\u4E26\u3073\u3068\u3057\u3066\u6301\u3064\u3002",
12033
+ items: {
12034
+ type: "object",
12035
+ required: ["id", "kind"],
12036
+ additionalProperties: false,
12037
+ properties: {
12038
+ id: {
12039
+ type: "string",
12040
+ minLength: 1
12041
+ },
12042
+ kind: {
12043
+ type: "string",
12044
+ enum: [
12045
+ "color",
12046
+ "datetime",
12047
+ "dropdown",
12048
+ "multi-select",
12049
+ "number",
12050
+ "radio",
12051
+ "range",
12052
+ "slider",
12053
+ "stepper",
12054
+ "tabs",
12055
+ "text",
12056
+ "timeline",
12057
+ "toggle",
12058
+ "xypad"
12059
+ ]
12060
+ },
12061
+ autoplay: {
12062
+ type: "boolean"
12063
+ },
12064
+ defaultHi: {
12065
+ type: "number"
12066
+ },
12067
+ defaultLo: {
12068
+ type: "number"
12069
+ },
12070
+ defaultSpeedIdx: {
12071
+ type: "number"
12072
+ },
12073
+ defaultValue: {
12074
+ type: ["boolean", "number", "string"]
12075
+ },
12076
+ defaultValues: {
12077
+ type: "array",
12078
+ items: {
12079
+ type: "string"
12080
+ }
12081
+ },
12082
+ defaultX: {
12083
+ type: "number"
12084
+ },
12085
+ defaultY: {
12086
+ type: "number"
12087
+ },
12088
+ duration: {
12089
+ type: "number"
12090
+ },
12091
+ label: {
12092
+ type: "string"
12093
+ },
12094
+ loop: {
12095
+ type: "boolean"
12096
+ },
12097
+ max: {
12098
+ type: "number"
12099
+ },
12100
+ maxLength: {
12101
+ type: "number"
12102
+ },
12103
+ min: {
12104
+ type: "number"
12105
+ },
12106
+ options: {
12107
+ type: "array",
12108
+ items: {
12109
+ type: "string"
12110
+ }
12111
+ },
12112
+ placeholder: {
12113
+ type: "string"
12114
+ },
12115
+ speeds: {
12116
+ type: "array",
12117
+ items: {
12118
+ type: "number"
12119
+ }
12120
+ },
12121
+ step: {
12122
+ type: "number"
12123
+ },
12124
+ xMax: {
12125
+ type: "number"
12126
+ },
12127
+ xMin: {
12128
+ type: "number"
12129
+ },
12130
+ yMax: {
12131
+ type: "number"
12132
+ },
12133
+ yMin: {
12134
+ type: "number"
12135
+ }
12136
+ },
12137
+ oneOf: [
12138
+ {
12139
+ properties: {
12140
+ kind: {
12141
+ enum: ["color", "datetime", "text"]
12142
+ },
12143
+ defaultValue: {
12144
+ type: "string"
12145
+ }
12146
+ },
12147
+ required: ["defaultValue"]
12148
+ },
12149
+ {
12150
+ properties: {
12151
+ kind: {
12152
+ enum: ["dropdown", "radio", "tabs"]
12153
+ },
12154
+ defaultValue: {
12155
+ type: "string"
12156
+ }
12157
+ },
12158
+ required: ["options", "defaultValue"]
12159
+ },
12160
+ {
12161
+ properties: {
12162
+ kind: {
12163
+ enum: ["multi-select"]
12164
+ }
12165
+ },
12166
+ required: ["options", "defaultValues"]
12167
+ },
12168
+ {
12169
+ properties: {
12170
+ kind: {
12171
+ enum: ["number", "stepper"]
12172
+ },
12173
+ defaultValue: {
12174
+ type: "number"
12175
+ }
12176
+ },
12177
+ required: ["defaultValue"]
12178
+ },
12179
+ {
12180
+ properties: {
12181
+ kind: {
12182
+ enum: ["range"]
12183
+ }
12184
+ },
12185
+ required: ["min", "max", "defaultLo", "defaultHi"]
12186
+ },
12187
+ {
12188
+ properties: {
12189
+ kind: {
12190
+ enum: ["slider"]
12191
+ },
12192
+ defaultValue: {
12193
+ type: "number"
12194
+ }
12195
+ },
12196
+ required: ["min", "max", "defaultValue"]
12197
+ },
12198
+ {
12199
+ properties: {
12200
+ kind: {
12201
+ enum: ["timeline"]
12202
+ }
12203
+ },
12204
+ required: ["duration"]
12205
+ },
12206
+ {
12207
+ properties: {
12208
+ kind: {
12209
+ enum: ["toggle"]
12210
+ },
12211
+ defaultValue: {
12212
+ type: "boolean"
12213
+ }
12214
+ },
12215
+ required: ["defaultValue"]
12216
+ },
12217
+ {
12218
+ properties: {
12219
+ kind: {
12220
+ enum: ["xypad"]
12221
+ }
12222
+ },
12223
+ required: ["xMin", "xMax", "yMin", "yMax", "defaultX", "defaultY"]
12224
+ }
12225
+ ]
12226
+ }
12227
+ },
12228
+ formulas: {
12229
+ type: "object",
12230
+ description: '\u3064\u307E\u307F\u306E\u5024\u304B\u3089\u6C7A\u307E\u308B\u5024\u3002 \u540D\u524D\u3092\u9375\u3001\u5F0F\u3092\u5024\u306B\u66F8\u304F\u3002 `values` \u3068\u306F\u7D4C\u8DEF\u304C\u5225\u3067\u3001\u5F0F\u306F\u540D\u524D\u3092\u4E2D\u62EC\u5F27\u3067\u56F2\u308F\u306A\u3044 (\u4F8B "input * 2")\u3002',
12231
+ additionalProperties: {
12232
+ type: "string",
12233
+ minLength: 1,
12234
+ pattern: "\\S"
12235
+ },
12236
+ propertyNames: {
12237
+ pattern: "^[A-Za-z_][A-Za-z0-9_]*$"
12238
+ }
12239
+ },
12240
+ events: {
12241
+ type: "array",
12242
+ description: "\u62BC\u4E0B\u306A\u3069\u306E\u51FA\u6765\u4E8B\u3067\u52D5\u304F\u4ED5\u639B\u3051\u3002 \u76F8\u624B\u306F\u540D\u524D\u3067\u6307\u3059 (box / lane / arrow / diagram \u306E\u3069\u308C\u304B 1 \u3064)\u3002",
12243
+ items: {
12244
+ type: "object",
12245
+ required: ["on", "handler"],
12246
+ additionalProperties: false,
12247
+ properties: {
12248
+ on: {
12249
+ type: "string",
12250
+ enum: [
12251
+ "click",
12252
+ "hover",
12253
+ "double-click",
12254
+ "long-press",
12255
+ "drag",
12256
+ "drop",
12257
+ "keydown",
12258
+ "focus",
12259
+ "blur"
12260
+ ]
12261
+ },
12262
+ handler: {
12263
+ type: "string",
12264
+ minLength: 1,
12265
+ pattern: "\\S"
12266
+ },
12267
+ box: {
12268
+ type: "string",
12269
+ minLength: 1,
12270
+ description: "\u7BB1\u306E\u540D\u524D"
12271
+ },
12272
+ lane: {
12273
+ type: "string",
12274
+ minLength: 1,
12275
+ description: "\u7E26\u5217\u306E\u540D\u524D"
12276
+ },
12277
+ arrow: {
12278
+ type: "string",
12279
+ minLength: 1,
12280
+ pattern: "^(?!.*->.*->)\\s*\\S(?:.*\\S)?\\s*->\\s*\\S(?:.*\\S)?\\s*$",
12281
+ description: "\u77E2\u5370\u3002 `A -> B` \u306E\u5F62\u3067\u4E21\u7AEF\u306E\u540D\u524D\u3092\u66F8\u304F"
12282
+ },
12283
+ diagram: {
12284
+ const: true,
12285
+ description: "\u56F3\u5168\u4F53\u3092\u6307\u3059"
12286
+ }
12287
+ },
12288
+ oneOf: [
12289
+ {
12290
+ required: ["box"]
12291
+ },
12292
+ {
12293
+ required: ["lane"]
12294
+ },
12295
+ {
12296
+ required: ["arrow"]
12297
+ },
12298
+ {
12299
+ required: ["diagram"]
12300
+ }
12301
+ ]
12302
+ }
12303
+ },
12304
+ scrolls: {
12305
+ type: "object",
12306
+ description: "\u5DFB\u304D\u4E0A\u3052\u306B\u5FDC\u3058\u3066\u9032\u3080\u5024\u3002 \u753B\u9762\u3092\u5DFB\u304D\u4E0A\u3052\u305F\u91CF\u304B\u3089 0 \u304B\u3089 1 \u306E\u9032\u307F\u5177\u5408\u3092\u4F5C\u308B\u3002",
12307
+ propertyNames: {
12308
+ pattern: "^[A-Za-z_][A-Za-z0-9_]*$"
12309
+ },
12310
+ additionalProperties: {
12311
+ type: "object",
12312
+ additionalProperties: false,
12313
+ properties: {
12314
+ start: {
12315
+ type: "number",
12316
+ minimum: 0,
12317
+ maximum: 1,
12318
+ description: "\u9032\u307F\u5177\u5408\u304C 0 \u306B\u306A\u308B\u753B\u9762\u4E0A\u306E\u4F4D\u7F6E (0 \u304C\u4E0A\u7AEF\u30011 \u304C\u4E0B\u7AEF)"
12319
+ },
12320
+ end: {
12321
+ type: "number",
12322
+ minimum: 0,
12323
+ maximum: 1,
12324
+ description: "\u9032\u307F\u5177\u5408\u304C 1 \u306B\u306A\u308B\u753B\u9762\u4E0A\u306E\u4F4D\u7F6E"
12325
+ },
12326
+ scrub: {
12327
+ type: "number",
12328
+ minimum: 0,
12329
+ maximum: 1,
12330
+ description: "\u5DFB\u304D\u4E0A\u3052\u3078\u306E\u8FFD\u968F\u5EA6\u5408\u3044 (0 \u304C\u6BB5\u968E\u7684\u30011 \u304C\u9023\u7D9A)"
12331
+ },
12332
+ label: {
12333
+ type: "string"
12334
+ }
12335
+ }
12336
+ }
10831
12337
  }
10832
12338
  }
10833
12339
  };