@pipelex/mthds-ui 0.29.0 → 0.30.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.
Files changed (33) hide show
  1. package/README.md +14 -8
  2. package/dist/{chunk-ZTXSDTVF.js → chunk-3BXB6HSF.js} +1304 -31
  3. package/dist/chunk-3BXB6HSF.js.map +1 -0
  4. package/dist/{chunk-Y46574OW.js → chunk-GAOBB3UT.js} +5 -2
  5. package/dist/chunk-GAOBB3UT.js.map +1 -0
  6. package/dist/chunk-KB2DIEVF.js +1 -0
  7. package/dist/{chunk-3I3ZPYMW.js → chunk-PJTYQURQ.js} +33 -1
  8. package/dist/chunk-PJTYQURQ.js.map +1 -0
  9. package/dist/form/react/index.d.ts +1 -1
  10. package/dist/form/react/index.js +2 -2
  11. package/dist/graph/index.d.ts +336 -9
  12. package/dist/graph/index.js +98 -4
  13. package/dist/graph/react/index.d.ts +26 -2
  14. package/dist/graph/react/index.js +975 -371
  15. package/dist/graph/react/index.js.map +1 -1
  16. package/dist/graph/react/styles/simple/SimpleStyle.css +434 -0
  17. package/dist/graph/react/viewer/GraphToolbar.css +114 -0
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +98 -4
  20. package/dist/standalone/graph-standalone.html +714 -165
  21. package/dist/standalone/graph-viewer.css +549 -0
  22. package/dist/standalone/graph-viewer.js +164 -164
  23. package/dist/static-graph/index.d.ts +1 -1
  24. package/dist/static-graph/index.js +1 -1
  25. package/dist/{types-BaFWy56P.d.ts → types-BNqjYF_x.d.ts} +152 -1
  26. package/package.json +2 -1
  27. package/dist/chunk-3I3ZPYMW.js.map +0 -1
  28. package/dist/chunk-F6TZIJ7A.js +0 -1
  29. package/dist/chunk-Y46574OW.js.map +0 -1
  30. package/dist/chunk-ZTXSDTVF.js.map +0 -1
  31. package/dist/graph/react/index.css +0 -749
  32. package/dist/graph/react/index.css.map +0 -1
  33. /package/dist/{chunk-F6TZIJ7A.js.map → chunk-KB2DIEVF.js.map} +0 -0
@@ -1,7 +1,9 @@
1
1
  "use client";
2
2
  import {
3
+ GRAPH_STYLES,
4
+ GRAPH_STYLE_PIPELINES,
3
5
  MAX_VISIBLE_CONTROLLER_CHILDREN,
4
- applyControllers,
6
+ STEP_CATEGORY_WORDS,
5
7
  applyFolds,
6
8
  applyValidationDecorations,
7
9
  buildChildToControllerMap,
@@ -9,27 +11,38 @@ import {
9
11
  buildValidationDecorations,
10
12
  findCousinControllers,
11
13
  findStuffByDigest,
14
+ fitRoute,
12
15
  getLayoutedElements,
13
16
  getPipeBlueprint,
14
17
  resolveConceptRef,
18
+ resolveGraphStyle,
15
19
  resolveIssueTargetNodeId,
20
+ resolveStyleMenu,
21
+ roundedPolylinePath,
22
+ routeLabelCenter,
16
23
  validateGraphSpec
17
- } from "../../chunk-ZTXSDTVF.js";
24
+ } from "../../chunk-3BXB6HSF.js";
18
25
  import {
19
26
  parsePipeRef
20
27
  } from "../../chunk-2N65P32H.js";
21
28
  import {
22
29
  DEFAULT_GRAPH_CONFIG,
23
30
  getPaletteForTheme
24
- } from "../../chunk-Y46574OW.js";
31
+ } from "../../chunk-GAOBB3UT.js";
25
32
  import {
26
33
  BINDING_STEP_TYPE,
27
34
  EDGE_TYPE,
35
+ EDGE_TYPE_ROUTED,
28
36
  FOLD_MODE,
29
37
  GRAPH_DIRECTION,
30
38
  GRAPH_SPEC_MODE,
39
+ GRAPH_STYLE,
31
40
  GRAPH_THEME,
32
41
  GRAPH_THEME_MODE,
42
+ NODE_TYPE_SIMPLE_DECISION,
43
+ NODE_TYPE_SIMPLE_FRAME,
44
+ NODE_TYPE_SIMPLE_STEP,
45
+ NODE_TYPE_SIMPLE_TERMINAL,
33
46
  TOOLBAR_POSITION,
34
47
  VALIDATION_STATE,
35
48
  graphSpecMode,
@@ -42,7 +55,7 @@ import {
42
55
  stuffDigestFromId,
43
56
  toolbarOrientation,
44
57
  toolbarSide
45
- } from "../../chunk-3I3ZPYMW.js";
58
+ } from "../../chunk-PJTYQURQ.js";
46
59
  import {
47
60
  __spreadProps,
48
61
  __spreadValues
@@ -52,9 +65,10 @@ import {
52
65
  import "./graph-core.css";
53
66
  import "./detail/DetailPanel.css";
54
67
  import "./viewer/GraphToolbar.css";
68
+ import "./styles/simple/SimpleStyle.css";
55
69
 
56
70
  // src/graph/react/viewer/GraphViewer.tsx
57
- import React10 from "react";
71
+ import React12 from "react";
58
72
  import {
59
73
  ReactFlow,
60
74
  useNodesState,
@@ -1508,7 +1522,7 @@ function toAppNodes(nodes) {
1508
1522
  }));
1509
1523
  }
1510
1524
  function toAppEdges(edges) {
1511
- return edges.map((e) => ({
1525
+ return edges.map((e) => __spreadValues({
1512
1526
  id: e.id,
1513
1527
  source: e.source,
1514
1528
  target: e.target,
@@ -1521,7 +1535,7 @@ function toAppEdges(edges) {
1521
1535
  labelBgBorderRadius: e.labelBgBorderRadius,
1522
1536
  style: e.style,
1523
1537
  markerEnd: e.markerEnd
1524
- }));
1538
+ }, e.route ? { data: { route: e.route } } : {}));
1525
1539
  }
1526
1540
 
1527
1541
  // src/graph/react/viewer/renderLabel.tsx
@@ -1623,7 +1637,7 @@ function hydrateLabels(nodes) {
1623
1637
  }
1624
1638
 
1625
1639
  // src/graph/react/viewer/GraphToolbar.tsx
1626
- import React8 from "react";
1640
+ import React10 from "react";
1627
1641
  import { Panel } from "@xyflow/react";
1628
1642
 
1629
1643
  // src/graph/react/viewer/ValidationPanel.tsx
@@ -1742,10 +1756,194 @@ function ValidationPanel({
1742
1756
  );
1743
1757
  }
1744
1758
 
1759
+ // src/graph/react/viewer/StyleMenu.tsx
1760
+ import React9 from "react";
1761
+
1762
+ // src/graph/react/viewer/usePopoverDismiss.ts
1763
+ import React8 from "react";
1764
+ function usePopoverDismiss(open, wrapperRef, onDismiss) {
1765
+ const onDismissRef = React8.useRef(onDismiss);
1766
+ onDismissRef.current = onDismiss;
1767
+ React8.useEffect(() => {
1768
+ if (!open) return;
1769
+ const onPointerDown = (event) => {
1770
+ const wrapper = wrapperRef.current;
1771
+ if (wrapper && event.target instanceof Node && !wrapper.contains(event.target)) {
1772
+ onDismissRef.current("outside");
1773
+ }
1774
+ };
1775
+ const onKeyDown = (event) => {
1776
+ if (event.key === "Escape") onDismissRef.current("escape");
1777
+ };
1778
+ document.addEventListener("pointerdown", onPointerDown, true);
1779
+ document.addEventListener("keydown", onKeyDown);
1780
+ return () => {
1781
+ document.removeEventListener("pointerdown", onPointerDown, true);
1782
+ document.removeEventListener("keydown", onKeyDown);
1783
+ };
1784
+ }, [open, wrapperRef]);
1785
+ }
1786
+
1787
+ // src/graph/react/viewer/StyleMenu.tsx
1788
+ import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
1789
+ var ICON_PROPS = {
1790
+ viewBox: "0 0 24 24",
1791
+ width: 14,
1792
+ height: 14,
1793
+ fill: "none",
1794
+ stroke: "currentColor",
1795
+ strokeWidth: 2,
1796
+ strokeLinecap: "round",
1797
+ strokeLinejoin: "round"
1798
+ };
1799
+ var STYLE_ICONS = {
1800
+ // Cards with their rows: every pipe with its slots.
1801
+ [GRAPH_STYLE.DETAILED]: /* @__PURE__ */ jsxs20("svg", __spreadProps(__spreadValues({}, ICON_PROPS), { children: [
1802
+ /* @__PURE__ */ jsx20("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
1803
+ /* @__PURE__ */ jsx20("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }),
1804
+ /* @__PURE__ */ jsx20("line", { x1: "14", y1: "4", x2: "21", y2: "4" }),
1805
+ /* @__PURE__ */ jsx20("line", { x1: "14", y1: "9", x2: "21", y2: "9" }),
1806
+ /* @__PURE__ */ jsx20("line", { x1: "14", y1: "15", x2: "21", y2: "15" }),
1807
+ /* @__PURE__ */ jsx20("line", { x1: "14", y1: "20", x2: "21", y2: "20" })
1808
+ ] })),
1809
+ // Two steps and the arrow between them: a flowchart.
1810
+ [GRAPH_STYLE.SIMPLE]: /* @__PURE__ */ jsxs20("svg", __spreadProps(__spreadValues({}, ICON_PROPS), { children: [
1811
+ /* @__PURE__ */ jsx20("rect", { x: "3", y: "3", width: "8", height: "8", rx: "2" }),
1812
+ /* @__PURE__ */ jsx20("path", { d: "M7 11v4a2 2 0 0 0 2 2h4" }),
1813
+ /* @__PURE__ */ jsx20("rect", { x: "13", y: "13", width: "8", height: "8", rx: "2" })
1814
+ ] }))
1815
+ };
1816
+ var CHECK_ICON2 = /* @__PURE__ */ jsx20("svg", __spreadProps(__spreadValues({}, ICON_PROPS), { children: /* @__PURE__ */ jsx20("polyline", { points: "20 6 9 17 4 12" }) }));
1817
+ function graphStyleIcon(style) {
1818
+ return STYLE_ICONS[style];
1819
+ }
1820
+ function styleMenuLabel(style) {
1821
+ return `Graph style: ${GRAPH_STYLES[style].name} \u2014 choose how the graph is drawn`;
1822
+ }
1823
+ function StyleMenu({ value, options, onChange, placement }) {
1824
+ const [open, setOpen] = React9.useState(false);
1825
+ const [activeIndex, setActiveIndex] = React9.useState(0);
1826
+ const wrapperRef = React9.useRef(null);
1827
+ const buttonRef = React9.useRef(null);
1828
+ const itemRefs = React9.useRef([]);
1829
+ const menuId = React9.useId();
1830
+ usePopoverDismiss(open, wrapperRef, (reason) => {
1831
+ var _a;
1832
+ setOpen(false);
1833
+ if (reason === "escape") (_a = buttonRef.current) == null ? void 0 : _a.focus();
1834
+ });
1835
+ React9.useEffect(() => {
1836
+ var _a;
1837
+ if (!open) return;
1838
+ const index = Math.max(0, options.indexOf(value));
1839
+ setActiveIndex(index);
1840
+ (_a = itemRefs.current[index]) == null ? void 0 : _a.focus();
1841
+ }, [open]);
1842
+ const focusItem = (index) => {
1843
+ var _a;
1844
+ const count = options.length;
1845
+ const next = (index % count + count) % count;
1846
+ setActiveIndex(next);
1847
+ (_a = itemRefs.current[next]) == null ? void 0 : _a.focus();
1848
+ };
1849
+ const onMenuKeyDown = (event) => {
1850
+ switch (event.key) {
1851
+ case "ArrowDown":
1852
+ event.preventDefault();
1853
+ focusItem(activeIndex + 1);
1854
+ break;
1855
+ case "ArrowUp":
1856
+ event.preventDefault();
1857
+ focusItem(activeIndex - 1);
1858
+ break;
1859
+ case "Home":
1860
+ event.preventDefault();
1861
+ focusItem(0);
1862
+ break;
1863
+ case "End":
1864
+ event.preventDefault();
1865
+ focusItem(options.length - 1);
1866
+ break;
1867
+ case "Tab":
1868
+ setOpen(false);
1869
+ break;
1870
+ default:
1871
+ break;
1872
+ }
1873
+ };
1874
+ const choose = (style) => {
1875
+ var _a;
1876
+ setOpen(false);
1877
+ (_a = buttonRef.current) == null ? void 0 : _a.focus();
1878
+ if (style !== value) onChange(style);
1879
+ };
1880
+ const label = styleMenuLabel(value);
1881
+ return /* @__PURE__ */ jsxs20("div", { className: "graph-toolbar-style", ref: wrapperRef, children: [
1882
+ /* @__PURE__ */ jsx20(
1883
+ "button",
1884
+ {
1885
+ ref: buttonRef,
1886
+ type: "button",
1887
+ className: `graph-toolbar-btn${open ? " graph-toolbar-btn--open" : ""}`,
1888
+ onClick: () => setOpen(!open),
1889
+ onKeyDown: (event) => {
1890
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1891
+ event.preventDefault();
1892
+ setOpen(true);
1893
+ }
1894
+ },
1895
+ title: label,
1896
+ "aria-label": label,
1897
+ "aria-haspopup": "menu",
1898
+ "aria-expanded": open,
1899
+ "aria-controls": open ? menuId : void 0,
1900
+ children: graphStyleIcon(value)
1901
+ }
1902
+ ),
1903
+ open && /* @__PURE__ */ jsx20(
1904
+ "div",
1905
+ {
1906
+ id: menuId,
1907
+ role: "menu",
1908
+ "aria-label": "Graph style",
1909
+ className: `graph-style-menu graph-style-menu--${placement}`,
1910
+ onKeyDown: onMenuKeyDown,
1911
+ children: options.map((style, index) => {
1912
+ const descriptor = GRAPH_STYLES[style];
1913
+ const checked = style === value;
1914
+ return /* @__PURE__ */ jsxs20(
1915
+ "button",
1916
+ {
1917
+ ref: (el) => {
1918
+ itemRefs.current[index] = el;
1919
+ },
1920
+ type: "button",
1921
+ role: "menuitemradio",
1922
+ "aria-checked": checked,
1923
+ tabIndex: index === activeIndex ? 0 : -1,
1924
+ className: `graph-style-menu-item${checked ? " graph-style-menu-item--checked" : ""}`,
1925
+ onClick: () => choose(style),
1926
+ children: [
1927
+ /* @__PURE__ */ jsx20("span", { className: "graph-style-menu-icon", "aria-hidden": "true", children: graphStyleIcon(style) }),
1928
+ /* @__PURE__ */ jsxs20("span", { className: "graph-style-menu-text", children: [
1929
+ /* @__PURE__ */ jsx20("span", { className: "graph-style-menu-name", children: descriptor.name }),
1930
+ /* @__PURE__ */ jsx20("span", { className: "graph-style-menu-description", children: descriptor.description })
1931
+ ] }),
1932
+ /* @__PURE__ */ jsx20("span", { className: "graph-style-menu-check", "aria-hidden": "true", children: checked ? CHECK_ICON2 : null })
1933
+ ]
1934
+ },
1935
+ style
1936
+ );
1937
+ })
1938
+ }
1939
+ )
1940
+ ] });
1941
+ }
1942
+
1745
1943
  // src/graph/react/viewer/GraphToolbar.tsx
1746
- import { Fragment as Fragment12, jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
1944
+ import { Fragment as Fragment12, jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
1747
1945
  var REACTFLOW_PANEL_MARGIN = 15;
1748
- var ARROW_RIGHT_ICON = /* @__PURE__ */ jsxs20(
1946
+ var ARROW_RIGHT_ICON = /* @__PURE__ */ jsxs21(
1749
1947
  "svg",
1750
1948
  {
1751
1949
  viewBox: "0 0 24 24",
@@ -1757,12 +1955,12 @@ var ARROW_RIGHT_ICON = /* @__PURE__ */ jsxs20(
1757
1955
  strokeLinecap: "round",
1758
1956
  strokeLinejoin: "round",
1759
1957
  children: [
1760
- /* @__PURE__ */ jsx20("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
1761
- /* @__PURE__ */ jsx20("polyline", { points: "12 5 19 12 12 19" })
1958
+ /* @__PURE__ */ jsx21("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
1959
+ /* @__PURE__ */ jsx21("polyline", { points: "12 5 19 12 12 19" })
1762
1960
  ]
1763
1961
  }
1764
1962
  );
1765
- var ARROW_DOWN_ICON = /* @__PURE__ */ jsxs20(
1963
+ var ARROW_DOWN_ICON = /* @__PURE__ */ jsxs21(
1766
1964
  "svg",
1767
1965
  {
1768
1966
  viewBox: "0 0 24 24",
@@ -1774,12 +1972,12 @@ var ARROW_DOWN_ICON = /* @__PURE__ */ jsxs20(
1774
1972
  strokeLinecap: "round",
1775
1973
  strokeLinejoin: "round",
1776
1974
  children: [
1777
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1778
- /* @__PURE__ */ jsx20("polyline", { points: "19 12 12 19 5 12" })
1975
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1976
+ /* @__PURE__ */ jsx21("polyline", { points: "19 12 12 19 5 12" })
1779
1977
  ]
1780
1978
  }
1781
1979
  );
1782
- var MINUS_ICON = /* @__PURE__ */ jsx20(
1980
+ var MINUS_ICON = /* @__PURE__ */ jsx21(
1783
1981
  "svg",
1784
1982
  {
1785
1983
  viewBox: "0 0 24 24",
@@ -1790,10 +1988,10 @@ var MINUS_ICON = /* @__PURE__ */ jsx20(
1790
1988
  strokeWidth: "2",
1791
1989
  strokeLinecap: "round",
1792
1990
  strokeLinejoin: "round",
1793
- children: /* @__PURE__ */ jsx20("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1991
+ children: /* @__PURE__ */ jsx21("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1794
1992
  }
1795
1993
  );
1796
- var PLUS_ICON = /* @__PURE__ */ jsxs20(
1994
+ var PLUS_ICON = /* @__PURE__ */ jsxs21(
1797
1995
  "svg",
1798
1996
  {
1799
1997
  viewBox: "0 0 24 24",
@@ -1805,12 +2003,12 @@ var PLUS_ICON = /* @__PURE__ */ jsxs20(
1805
2003
  strokeLinecap: "round",
1806
2004
  strokeLinejoin: "round",
1807
2005
  children: [
1808
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1809
- /* @__PURE__ */ jsx20("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
2006
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
2007
+ /* @__PURE__ */ jsx21("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1810
2008
  ]
1811
2009
  }
1812
2010
  );
1813
- var FIT_VIEW_ICON = /* @__PURE__ */ jsxs20(
2011
+ var FIT_VIEW_ICON = /* @__PURE__ */ jsxs21(
1814
2012
  "svg",
1815
2013
  {
1816
2014
  viewBox: "0 0 24 24",
@@ -1822,14 +2020,14 @@ var FIT_VIEW_ICON = /* @__PURE__ */ jsxs20(
1822
2020
  strokeLinecap: "round",
1823
2021
  strokeLinejoin: "round",
1824
2022
  children: [
1825
- /* @__PURE__ */ jsx20("polyline", { points: "15 3 21 3 21 9" }),
1826
- /* @__PURE__ */ jsx20("polyline", { points: "9 21 3 21 3 15" }),
1827
- /* @__PURE__ */ jsx20("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
1828
- /* @__PURE__ */ jsx20("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
2023
+ /* @__PURE__ */ jsx21("polyline", { points: "15 3 21 3 21 9" }),
2024
+ /* @__PURE__ */ jsx21("polyline", { points: "9 21 3 21 3 15" }),
2025
+ /* @__PURE__ */ jsx21("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
2026
+ /* @__PURE__ */ jsx21("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
1829
2027
  ]
1830
2028
  }
1831
2029
  );
1832
- var BOXES_ICON = /* @__PURE__ */ jsxs20(
2030
+ var BOXES_ICON = /* @__PURE__ */ jsxs21(
1833
2031
  "svg",
1834
2032
  {
1835
2033
  viewBox: "0 0 24 24",
@@ -1841,22 +2039,22 @@ var BOXES_ICON = /* @__PURE__ */ jsxs20(
1841
2039
  strokeLinecap: "round",
1842
2040
  strokeLinejoin: "round",
1843
2041
  children: [
1844
- /* @__PURE__ */ jsx20("path", { d: "M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" }),
1845
- /* @__PURE__ */ jsx20("path", { d: "m7 16.5-4.74-2.85" }),
1846
- /* @__PURE__ */ jsx20("path", { d: "m7 16.5 5-3" }),
1847
- /* @__PURE__ */ jsx20("path", { d: "M7 16.5v5.17" }),
1848
- /* @__PURE__ */ jsx20("path", { d: "M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" }),
1849
- /* @__PURE__ */ jsx20("path", { d: "m17 16.5-5-3" }),
1850
- /* @__PURE__ */ jsx20("path", { d: "m17 16.5 4.74-2.85" }),
1851
- /* @__PURE__ */ jsx20("path", { d: "M17 16.5v5.17" }),
1852
- /* @__PURE__ */ jsx20("path", { d: "M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z" }),
1853
- /* @__PURE__ */ jsx20("path", { d: "M12 8 7.26 5.15" }),
1854
- /* @__PURE__ */ jsx20("path", { d: "m12 8 4.74-2.85" }),
1855
- /* @__PURE__ */ jsx20("path", { d: "M12 13.5V8" })
2042
+ /* @__PURE__ */ jsx21("path", { d: "M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" }),
2043
+ /* @__PURE__ */ jsx21("path", { d: "m7 16.5-4.74-2.85" }),
2044
+ /* @__PURE__ */ jsx21("path", { d: "m7 16.5 5-3" }),
2045
+ /* @__PURE__ */ jsx21("path", { d: "M7 16.5v5.17" }),
2046
+ /* @__PURE__ */ jsx21("path", { d: "M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" }),
2047
+ /* @__PURE__ */ jsx21("path", { d: "m17 16.5-5-3" }),
2048
+ /* @__PURE__ */ jsx21("path", { d: "m17 16.5 4.74-2.85" }),
2049
+ /* @__PURE__ */ jsx21("path", { d: "M17 16.5v5.17" }),
2050
+ /* @__PURE__ */ jsx21("path", { d: "M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z" }),
2051
+ /* @__PURE__ */ jsx21("path", { d: "M12 8 7.26 5.15" }),
2052
+ /* @__PURE__ */ jsx21("path", { d: "m12 8 4.74-2.85" }),
2053
+ /* @__PURE__ */ jsx21("path", { d: "M12 13.5V8" })
1856
2054
  ]
1857
2055
  }
1858
2056
  );
1859
- var FOLD_ALL_ICON = /* @__PURE__ */ jsxs20(
2057
+ var FOLD_ALL_ICON = /* @__PURE__ */ jsxs21(
1860
2058
  "svg",
1861
2059
  {
1862
2060
  viewBox: "0 0 24 24",
@@ -1868,15 +2066,15 @@ var FOLD_ALL_ICON = /* @__PURE__ */ jsxs20(
1868
2066
  strokeLinecap: "round",
1869
2067
  strokeLinejoin: "round",
1870
2068
  children: [
1871
- /* @__PURE__ */ jsx20("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }),
1872
- /* @__PURE__ */ jsx20("polyline", { points: "2 2 6 6 2 6" }),
1873
- /* @__PURE__ */ jsx20("polyline", { points: "22 2 18 6 22 6" }),
1874
- /* @__PURE__ */ jsx20("polyline", { points: "2 22 6 18 2 18" }),
1875
- /* @__PURE__ */ jsx20("polyline", { points: "22 22 18 18 22 18" })
2069
+ /* @__PURE__ */ jsx21("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }),
2070
+ /* @__PURE__ */ jsx21("polyline", { points: "2 2 6 6 2 6" }),
2071
+ /* @__PURE__ */ jsx21("polyline", { points: "22 2 18 6 22 6" }),
2072
+ /* @__PURE__ */ jsx21("polyline", { points: "2 22 6 18 2 18" }),
2073
+ /* @__PURE__ */ jsx21("polyline", { points: "22 22 18 18 22 18" })
1876
2074
  ]
1877
2075
  }
1878
2076
  );
1879
- var EXPAND_ALL_ICON = /* @__PURE__ */ jsxs20(
2077
+ var EXPAND_ALL_ICON = /* @__PURE__ */ jsxs21(
1880
2078
  "svg",
1881
2079
  {
1882
2080
  viewBox: "0 0 24 24",
@@ -1888,15 +2086,15 @@ var EXPAND_ALL_ICON = /* @__PURE__ */ jsxs20(
1888
2086
  strokeLinecap: "round",
1889
2087
  strokeLinejoin: "round",
1890
2088
  children: [
1891
- /* @__PURE__ */ jsx20("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1" }),
1892
- /* @__PURE__ */ jsx20("polyline", { points: "3 3 7 7 3 7" }),
1893
- /* @__PURE__ */ jsx20("polyline", { points: "21 3 17 7 21 7" }),
1894
- /* @__PURE__ */ jsx20("polyline", { points: "3 21 7 17 3 17" }),
1895
- /* @__PURE__ */ jsx20("polyline", { points: "21 21 17 17 21 17" })
2089
+ /* @__PURE__ */ jsx21("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1" }),
2090
+ /* @__PURE__ */ jsx21("polyline", { points: "3 3 7 7 3 7" }),
2091
+ /* @__PURE__ */ jsx21("polyline", { points: "21 3 17 7 21 7" }),
2092
+ /* @__PURE__ */ jsx21("polyline", { points: "3 21 7 17 3 17" }),
2093
+ /* @__PURE__ */ jsx21("polyline", { points: "21 21 17 17 21 17" })
1896
2094
  ]
1897
2095
  }
1898
2096
  );
1899
- var SUN_ICON = /* @__PURE__ */ jsxs20(
2097
+ var SUN_ICON = /* @__PURE__ */ jsxs21(
1900
2098
  "svg",
1901
2099
  {
1902
2100
  viewBox: "0 0 24 24",
@@ -1908,19 +2106,19 @@ var SUN_ICON = /* @__PURE__ */ jsxs20(
1908
2106
  strokeLinecap: "round",
1909
2107
  strokeLinejoin: "round",
1910
2108
  children: [
1911
- /* @__PURE__ */ jsx20("circle", { cx: "12", cy: "12", r: "4" }),
1912
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "2", x2: "12", y2: "4" }),
1913
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "20", x2: "12", y2: "22" }),
1914
- /* @__PURE__ */ jsx20("line", { x1: "4.93", y1: "4.93", x2: "6.34", y2: "6.34" }),
1915
- /* @__PURE__ */ jsx20("line", { x1: "17.66", y1: "17.66", x2: "19.07", y2: "19.07" }),
1916
- /* @__PURE__ */ jsx20("line", { x1: "2", y1: "12", x2: "4", y2: "12" }),
1917
- /* @__PURE__ */ jsx20("line", { x1: "20", y1: "12", x2: "22", y2: "12" }),
1918
- /* @__PURE__ */ jsx20("line", { x1: "4.93", y1: "19.07", x2: "6.34", y2: "17.66" }),
1919
- /* @__PURE__ */ jsx20("line", { x1: "17.66", y1: "6.34", x2: "19.07", y2: "4.93" })
2109
+ /* @__PURE__ */ jsx21("circle", { cx: "12", cy: "12", r: "4" }),
2110
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "2", x2: "12", y2: "4" }),
2111
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "20", x2: "12", y2: "22" }),
2112
+ /* @__PURE__ */ jsx21("line", { x1: "4.93", y1: "4.93", x2: "6.34", y2: "6.34" }),
2113
+ /* @__PURE__ */ jsx21("line", { x1: "17.66", y1: "17.66", x2: "19.07", y2: "19.07" }),
2114
+ /* @__PURE__ */ jsx21("line", { x1: "2", y1: "12", x2: "4", y2: "12" }),
2115
+ /* @__PURE__ */ jsx21("line", { x1: "20", y1: "12", x2: "22", y2: "12" }),
2116
+ /* @__PURE__ */ jsx21("line", { x1: "4.93", y1: "19.07", x2: "6.34", y2: "17.66" }),
2117
+ /* @__PURE__ */ jsx21("line", { x1: "17.66", y1: "6.34", x2: "19.07", y2: "4.93" })
1920
2118
  ]
1921
2119
  }
1922
2120
  );
1923
- var MOON_ICON = /* @__PURE__ */ jsx20(
2121
+ var MOON_ICON = /* @__PURE__ */ jsx21(
1924
2122
  "svg",
1925
2123
  {
1926
2124
  viewBox: "0 0 24 24",
@@ -1931,10 +2129,10 @@ var MOON_ICON = /* @__PURE__ */ jsx20(
1931
2129
  strokeWidth: "2",
1932
2130
  strokeLinecap: "round",
1933
2131
  strokeLinejoin: "round",
1934
- children: /* @__PURE__ */ jsx20("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
2132
+ children: /* @__PURE__ */ jsx21("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
1935
2133
  }
1936
2134
  );
1937
- var MONITOR_ICON = /* @__PURE__ */ jsxs20(
2135
+ var MONITOR_ICON = /* @__PURE__ */ jsxs21(
1938
2136
  "svg",
1939
2137
  {
1940
2138
  viewBox: "0 0 24 24",
@@ -1946,13 +2144,13 @@ var MONITOR_ICON = /* @__PURE__ */ jsxs20(
1946
2144
  strokeLinecap: "round",
1947
2145
  strokeLinejoin: "round",
1948
2146
  children: [
1949
- /* @__PURE__ */ jsx20("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
1950
- /* @__PURE__ */ jsx20("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
1951
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
2147
+ /* @__PURE__ */ jsx21("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
2148
+ /* @__PURE__ */ jsx21("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
2149
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
1952
2150
  ]
1953
2151
  }
1954
2152
  );
1955
- var SPINNER_ICON = /* @__PURE__ */ jsx20(
2153
+ var SPINNER_ICON = /* @__PURE__ */ jsx21(
1956
2154
  "svg",
1957
2155
  {
1958
2156
  className: "graph-toolbar-validation-spin",
@@ -1964,10 +2162,10 @@ var SPINNER_ICON = /* @__PURE__ */ jsx20(
1964
2162
  strokeWidth: "2",
1965
2163
  strokeLinecap: "round",
1966
2164
  strokeLinejoin: "round",
1967
- children: /* @__PURE__ */ jsx20("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
2165
+ children: /* @__PURE__ */ jsx21("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
1968
2166
  }
1969
2167
  );
1970
- var CHECK_ICON2 = /* @__PURE__ */ jsx20(
2168
+ var CHECK_ICON3 = /* @__PURE__ */ jsx21(
1971
2169
  "svg",
1972
2170
  {
1973
2171
  viewBox: "0 0 24 24",
@@ -1978,10 +2176,10 @@ var CHECK_ICON2 = /* @__PURE__ */ jsx20(
1978
2176
  strokeWidth: "2",
1979
2177
  strokeLinecap: "round",
1980
2178
  strokeLinejoin: "round",
1981
- children: /* @__PURE__ */ jsx20("polyline", { points: "20 6 9 17 4 12" })
2179
+ children: /* @__PURE__ */ jsx21("polyline", { points: "20 6 9 17 4 12" })
1982
2180
  }
1983
2181
  );
1984
- var X_CIRCLE_ICON = /* @__PURE__ */ jsxs20(
2182
+ var X_CIRCLE_ICON = /* @__PURE__ */ jsxs21(
1985
2183
  "svg",
1986
2184
  {
1987
2185
  viewBox: "0 0 24 24",
@@ -1993,13 +2191,13 @@ var X_CIRCLE_ICON = /* @__PURE__ */ jsxs20(
1993
2191
  strokeLinecap: "round",
1994
2192
  strokeLinejoin: "round",
1995
2193
  children: [
1996
- /* @__PURE__ */ jsx20("circle", { cx: "12", cy: "12", r: "10" }),
1997
- /* @__PURE__ */ jsx20("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
1998
- /* @__PURE__ */ jsx20("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
2194
+ /* @__PURE__ */ jsx21("circle", { cx: "12", cy: "12", r: "10" }),
2195
+ /* @__PURE__ */ jsx21("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
2196
+ /* @__PURE__ */ jsx21("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
1999
2197
  ]
2000
2198
  }
2001
2199
  );
2002
- var ALERT_TRIANGLE_ICON = /* @__PURE__ */ jsxs20(
2200
+ var ALERT_TRIANGLE_ICON = /* @__PURE__ */ jsxs21(
2003
2201
  "svg",
2004
2202
  {
2005
2203
  viewBox: "0 0 24 24",
@@ -2011,13 +2209,13 @@ var ALERT_TRIANGLE_ICON = /* @__PURE__ */ jsxs20(
2011
2209
  strokeLinecap: "round",
2012
2210
  strokeLinejoin: "round",
2013
2211
  children: [
2014
- /* @__PURE__ */ jsx20("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" }),
2015
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
2016
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
2212
+ /* @__PURE__ */ jsx21("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" }),
2213
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
2214
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
2017
2215
  ]
2018
2216
  }
2019
2217
  );
2020
- var INFO_CIRCLE_ICON = /* @__PURE__ */ jsxs20(
2218
+ var INFO_CIRCLE_ICON = /* @__PURE__ */ jsxs21(
2021
2219
  "svg",
2022
2220
  {
2023
2221
  viewBox: "0 0 24 24",
@@ -2029,9 +2227,9 @@ var INFO_CIRCLE_ICON = /* @__PURE__ */ jsxs20(
2029
2227
  strokeLinecap: "round",
2030
2228
  strokeLinejoin: "round",
2031
2229
  children: [
2032
- /* @__PURE__ */ jsx20("circle", { cx: "12", cy: "12", r: "10" }),
2033
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
2034
- /* @__PURE__ */ jsx20("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
2230
+ /* @__PURE__ */ jsx21("circle", { cx: "12", cy: "12", r: "10" }),
2231
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
2232
+ /* @__PURE__ */ jsx21("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
2035
2233
  ]
2036
2234
  }
2037
2235
  );
@@ -2040,7 +2238,7 @@ function validationIcon(state) {
2040
2238
  case VALIDATION_STATE.VALIDATING:
2041
2239
  return SPINNER_ICON;
2042
2240
  case VALIDATION_STATE.VALID:
2043
- return CHECK_ICON2;
2241
+ return CHECK_ICON3;
2044
2242
  case VALIDATION_STATE.INVALID:
2045
2243
  return X_CIRCLE_ICON;
2046
2244
  case VALIDATION_STATE.ERROR:
@@ -2081,6 +2279,9 @@ function GraphToolbar({
2081
2279
  onDirectionChange,
2082
2280
  showControllers,
2083
2281
  onShowControllersChange,
2282
+ graphStyle,
2283
+ styleMenuOptions = [],
2284
+ onGraphStyleChange,
2084
2285
  onZoomIn,
2085
2286
  onZoomOut,
2086
2287
  onFitView,
@@ -2102,31 +2303,15 @@ function GraphToolbar({
2102
2303
  const orientation = toolbarOrientation(position);
2103
2304
  const setValidationOpen = onValidationOpenChange != null ? onValidationOpenChange : (() => {
2104
2305
  });
2105
- const setValidationOpenRef = React8.useRef(setValidationOpen);
2306
+ const setValidationOpenRef = React10.useRef(setValidationOpen);
2106
2307
  setValidationOpenRef.current = setValidationOpen;
2107
- const validationRef = React8.useRef(null);
2108
- const validationPanelId = React8.useId();
2109
- React8.useEffect(() => {
2308
+ const validationRef = React10.useRef(null);
2309
+ const validationPanelId = React10.useId();
2310
+ React10.useEffect(() => {
2110
2311
  if (validationState === void 0) setValidationOpenRef.current(false);
2111
2312
  }, [validationState]);
2112
- React8.useEffect(() => {
2113
- if (!validationOpen) return;
2114
- const onPointerDown = (event) => {
2115
- const wrapper = validationRef.current;
2116
- if (wrapper && event.target instanceof Node && !wrapper.contains(event.target)) {
2117
- setValidationOpenRef.current(false);
2118
- }
2119
- };
2120
- const onKeyDown = (event) => {
2121
- if (event.key === "Escape") setValidationOpenRef.current(false);
2122
- };
2123
- document.addEventListener("mousedown", onPointerDown);
2124
- document.addEventListener("keydown", onKeyDown);
2125
- return () => {
2126
- document.removeEventListener("mousedown", onPointerDown);
2127
- document.removeEventListener("keydown", onKeyDown);
2128
- };
2129
- }, [validationOpen]);
2313
+ usePopoverDismiss(validationOpen, validationRef, () => setValidationOpenRef.current(false));
2314
+ const styleMenuEnabled = graphStyle !== void 0 && onGraphStyleChange !== void 0 && styleMenuOptions.length >= 2;
2130
2315
  const dodgesDetailPanel = toolbarSide(position) === "right" && rightOffset > 0;
2131
2316
  const panelStyle = dodgesDetailPanel ? { marginRight: REACTFLOW_PANEL_MARGIN + rightOffset } : void 0;
2132
2317
  const isVertical = direction === GRAPH_DIRECTION.TB || direction === GRAPH_DIRECTION.BT;
@@ -2135,10 +2320,10 @@ function GraphToolbar({
2135
2320
  const foldAllSection = onFoldAll || onExpandAll;
2136
2321
  const foldAllTitle = foldAllDisabled ? "Fold all controllers (nothing to fold)" : "Fold all controllers";
2137
2322
  const expandAllTitle = expandAllDisabled ? "Expand all controllers (nothing to expand)" : "Expand all controllers";
2138
- return /* @__PURE__ */ jsx20(Panel, { position, className: "graph-toolbar-panel", style: panelStyle, children: /* @__PURE__ */ jsxs20("div", { className: `graph-toolbar graph-toolbar--${orientation}`, children: [
2139
- validationState !== void 0 && /* @__PURE__ */ jsxs20(Fragment12, { children: [
2140
- /* @__PURE__ */ jsxs20("div", { className: "graph-toolbar-validation", ref: validationRef, children: [
2141
- /* @__PURE__ */ jsxs20(
2323
+ return /* @__PURE__ */ jsx21(Panel, { position, className: "graph-toolbar-panel", style: panelStyle, children: /* @__PURE__ */ jsxs21("div", { className: `graph-toolbar graph-toolbar--${orientation}`, children: [
2324
+ validationState !== void 0 && /* @__PURE__ */ jsxs21(Fragment12, { children: [
2325
+ /* @__PURE__ */ jsxs21("div", { className: "graph-toolbar-validation", ref: validationRef, children: [
2326
+ /* @__PURE__ */ jsxs21(
2142
2327
  "button",
2143
2328
  {
2144
2329
  type: "button",
@@ -2151,11 +2336,11 @@ function GraphToolbar({
2151
2336
  "aria-controls": validationPanelId,
2152
2337
  children: [
2153
2338
  validationIcon(validationState),
2154
- validationIssues.length > 0 && /* @__PURE__ */ jsx20("span", { className: "graph-toolbar-validation-badge", children: validationIssues.length > 99 ? "99+" : validationIssues.length })
2339
+ validationIssues.length > 0 && /* @__PURE__ */ jsx21("span", { className: "graph-toolbar-validation-badge", children: validationIssues.length > 99 ? "99+" : validationIssues.length })
2155
2340
  ]
2156
2341
  }
2157
2342
  ),
2158
- validationOpen && /* @__PURE__ */ jsx20(
2343
+ validationOpen && /* @__PURE__ */ jsx21(
2159
2344
  ValidationPanel,
2160
2345
  {
2161
2346
  id: validationPanelId,
@@ -2166,9 +2351,21 @@ function GraphToolbar({
2166
2351
  }
2167
2352
  )
2168
2353
  ] }),
2169
- /* @__PURE__ */ jsx20("div", { className: "graph-toolbar-separator" })
2354
+ /* @__PURE__ */ jsx21("div", { className: "graph-toolbar-separator" })
2355
+ ] }),
2356
+ styleMenuEnabled && /* @__PURE__ */ jsxs21(Fragment12, { children: [
2357
+ /* @__PURE__ */ jsx21(
2358
+ StyleMenu,
2359
+ {
2360
+ value: graphStyle,
2361
+ options: styleMenuOptions,
2362
+ onChange: onGraphStyleChange,
2363
+ placement: validationPanelPlacement(position)
2364
+ }
2365
+ ),
2366
+ /* @__PURE__ */ jsx21("div", { className: "graph-toolbar-separator" })
2170
2367
  ] }),
2171
- onFoldAll && /* @__PURE__ */ jsx20(
2368
+ onFoldAll && /* @__PURE__ */ jsx21(
2172
2369
  "button",
2173
2370
  {
2174
2371
  type: "button",
@@ -2180,7 +2377,7 @@ function GraphToolbar({
2180
2377
  children: FOLD_ALL_ICON
2181
2378
  }
2182
2379
  ),
2183
- onExpandAll && /* @__PURE__ */ jsx20(
2380
+ onExpandAll && /* @__PURE__ */ jsx21(
2184
2381
  "button",
2185
2382
  {
2186
2383
  type: "button",
@@ -2192,8 +2389,8 @@ function GraphToolbar({
2192
2389
  children: EXPAND_ALL_ICON
2193
2390
  }
2194
2391
  ),
2195
- foldAllSection && /* @__PURE__ */ jsx20("div", { className: "graph-toolbar-separator" }),
2196
- /* @__PURE__ */ jsx20(
2392
+ foldAllSection && /* @__PURE__ */ jsx21("div", { className: "graph-toolbar-separator" }),
2393
+ onShowControllersChange && /* @__PURE__ */ jsx21(
2197
2394
  "button",
2198
2395
  {
2199
2396
  type: "button",
@@ -2204,7 +2401,7 @@ function GraphToolbar({
2204
2401
  children: BOXES_ICON
2205
2402
  }
2206
2403
  ),
2207
- /* @__PURE__ */ jsx20(
2404
+ /* @__PURE__ */ jsx21(
2208
2405
  "button",
2209
2406
  {
2210
2407
  type: "button",
@@ -2215,8 +2412,8 @@ function GraphToolbar({
2215
2412
  children: isVertical ? ARROW_RIGHT_ICON : ARROW_DOWN_ICON
2216
2413
  }
2217
2414
  ),
2218
- (onZoomOut || onZoomIn || onFitView) && /* @__PURE__ */ jsx20("div", { className: "graph-toolbar-separator" }),
2219
- onZoomOut && /* @__PURE__ */ jsx20(
2415
+ (onZoomOut || onZoomIn || onFitView) && /* @__PURE__ */ jsx21("div", { className: "graph-toolbar-separator" }),
2416
+ onZoomOut && /* @__PURE__ */ jsx21(
2220
2417
  "button",
2221
2418
  {
2222
2419
  type: "button",
@@ -2227,7 +2424,7 @@ function GraphToolbar({
2227
2424
  children: MINUS_ICON
2228
2425
  }
2229
2426
  ),
2230
- onZoomIn && /* @__PURE__ */ jsx20(
2427
+ onZoomIn && /* @__PURE__ */ jsx21(
2231
2428
  "button",
2232
2429
  {
2233
2430
  type: "button",
@@ -2238,7 +2435,7 @@ function GraphToolbar({
2238
2435
  children: PLUS_ICON
2239
2436
  }
2240
2437
  ),
2241
- onFitView && /* @__PURE__ */ jsx20(
2438
+ onFitView && /* @__PURE__ */ jsx21(
2242
2439
  "button",
2243
2440
  {
2244
2441
  type: "button",
@@ -2249,9 +2446,9 @@ function GraphToolbar({
2249
2446
  children: FIT_VIEW_ICON
2250
2447
  }
2251
2448
  ),
2252
- themeToggleEnabled && /* @__PURE__ */ jsxs20(Fragment12, { children: [
2253
- /* @__PURE__ */ jsx20("div", { className: "graph-toolbar-separator" }),
2254
- /* @__PURE__ */ jsx20(
2449
+ themeToggleEnabled && /* @__PURE__ */ jsxs21(Fragment12, { children: [
2450
+ /* @__PURE__ */ jsx21("div", { className: "graph-toolbar-separator" }),
2451
+ /* @__PURE__ */ jsx21(
2255
2452
  "button",
2256
2453
  {
2257
2454
  type: "button",
@@ -2267,7 +2464,7 @@ function GraphToolbar({
2267
2464
  }
2268
2465
 
2269
2466
  // src/graph/react/nodes/NodeValidationBadge.tsx
2270
- import { jsx as jsx21 } from "react/jsx-runtime";
2467
+ import { jsx as jsx22 } from "react/jsx-runtime";
2271
2468
  function NodeValidationBadge({
2272
2469
  validation,
2273
2470
  onClick
@@ -2277,9 +2474,9 @@ function NodeValidationBadge({
2277
2474
  const className = `node-validation-badge node-validation-badge--${validation.severity}`;
2278
2475
  const text = validation.count > 99 ? "99+" : String(validation.count);
2279
2476
  if (!onClick) {
2280
- return /* @__PURE__ */ jsx21("span", { className, title: tooltip, "aria-label": label, children: text });
2477
+ return /* @__PURE__ */ jsx22("span", { className, title: tooltip, "aria-label": label, children: text });
2281
2478
  }
2282
- return /* @__PURE__ */ jsx21(
2479
+ return /* @__PURE__ */ jsx22(
2283
2480
  "button",
2284
2481
  {
2285
2482
  type: "button",
@@ -2299,7 +2496,7 @@ function validationRingClass(validation) {
2299
2496
  }
2300
2497
 
2301
2498
  // src/graph/react/nodes/controller/ControllerGroupNode.tsx
2302
- import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
2499
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
2303
2500
  var CONTROLLER_CONFIG = {
2304
2501
  PipeSequence: { badge: "Sequence", icon: "\u2192" },
2305
2502
  PipeParallel: { badge: "Parallel", icon: "//" },
@@ -2321,12 +2518,12 @@ function ControllerGroupNode({ data }) {
2321
2518
  const modifier = getControllerModifier(data.pipeType);
2322
2519
  const isCollapsible = (data.pipeType === "PipeParallel" || data.pipeType === "PipeBatch") && ((_a = data.childCount) != null ? _a : 0) > MAX_VISIBLE_CONTROLLER_CHILDREN;
2323
2520
  const hiddenCount = isCollapsible ? ((_b = data.childCount) != null ? _b : 0) - MAX_VISIBLE_CONTROLLER_CHILDREN : 0;
2324
- return /* @__PURE__ */ jsxs21("div", { className: `controller-group-node ${modifier}${validationRingClass(data.validation)}`, children: [
2325
- /* @__PURE__ */ jsxs21("div", { className: "controller-group-header", children: [
2326
- /* @__PURE__ */ jsx22("span", { className: "controller-group-icon", children: config.icon }),
2327
- /* @__PURE__ */ jsx22("span", { className: "controller-group-badge", children: config.badge }),
2328
- data.label && /* @__PURE__ */ jsx22("span", { className: "controller-group-label", children: data.label }),
2329
- data.onToggleFold && /* @__PURE__ */ jsx22(
2521
+ return /* @__PURE__ */ jsxs22("div", { className: `controller-group-node ${modifier}${validationRingClass(data.validation)}`, children: [
2522
+ /* @__PURE__ */ jsxs22("div", { className: "controller-group-header", children: [
2523
+ /* @__PURE__ */ jsx23("span", { className: "controller-group-icon", children: config.icon }),
2524
+ /* @__PURE__ */ jsx23("span", { className: "controller-group-badge", children: config.badge }),
2525
+ data.label && /* @__PURE__ */ jsx23("span", { className: "controller-group-label", children: data.label }),
2526
+ data.onToggleFold && /* @__PURE__ */ jsx23(
2330
2527
  "button",
2331
2528
  {
2332
2529
  type: "button",
@@ -2341,9 +2538,9 @@ function ControllerGroupNode({ data }) {
2341
2538
  children: "\u2921"
2342
2539
  }
2343
2540
  ),
2344
- data.validation && /* @__PURE__ */ jsx22(NodeValidationBadge, { validation: data.validation, onClick: data.onValidationBadgeClick })
2541
+ data.validation && /* @__PURE__ */ jsx23(NodeValidationBadge, { validation: data.validation, onClick: data.onValidationBadgeClick })
2345
2542
  ] }),
2346
- isCollapsible && /* @__PURE__ */ jsx22(
2543
+ isCollapsible && /* @__PURE__ */ jsx23(
2347
2544
  "button",
2348
2545
  {
2349
2546
  className: "controller-group-collapse",
@@ -2364,7 +2561,7 @@ import { Handle, Position } from "@xyflow/react";
2364
2561
 
2365
2562
  // src/graph/react/nodes/pipe/PipeCardBase.tsx
2366
2563
  import { useState as useState2 } from "react";
2367
- import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
2564
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
2368
2565
  var PIPE_TYPE_BADGES2 = {
2369
2566
  PipeLLM: "LLM",
2370
2567
  PipeExtract: "Extract",
@@ -2425,21 +2622,21 @@ function PipeCardBase({ data, children }) {
2425
2622
  const staticClass = isStatic ? " pipe-card--static" : "";
2426
2623
  const badgeClass = isController ? "pipe-card-badge pipe-card-badge--controller" : isSignature ? "pipe-card-badge pipe-card-badge--signature" : isBinding ? "pipe-card-badge pipe-card-badge--binding" : "pipe-card-badge";
2427
2624
  const ringClass = validationRingClass(data.validation);
2428
- return /* @__PURE__ */ jsxs22(
2625
+ return /* @__PURE__ */ jsxs23(
2429
2626
  "div",
2430
2627
  {
2431
2628
  className: `pipe-card ${dirClass}${controllerClass}${signatureClass}${bindingClass}${staticClass}${ringClass}`,
2432
2629
  children: [
2433
- /* @__PURE__ */ jsxs22("div", { className: "pipe-card-header", children: [
2434
- /* @__PURE__ */ jsx23("span", { className: badgeClass, children: badge }),
2435
- /* @__PURE__ */ jsx23("span", { className: "pipe-card-code", title: data.pipeCode, children: data.pipeCode }),
2436
- !isStatic && /* @__PURE__ */ jsx23(
2630
+ /* @__PURE__ */ jsxs23("div", { className: "pipe-card-header", children: [
2631
+ /* @__PURE__ */ jsx24("span", { className: badgeClass, children: badge }),
2632
+ /* @__PURE__ */ jsx24("span", { className: "pipe-card-code", title: data.pipeCode, children: data.pipeCode }),
2633
+ !isStatic && /* @__PURE__ */ jsx24(
2437
2634
  "span",
2438
2635
  {
2439
2636
  className: "pipe-card-status",
2440
2637
  style: { color: statusConfig.color },
2441
2638
  title: statusConfig.label,
2442
- children: /* @__PURE__ */ jsx23(
2639
+ children: /* @__PURE__ */ jsx24(
2443
2640
  "span",
2444
2641
  {
2445
2642
  className: `pipe-card-status-dot ${isRunning ? "pipe-card-status-dot--pulse" : ""}`,
@@ -2448,7 +2645,7 @@ function PipeCardBase({ data, children }) {
2448
2645
  )
2449
2646
  }
2450
2647
  ),
2451
- data.onExpand && /* @__PURE__ */ jsx23(
2648
+ data.onExpand && /* @__PURE__ */ jsx24(
2452
2649
  "button",
2453
2650
  {
2454
2651
  type: "button",
@@ -2463,32 +2660,32 @@ function PipeCardBase({ data, children }) {
2463
2660
  children: "\u2922"
2464
2661
  }
2465
2662
  ),
2466
- data.validation && /* @__PURE__ */ jsx23(NodeValidationBadge, { validation: data.validation, onClick: data.onValidationBadgeClick })
2663
+ data.validation && /* @__PURE__ */ jsx24(NodeValidationBadge, { validation: data.validation, onClick: data.onValidationBadgeClick })
2467
2664
  ] }),
2468
- (outcome || batchMultiplicity) && /* @__PURE__ */ jsxs22("div", { className: "pipe-card-annotations", children: [
2469
- outcome && /* @__PURE__ */ jsxs22("span", { className: "pipe-card-annotation pipe-card-annotation--outcome", children: [
2665
+ (outcome || batchMultiplicity) && /* @__PURE__ */ jsxs23("div", { className: "pipe-card-annotations", children: [
2666
+ outcome && /* @__PURE__ */ jsxs23("span", { className: "pipe-card-annotation pipe-card-annotation--outcome", children: [
2470
2667
  "outcome: ",
2471
2668
  outcome
2472
2669
  ] }),
2473
- batchMultiplicity && /* @__PURE__ */ jsx23("span", { className: "pipe-card-annotation pipe-card-annotation--batch", children: batchMultiplicity })
2670
+ batchMultiplicity && /* @__PURE__ */ jsx24("span", { className: "pipe-card-annotation pipe-card-annotation--batch", children: batchMultiplicity })
2474
2671
  ] }),
2475
- data.description && /* @__PURE__ */ jsx23("span", { className: "pipe-card-description", title: data.description, children: data.description }),
2476
- data.inputs.length > 0 && /* @__PURE__ */ jsxs22("div", { className: "pipe-card-io", children: [
2477
- /* @__PURE__ */ jsx23("span", { className: "pipe-card-io-label", children: "INPUTS" }),
2478
- /* @__PURE__ */ jsxs22("div", { className: "pipe-card-io-pills", children: [
2479
- visibleInputs.map((input) => /* @__PURE__ */ jsxs22(
2672
+ data.description && /* @__PURE__ */ jsx24("span", { className: "pipe-card-description", title: data.description, children: data.description }),
2673
+ data.inputs.length > 0 && /* @__PURE__ */ jsxs23("div", { className: "pipe-card-io", children: [
2674
+ /* @__PURE__ */ jsx24("span", { className: "pipe-card-io-label", children: "INPUTS" }),
2675
+ /* @__PURE__ */ jsxs23("div", { className: "pipe-card-io-pills", children: [
2676
+ visibleInputs.map((input) => /* @__PURE__ */ jsxs23(
2480
2677
  "span",
2481
2678
  {
2482
2679
  className: "pipe-card-io-pill",
2483
2680
  title: `${input.name}: ${input.concept}`,
2484
2681
  children: [
2485
- /* @__PURE__ */ jsx23("span", { className: "pipe-card-io-pill-name", children: input.name }),
2486
- /* @__PURE__ */ jsx23("span", { className: "pipe-card-io-pill-concept", children: input.concept })
2682
+ /* @__PURE__ */ jsx24("span", { className: "pipe-card-io-pill-name", children: input.name }),
2683
+ /* @__PURE__ */ jsx24("span", { className: "pipe-card-io-pill-concept", children: input.concept })
2487
2684
  ]
2488
2685
  },
2489
2686
  input.name
2490
2687
  )),
2491
- hasMany && /* @__PURE__ */ jsx23(
2688
+ hasMany && /* @__PURE__ */ jsx24(
2492
2689
  "button",
2493
2690
  {
2494
2691
  className: "pipe-card-io-more",
@@ -2501,16 +2698,16 @@ function PipeCardBase({ data, children }) {
2501
2698
  )
2502
2699
  ] })
2503
2700
  ] }),
2504
- data.outputs.length > 0 && /* @__PURE__ */ jsxs22("div", { className: "pipe-card-io", children: [
2505
- /* @__PURE__ */ jsx23("span", { className: "pipe-card-io-label", children: "OUTPUT" }),
2506
- /* @__PURE__ */ jsx23("div", { className: "pipe-card-io-pills", children: data.outputs.map((output) => /* @__PURE__ */ jsxs22(
2701
+ data.outputs.length > 0 && /* @__PURE__ */ jsxs23("div", { className: "pipe-card-io", children: [
2702
+ /* @__PURE__ */ jsx24("span", { className: "pipe-card-io-label", children: "OUTPUT" }),
2703
+ /* @__PURE__ */ jsx24("div", { className: "pipe-card-io-pills", children: data.outputs.map((output) => /* @__PURE__ */ jsxs23(
2507
2704
  "span",
2508
2705
  {
2509
2706
  className: "pipe-card-io-pill",
2510
2707
  title: `${output.name}: ${output.concept}`,
2511
2708
  children: [
2512
- /* @__PURE__ */ jsx23("span", { className: "pipe-card-io-pill-name", children: output.name }),
2513
- /* @__PURE__ */ jsx23("span", { className: "pipe-card-io-pill-concept", children: output.concept })
2709
+ /* @__PURE__ */ jsx24("span", { className: "pipe-card-io-pill-name", children: output.name }),
2710
+ /* @__PURE__ */ jsx24("span", { className: "pipe-card-io-pill-concept", children: output.concept })
2514
2711
  ]
2515
2712
  },
2516
2713
  output.name
@@ -2545,11 +2742,11 @@ function getPipeCardComponent(pipeType) {
2545
2742
  }
2546
2743
 
2547
2744
  // src/graph/react/nodes/pipe/PipeCardNode.tsx
2548
- import { Fragment as Fragment13, jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
2745
+ import { Fragment as Fragment13, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
2549
2746
  function PipeCardNode({ data }) {
2550
2747
  var _a;
2551
2748
  const Card = (_a = getPipeCardComponent(data.pipeType)) != null ? _a : PipeCardBase;
2552
- return /* @__PURE__ */ jsx24(Card, { data });
2749
+ return /* @__PURE__ */ jsx25(Card, { data });
2553
2750
  }
2554
2751
  function PipeCardRFNode({
2555
2752
  data,
@@ -2558,18 +2755,358 @@ function PipeCardRFNode({
2558
2755
  }) {
2559
2756
  const payload = data.pipeCardData;
2560
2757
  if (!payload) return null;
2561
- return /* @__PURE__ */ jsxs23(Fragment13, { children: [
2562
- /* @__PURE__ */ jsx24(Handle, { type: "target", position: targetPosition }),
2563
- /* @__PURE__ */ jsx24(PipeCardNode, { data: payload }),
2564
- /* @__PURE__ */ jsx24(Handle, { type: "source", position: sourcePosition })
2758
+ return /* @__PURE__ */ jsxs24(Fragment13, { children: [
2759
+ /* @__PURE__ */ jsx25(Handle, { type: "target", position: targetPosition }),
2760
+ /* @__PURE__ */ jsx25(PipeCardNode, { data: payload }),
2761
+ /* @__PURE__ */ jsx25(Handle, { type: "source", position: sourcePosition })
2565
2762
  ] });
2566
2763
  }
2567
2764
 
2765
+ // src/graph/react/styles/simple/SimpleNodes.tsx
2766
+ import { Handle as Handle2, Position as Position2 } from "@xyflow/react";
2767
+ import { Fragment as Fragment14, jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
2768
+ var ICON_PROPS2 = {
2769
+ viewBox: "0 0 24 24",
2770
+ fill: "none",
2771
+ stroke: "currentColor",
2772
+ strokeWidth: 2,
2773
+ strokeLinecap: "round",
2774
+ strokeLinejoin: "round",
2775
+ "aria-hidden": true
2776
+ };
2777
+ function Icon({ size = 13, children }) {
2778
+ return /* @__PURE__ */ jsx26("svg", __spreadProps(__spreadValues({}, ICON_PROPS2), { width: size, height: size, children }));
2779
+ }
2780
+ var CATEGORY_ICONS = {
2781
+ ai: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2782
+ /* @__PURE__ */ jsx26("path", { d: "M9.94 15.5a2 2 0 0 0-1.44-1.44l-6.13-1.58a.5.5 0 0 1 0-.96L8.5 9.94A2 2 0 0 0 9.94 8.5l1.58-6.14a.5.5 0 0 1 .96 0l1.58 6.14a2 2 0 0 0 1.44 1.44l6.14 1.58a.5.5 0 0 1 0 .96l-6.14 1.58a2 2 0 0 0-1.44 1.44l-1.58 6.13a.5.5 0 0 1-.96 0z" }),
2783
+ /* @__PURE__ */ jsx26("path", { d: "M20 3v4" }),
2784
+ /* @__PURE__ */ jsx26("path", { d: "M22 5h-4" })
2785
+ ] }),
2786
+ extract: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2787
+ /* @__PURE__ */ jsx26("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }),
2788
+ /* @__PURE__ */ jsx26("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }),
2789
+ /* @__PURE__ */ jsx26("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }),
2790
+ /* @__PURE__ */ jsx26("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" }),
2791
+ /* @__PURE__ */ jsx26("path", { d: "M7 8h8" }),
2792
+ /* @__PURE__ */ jsx26("path", { d: "M7 12h10" }),
2793
+ /* @__PURE__ */ jsx26("path", { d: "M7 16h6" })
2794
+ ] }),
2795
+ image: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2796
+ /* @__PURE__ */ jsx26("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
2797
+ /* @__PURE__ */ jsx26("circle", { cx: "9", cy: "9", r: "2" }),
2798
+ /* @__PURE__ */ jsx26("path", { d: "m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21" })
2799
+ ] }),
2800
+ search: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2801
+ /* @__PURE__ */ jsx26("circle", { cx: "11", cy: "11", r: "8" }),
2802
+ /* @__PURE__ */ jsx26("path", { d: "m21 21-4.3-4.3" })
2803
+ ] }),
2804
+ code: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2805
+ /* @__PURE__ */ jsx26("polyline", { points: "16 18 22 12 16 6" }),
2806
+ /* @__PURE__ */ jsx26("polyline", { points: "8 6 2 12 8 18" })
2807
+ ] }),
2808
+ template: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2809
+ /* @__PURE__ */ jsx26("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
2810
+ /* @__PURE__ */ jsx26("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
2811
+ /* @__PURE__ */ jsx26("path", { d: "M16 13H8" }),
2812
+ /* @__PURE__ */ jsx26("path", { d: "M16 17H8" })
2813
+ ] }),
2814
+ document: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2815
+ /* @__PURE__ */ jsx26("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
2816
+ /* @__PURE__ */ jsx26("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
2817
+ /* @__PURE__ */ jsx26("path", { d: "M12 18v-6" }),
2818
+ /* @__PURE__ */ jsx26("path", { d: "m9 15 3 3 3-3" })
2819
+ ] }),
2820
+ judge: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2821
+ /* @__PURE__ */ jsx26("path", { d: "m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
2822
+ /* @__PURE__ */ jsx26("path", { d: "m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
2823
+ /* @__PURE__ */ jsx26("path", { d: "M7 21h10" }),
2824
+ /* @__PURE__ */ jsx26("path", { d: "M12 3v18" }),
2825
+ /* @__PURE__ */ jsx26("path", { d: "M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2" })
2826
+ ] }),
2827
+ planned: /* @__PURE__ */ jsx26("circle", { cx: "12", cy: "12", r: "9", strokeDasharray: "3 3" }),
2828
+ steps: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2829
+ /* @__PURE__ */ jsx26("path", { d: "m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z" }),
2830
+ /* @__PURE__ */ jsx26("path", { d: "m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65" }),
2831
+ /* @__PURE__ */ jsx26("path", { d: "m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65" })
2832
+ ] }),
2833
+ parallel: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2834
+ /* @__PURE__ */ jsx26("path", { d: "M16 3h5v5" }),
2835
+ /* @__PURE__ */ jsx26("path", { d: "M8 3H3v5" }),
2836
+ /* @__PURE__ */ jsx26("path", { d: "M12 22v-8.3a4 4 0 0 0-1.17-2.87L3 3" }),
2837
+ /* @__PURE__ */ jsx26("path", { d: "m15 9 6-6" })
2838
+ ] }),
2839
+ decision: /* @__PURE__ */ jsx26("path", { d: "M12 2 22 12 12 22 2 12Z" }),
2840
+ repeat: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2841
+ /* @__PURE__ */ jsx26("path", { d: "m17 2 4 4-4 4" }),
2842
+ /* @__PURE__ */ jsx26("path", { d: "M3 11v-1a4 4 0 0 1 4-4h14" }),
2843
+ /* @__PURE__ */ jsx26("path", { d: "m7 22-4-4 4-4" }),
2844
+ /* @__PURE__ */ jsx26("path", { d: "M21 13v1a4 4 0 0 1-4 4H3" })
2845
+ ] }),
2846
+ pick: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2847
+ /* @__PURE__ */ jsx26("polyline", { points: "15 10 20 15 15 20" }),
2848
+ /* @__PURE__ */ jsx26("path", { d: "M4 4v7a4 4 0 0 0 4 4h12" })
2849
+ ] })
2850
+ };
2851
+ var EXPAND_ICON2 = /* @__PURE__ */ jsxs25(Icon, { size: 12, children: [
2852
+ /* @__PURE__ */ jsx26("polyline", { points: "15 3 21 3 21 9" }),
2853
+ /* @__PURE__ */ jsx26("polyline", { points: "9 21 3 21 3 15" }),
2854
+ /* @__PURE__ */ jsx26("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
2855
+ /* @__PURE__ */ jsx26("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
2856
+ ] });
2857
+ var COLLAPSE_ICON2 = /* @__PURE__ */ jsxs25(Icon, { size: 12, children: [
2858
+ /* @__PURE__ */ jsx26("polyline", { points: "4 14 10 14 10 20" }),
2859
+ /* @__PURE__ */ jsx26("polyline", { points: "20 10 14 10 14 4" }),
2860
+ /* @__PURE__ */ jsx26("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
2861
+ /* @__PURE__ */ jsx26("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
2862
+ ] });
2863
+ var STATUS_LABELS = {
2864
+ succeeded: "Done",
2865
+ failed: "Failed",
2866
+ running: "Running",
2867
+ scheduled: "Waiting",
2868
+ skipped: "Skipped",
2869
+ canceled: "Canceled"
2870
+ };
2871
+ var STATUS_ICONS = {
2872
+ succeeded: /* @__PURE__ */ jsx26("polyline", { points: "20 6 9 17 4 12" }),
2873
+ failed: /* @__PURE__ */ jsxs25(Fragment14, { children: [
2874
+ /* @__PURE__ */ jsx26("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2875
+ /* @__PURE__ */ jsx26("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2876
+ ] }),
2877
+ running: /* @__PURE__ */ jsx26("path", { d: "M21 12a9 9 0 1 1-6.22-8.56" }),
2878
+ scheduled: /* @__PURE__ */ jsx26("circle", { cx: "12", cy: "12", r: "8" }),
2879
+ skipped: /* @__PURE__ */ jsx26("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
2880
+ canceled: /* @__PURE__ */ jsx26("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
2881
+ };
2882
+ function StatusMark({ status, graphMode }) {
2883
+ if (graphMode === "static") return null;
2884
+ return /* @__PURE__ */ jsx26(
2885
+ "span",
2886
+ {
2887
+ className: `simple-status simple-status--${status}`,
2888
+ title: STATUS_LABELS[status],
2889
+ "aria-label": STATUS_LABELS[status],
2890
+ children: /* @__PURE__ */ jsx26(Icon, { size: 11, children: STATUS_ICONS[status] })
2891
+ }
2892
+ );
2893
+ }
2894
+ function Handles({
2895
+ sourcePosition = Position2.Right,
2896
+ targetPosition = Position2.Left,
2897
+ children
2898
+ }) {
2899
+ return /* @__PURE__ */ jsxs25(Fragment14, { children: [
2900
+ /* @__PURE__ */ jsx26(Handle2, { type: "target", position: targetPosition, className: "simple-handle" }),
2901
+ children,
2902
+ /* @__PURE__ */ jsx26(Handle2, { type: "source", position: sourcePosition, className: "simple-handle" })
2903
+ ] });
2904
+ }
2905
+ function ValidationMark({
2906
+ validation,
2907
+ onClick
2908
+ }) {
2909
+ return validation ? /* @__PURE__ */ jsx26(NodeValidationBadge, { validation, onClick }) : null;
2910
+ }
2911
+ function payloadOf(data, kinds) {
2912
+ const simple = data.simple;
2913
+ if (!simple || !kinds.includes(simple.kind)) return null;
2914
+ return simple;
2915
+ }
2916
+ function SimpleStepNode({ data, sourcePosition, targetPosition }) {
2917
+ const step = payloadOf(data, ["step"]);
2918
+ if (!step) return null;
2919
+ const statusClass = step.graphMode !== "static" ? ` simple-step--${step.status}` : "";
2920
+ return /* @__PURE__ */ jsx26(Handles, { sourcePosition, targetPosition, children: /* @__PURE__ */ jsxs25(
2921
+ "div",
2922
+ {
2923
+ className: `simple-step simple-step--${step.category}${statusClass}${validationRingClass(data.validation)}`,
2924
+ children: [
2925
+ /* @__PURE__ */ jsxs25("div", { className: "simple-step-header", children: [
2926
+ /* @__PURE__ */ jsxs25("span", { className: "simple-step-category", children: [
2927
+ /* @__PURE__ */ jsx26(Icon, { children: CATEGORY_ICONS[step.category] }),
2928
+ STEP_CATEGORY_WORDS[step.category]
2929
+ ] }),
2930
+ /* @__PURE__ */ jsx26(StatusMark, { status: step.status, graphMode: step.graphMode }),
2931
+ /* @__PURE__ */ jsx26(ValidationMark, { validation: data.validation, onClick: data.onValidationBadgeClick })
2932
+ ] }),
2933
+ /* @__PURE__ */ jsx26("div", { className: "simple-step-title", title: step.title, children: step.title }),
2934
+ step.forEach && /* @__PURE__ */ jsxs25("span", { className: "simple-step-foreach", children: [
2935
+ /* @__PURE__ */ jsx26(Icon, { size: 11, children: CATEGORY_ICONS.repeat }),
2936
+ step.forEach
2937
+ ] }),
2938
+ step.innerStepCount !== void 0 && /* @__PURE__ */ jsxs25(
2939
+ "button",
2940
+ {
2941
+ type: "button",
2942
+ className: "simple-step-open",
2943
+ title: "Show the steps inside (alt/option: only this one)",
2944
+ onClick: (event) => {
2945
+ var _a;
2946
+ event.stopPropagation();
2947
+ (_a = step.onExpand) == null ? void 0 : _a.call(step, { soloMode: event.altKey });
2948
+ },
2949
+ disabled: !step.onExpand,
2950
+ children: [
2951
+ EXPAND_ICON2,
2952
+ step.innerStepCount === 1 ? "1 step inside" : `${step.innerStepCount} steps inside`
2953
+ ]
2954
+ }
2955
+ )
2956
+ ]
2957
+ }
2958
+ ) });
2959
+ }
2960
+ var DOCUMENT_PATH = "M1 1 H99 V84 C80 98 62 74 44 86 C28 96 14 96 1 88 Z";
2961
+ function DocumentShape({ className }) {
2962
+ return /* @__PURE__ */ jsx26("svg", { className, viewBox: "0 0 100 100", preserveAspectRatio: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx26("path", { d: DOCUMENT_PATH, vectorEffect: "non-scaling-stroke" }) });
2963
+ }
2964
+ function SimpleTerminalNode({ data, sourcePosition, targetPosition }) {
2965
+ const terminal = payloadOf(data, ["input", "output"]);
2966
+ if (!terminal) return null;
2967
+ return /* @__PURE__ */ jsx26(Handles, { sourcePosition, targetPosition, children: /* @__PURE__ */ jsxs25(
2968
+ "div",
2969
+ {
2970
+ className: `simple-terminal simple-terminal--${terminal.kind}${terminal.isList ? " simple-terminal--list" : ""}`,
2971
+ children: [
2972
+ terminal.isList && /* @__PURE__ */ jsxs25(Fragment14, { children: [
2973
+ /* @__PURE__ */ jsx26(DocumentShape, { className: "simple-terminal-shape simple-terminal-shape--back2" }),
2974
+ /* @__PURE__ */ jsx26(DocumentShape, { className: "simple-terminal-shape simple-terminal-shape--back1" })
2975
+ ] }),
2976
+ /* @__PURE__ */ jsx26(DocumentShape, { className: "simple-terminal-shape" }),
2977
+ /* @__PURE__ */ jsxs25("div", { className: "simple-terminal-text", children: [
2978
+ /* @__PURE__ */ jsx26("span", { className: "simple-terminal-title", title: terminal.title, children: terminal.title }),
2979
+ terminal.subtitle && /* @__PURE__ */ jsx26("span", { className: "simple-terminal-subtitle", children: terminal.subtitle })
2980
+ ] })
2981
+ ]
2982
+ }
2983
+ ) });
2984
+ }
2985
+ function SimpleDecisionNode({ data, sourcePosition, targetPosition }) {
2986
+ const decision = payloadOf(data, ["decision"]);
2987
+ if (!decision) return null;
2988
+ const statusClass = decision.graphMode !== "static" ? ` simple-decision--${decision.status}` : "";
2989
+ return /* @__PURE__ */ jsx26(Handles, { sourcePosition, targetPosition, children: /* @__PURE__ */ jsxs25("div", { className: `simple-decision${statusClass}${validationRingClass(data.validation)}`, children: [
2990
+ /* @__PURE__ */ jsx26(
2991
+ "svg",
2992
+ {
2993
+ className: "simple-decision-shape",
2994
+ viewBox: "0 0 100 100",
2995
+ preserveAspectRatio: "none",
2996
+ "aria-hidden": "true",
2997
+ children: /* @__PURE__ */ jsx26("path", { d: "M50 1 L99 50 L50 99 L1 50 Z", vectorEffect: "non-scaling-stroke" })
2998
+ }
2999
+ ),
3000
+ /* @__PURE__ */ jsx26("div", { className: "simple-decision-text", title: decision.title, children: decision.title }),
3001
+ /* @__PURE__ */ jsxs25("div", { className: "simple-decision-marks", children: [
3002
+ /* @__PURE__ */ jsx26(StatusMark, { status: decision.status, graphMode: decision.graphMode }),
3003
+ /* @__PURE__ */ jsx26(ValidationMark, { validation: data.validation, onClick: data.onValidationBadgeClick })
3004
+ ] })
3005
+ ] }) });
3006
+ }
3007
+ function SimpleFrameNode({ data }) {
3008
+ const frame = payloadOf(data, ["frame"]);
3009
+ if (!frame) return null;
3010
+ return /* @__PURE__ */ jsx26("div", { className: `simple-frame${validationRingClass(data.validation)}`, children: /* @__PURE__ */ jsxs25("div", { className: "simple-frame-header", children: [
3011
+ /* @__PURE__ */ jsxs25("span", { className: "simple-frame-title", children: [
3012
+ /* @__PURE__ */ jsx26(Icon, { size: 12, children: CATEGORY_ICONS.repeat }),
3013
+ frame.title
3014
+ ] }),
3015
+ /* @__PURE__ */ jsx26(StatusMark, { status: frame.status, graphMode: frame.graphMode }),
3016
+ /* @__PURE__ */ jsx26(ValidationMark, { validation: data.validation, onClick: data.onValidationBadgeClick }),
3017
+ frame.onFold && /* @__PURE__ */ jsx26(
3018
+ "button",
3019
+ {
3020
+ type: "button",
3021
+ className: "simple-frame-fold",
3022
+ title: "Fold into one step (alt/option: only this one)",
3023
+ "aria-label": "Fold into one step",
3024
+ onClick: (event) => {
3025
+ var _a;
3026
+ event.stopPropagation();
3027
+ (_a = frame.onFold) == null ? void 0 : _a.call(frame, { soloMode: event.altKey });
3028
+ },
3029
+ children: COLLAPSE_ICON2
3030
+ }
3031
+ )
3032
+ ] }) });
3033
+ }
3034
+ var simpleNodeTypes = {
3035
+ [NODE_TYPE_SIMPLE_STEP]: SimpleStepNode,
3036
+ [NODE_TYPE_SIMPLE_TERMINAL]: SimpleTerminalNode,
3037
+ [NODE_TYPE_SIMPLE_DECISION]: SimpleDecisionNode,
3038
+ [NODE_TYPE_SIMPLE_FRAME]: SimpleFrameNode
3039
+ };
3040
+
3041
+ // src/graph/react/edges/RoutedEdge.tsx
3042
+ import { BaseEdge, getSmoothStepPath } from "@xyflow/react";
3043
+ import { jsx as jsx27 } from "react/jsx-runtime";
3044
+ function RoutedEdge({
3045
+ id,
3046
+ sourceX,
3047
+ sourceY,
3048
+ targetX,
3049
+ targetY,
3050
+ sourcePosition,
3051
+ targetPosition,
3052
+ data,
3053
+ label,
3054
+ labelStyle,
3055
+ labelShowBg,
3056
+ labelBgStyle,
3057
+ labelBgPadding,
3058
+ labelBgBorderRadius,
3059
+ style,
3060
+ markerEnd,
3061
+ markerStart,
3062
+ interactionWidth
3063
+ }) {
3064
+ const route = data == null ? void 0 : data.route;
3065
+ const fitted = route ? fitRoute(route.points, { x: sourceX, y: sourceY }, { x: targetX, y: targetY }) : null;
3066
+ let path;
3067
+ let labelX;
3068
+ let labelY;
3069
+ if (route && fitted) {
3070
+ path = roundedPolylinePath(fitted);
3071
+ ({ x: labelX, y: labelY } = routeLabelCenter(route, fitted));
3072
+ } else {
3073
+ [path, labelX, labelY] = getSmoothStepPath({
3074
+ sourceX,
3075
+ sourceY,
3076
+ targetX,
3077
+ targetY,
3078
+ sourcePosition,
3079
+ targetPosition,
3080
+ borderRadius: 8
3081
+ });
3082
+ }
3083
+ return /* @__PURE__ */ jsx27(
3084
+ BaseEdge,
3085
+ {
3086
+ id,
3087
+ path,
3088
+ labelX,
3089
+ labelY,
3090
+ label,
3091
+ labelStyle,
3092
+ labelShowBg,
3093
+ labelBgStyle,
3094
+ labelBgPadding,
3095
+ labelBgBorderRadius,
3096
+ style,
3097
+ markerEnd,
3098
+ markerStart,
3099
+ interactionWidth
3100
+ }
3101
+ );
3102
+ }
3103
+
2568
3104
  // src/graph/react/viewer/GraphViewer.tsx
2569
- import { Fragment as Fragment14, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
2570
- var nodeTypes = __spreadProps(__spreadValues({}, controllerNodeTypes), {
3105
+ import { Fragment as Fragment15, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
3106
+ var nodeTypes = __spreadValues(__spreadProps(__spreadValues({}, controllerNodeTypes), {
2571
3107
  pipeCard: PipeCardRFNode
2572
- });
3108
+ }), simpleNodeTypes);
3109
+ var edgeTypes = { [EDGE_TYPE_ROUTED]: RoutedEdge };
2573
3110
  function StuffNodeDetail({
2574
3111
  nodeId,
2575
3112
  stuffData,
@@ -2587,7 +3124,7 @@ function StuffNodeDetail({
2587
3124
  const conceptInfo = stuffData.concept && graphspec ? resolveConceptRef(graphspec, stuffData.concept) : void 0;
2588
3125
  const isDryRun = graphSpecMode(graphspec) === GRAPH_SPEC_MODE.DRY;
2589
3126
  const descriptors = resultDescriptors(artifacts);
2590
- const renderData = descriptors ? () => /* @__PURE__ */ jsx25(
3127
+ const renderData = descriptors ? () => /* @__PURE__ */ jsx28(
2591
3128
  StuffResultPanel,
2592
3129
  __spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadProps(__spreadValues({}, descriptors), {
2593
3130
  stuff: stuffData
@@ -2596,7 +3133,7 @@ function StuffNodeDetail({
2596
3133
  })
2597
3134
  ) : void 0;
2598
3135
  if (conceptInfo) {
2599
- return /* @__PURE__ */ jsx25(
3136
+ return /* @__PURE__ */ jsx28(
2600
3137
  ConceptDetailPanel,
2601
3138
  {
2602
3139
  concept: conceptInfo,
@@ -2607,8 +3144,8 @@ function StuffNodeDetail({
2607
3144
  }
2608
3145
  );
2609
3146
  }
2610
- if (isDryRun) return /* @__PURE__ */ jsx25("div", { className: "detail-not-available", children: "Dry run data hidden" });
2611
- return /* @__PURE__ */ jsx25(Fragment14, { children: (_a = renderData == null ? void 0 : renderData()) != null ? _a : /* @__PURE__ */ jsx25("div", { className: "detail-not-available", children: "No data" }) });
3147
+ if (isDryRun) return /* @__PURE__ */ jsx28("div", { className: "detail-not-available", children: "Dry run data hidden" });
3148
+ return /* @__PURE__ */ jsx28(Fragment15, { children: (_a = renderData == null ? void 0 : renderData()) != null ? _a : /* @__PURE__ */ jsx28("div", { className: "detail-not-available", children: "No data" }) });
2612
3149
  }
2613
3150
  function seedFoldedControllers(mode, controllerIds) {
2614
3151
  if (mode === FOLD_MODE.FOLDED) return new Set(controllerIds);
@@ -2635,10 +3172,16 @@ function cloneCachedNodes(nodes) {
2635
3172
  style: n.style ? __spreadValues({}, n.style) : void 0
2636
3173
  }));
2637
3174
  }
3175
+ function nodeRunStatus(data) {
3176
+ var _a;
3177
+ const simple = data.simple;
3178
+ if (simple) return "status" in simple ? simple.status : void 0;
3179
+ return (_a = data.pipeCardData) == null ? void 0 : _a.status;
3180
+ }
2638
3181
  function applyStatusOverrides(nodes, statusMap) {
2639
3182
  if (!statusMap || Object.keys(statusMap).length === 0) return nodes;
2640
3183
  return nodes.map((node) => {
2641
- var _a, _b;
3184
+ var _a;
2642
3185
  if (node.data.graphMode === "static" || ((_a = node.data.pipeCardData) == null ? void 0 : _a.graphMode) === "static") {
2643
3186
  return node;
2644
3187
  }
@@ -2646,17 +3189,20 @@ function applyStatusOverrides(nodes, statusMap) {
2646
3189
  const pipeCode = node.data.pipeCode;
2647
3190
  if (!pipeCode || !Object.hasOwn(statusMap, pipeCode)) return node;
2648
3191
  const newStatus = statusMap[pipeCode];
2649
- if (((_b = node.data.pipeCardData) == null ? void 0 : _b.status) === newStatus) return node;
3192
+ const simple = node.data.simple;
3193
+ const simpleWithStatus = simple && "status" in simple ? simple : void 0;
3194
+ if (nodeRunStatus(node.data) === newStatus) return node;
2650
3195
  return __spreadProps(__spreadValues({}, node), {
2651
3196
  data: __spreadProps(__spreadValues({}, node.data), {
2652
3197
  nodeData: node.data.nodeData ? __spreadProps(__spreadValues({}, node.data.nodeData), { status: newStatus }) : node.data.nodeData,
2653
- pipeCardData: node.data.pipeCardData ? __spreadProps(__spreadValues({}, node.data.pipeCardData), { status: newStatus }) : node.data.pipeCardData
3198
+ pipeCardData: node.data.pipeCardData ? __spreadProps(__spreadValues({}, node.data.pipeCardData), { status: newStatus }) : node.data.pipeCardData,
3199
+ simple: simpleWithStatus ? __spreadProps(__spreadValues({}, simpleWithStatus), { status: newStatus }) : simple
2654
3200
  })
2655
3201
  });
2656
3202
  });
2657
3203
  }
2658
3204
  function GraphViewer(props) {
2659
- var _a, _b, _c, _d;
3205
+ var _a, _b, _c, _d, _e;
2660
3206
  const {
2661
3207
  graph,
2662
3208
  config = DEFAULT_GRAPH_CONFIG,
@@ -2665,6 +3211,9 @@ function GraphViewer(props) {
2665
3211
  initialFoldMode,
2666
3212
  hideToolbar = false,
2667
3213
  theme: themeProp,
3214
+ graphStyle: graphStyleProp,
3215
+ onGraphStyleChange,
3216
+ styleMenu,
2668
3217
  toolbarPosition: toolbarPositionProp,
2669
3218
  systemTheme: systemThemeProp,
2670
3219
  showThemeToggle = true,
@@ -2685,20 +3234,20 @@ function GraphViewer(props) {
2685
3234
  onValidationIssueClick
2686
3235
  } = props;
2687
3236
  const graphspecProp = (_a = graph == null ? void 0 : graph.graphSpec) != null ? _a : null;
2688
- const graphspec = React10.useMemo(
3237
+ const graphspec = React12.useMemo(
2689
3238
  () => graphspecProp === null ? null : validateGraphSpec(graphspecProp),
2690
3239
  [graphspecProp]
2691
3240
  );
2692
- const [direction, setDirection] = React10.useState(
3241
+ const [direction, setDirection] = React12.useState(
2693
3242
  () => {
2694
3243
  var _a2, _b2;
2695
3244
  return (_b2 = (_a2 = initialDirection != null ? initialDirection : config.direction) != null ? _a2 : DEFAULT_GRAPH_CONFIG.direction) != null ? _b2 : GRAPH_DIRECTION.TB;
2696
3245
  }
2697
3246
  );
2698
3247
  const externalMode = resolveExternalThemeMode(themeProp, config.theme);
2699
- const [mode, setMode] = React10.useState(externalMode);
2700
- const prevExternalModeRef = React10.useRef(externalMode);
2701
- React10.useEffect(() => {
3248
+ const [mode, setMode] = React12.useState(externalMode);
3249
+ const prevExternalModeRef = React12.useRef(externalMode);
3250
+ React12.useEffect(() => {
2702
3251
  if (externalMode !== prevExternalModeRef.current) {
2703
3252
  prevExternalModeRef.current = externalMode;
2704
3253
  setMode(externalMode);
@@ -2706,13 +3255,13 @@ function GraphViewer(props) {
2706
3255
  }, [externalMode]);
2707
3256
  const systemTheme = useSystemTheme(systemThemeProp);
2708
3257
  const resolvedTheme = resolveActiveTheme(mode, systemTheme);
2709
- const onThemeChangeRef = React10.useRef(onThemeChange);
3258
+ const onThemeChangeRef = React12.useRef(onThemeChange);
2710
3259
  onThemeChangeRef.current = onThemeChange;
2711
- const prevReportedRef = React10.useRef({
3260
+ const prevReportedRef = React12.useRef({
2712
3261
  mode,
2713
3262
  resolvedTheme
2714
3263
  });
2715
- React10.useEffect(() => {
3264
+ React12.useEffect(() => {
2716
3265
  var _a2;
2717
3266
  const prev = prevReportedRef.current;
2718
3267
  if (prev.mode !== mode || prev.resolvedTheme !== resolvedTheme) {
@@ -2720,27 +3269,49 @@ function GraphViewer(props) {
2720
3269
  (_a2 = onThemeChangeRef.current) == null ? void 0 : _a2.call(onThemeChangeRef, mode, resolvedTheme);
2721
3270
  }
2722
3271
  }, [mode, resolvedTheme]);
3272
+ const externalStyle = resolveGraphStyle(graphStyleProp, config.graphStyle);
3273
+ const [graphStyle, setGraphStyle] = React12.useState(externalStyle);
3274
+ const prevExternalStyleRef = React12.useRef(externalStyle);
3275
+ React12.useEffect(() => {
3276
+ if (externalStyle !== prevExternalStyleRef.current) {
3277
+ prevExternalStyleRef.current = externalStyle;
3278
+ setGraphStyle(externalStyle);
3279
+ }
3280
+ }, [externalStyle]);
3281
+ const onGraphStyleChangeRef = React12.useRef(onGraphStyleChange);
3282
+ onGraphStyleChangeRef.current = onGraphStyleChange;
3283
+ const prevReportedStyleRef = React12.useRef(graphStyle);
3284
+ React12.useEffect(() => {
3285
+ var _a2;
3286
+ if (prevReportedStyleRef.current !== graphStyle) {
3287
+ prevReportedStyleRef.current = graphStyle;
3288
+ (_a2 = onGraphStyleChangeRef.current) == null ? void 0 : _a2.call(onGraphStyleChangeRef, graphStyle);
3289
+ }
3290
+ }, [graphStyle]);
3291
+ const graphStyleRef = React12.useRef(graphStyle);
3292
+ graphStyleRef.current = graphStyle;
3293
+ const styleCapabilities = GRAPH_STYLES[graphStyle].capabilities;
2723
3294
  const effectiveFoldMode = (_c = (_b = initialFoldMode != null ? initialFoldMode : config.foldMode) != null ? _b : DEFAULT_GRAPH_CONFIG.foldMode) != null ? _c : FOLD_MODE.EXPANDED;
2724
- const [showControllers, setShowControllers] = React10.useState(() => {
3295
+ const [showControllers, setShowControllers] = React12.useState(() => {
2725
3296
  var _a2, _b2;
2726
3297
  if (effectiveFoldMode === FOLD_MODE.FOLDED) return true;
2727
3298
  return (_b2 = (_a2 = initialShowControllers != null ? initialShowControllers : config.showControllers) != null ? _a2 : DEFAULT_GRAPH_CONFIG.showControllers) != null ? _b2 : false;
2728
3299
  });
2729
- const foldModeRef = React10.useRef(effectiveFoldMode);
3300
+ const foldModeRef = React12.useRef(effectiveFoldMode);
2730
3301
  foldModeRef.current = effectiveFoldMode;
2731
- const containerRef = React10.useRef(null);
2732
- const [detailSelection, setDetailSelection] = React10.useState(null);
2733
- const [conceptOverride, setConceptOverride] = React10.useState(null);
3302
+ const containerRef = React12.useRef(null);
3303
+ const [detailSelection, setDetailSelection] = React12.useState(null);
3304
+ const [conceptOverride, setConceptOverride] = React12.useState(null);
2734
3305
  const {
2735
3306
  width: panelWidth,
2736
3307
  isDragging: isPanelDragging,
2737
3308
  handleMouseDown: onResizeMouseDown
2738
3309
  } = useResizable({ defaultWidth: 380, minWidth: 280, maxWidth: 800, containerRef });
2739
- React10.useEffect(() => {
3310
+ React12.useEffect(() => {
2740
3311
  setDetailSelection(null);
2741
3312
  setConceptOverride(null);
2742
3313
  }, [graphspec]);
2743
- React10.useEffect(() => {
3314
+ React12.useEffect(() => {
2744
3315
  const el = containerRef.current;
2745
3316
  if (!el) return;
2746
3317
  const themePalette = getPaletteForTheme(resolvedTheme);
@@ -2757,12 +3328,12 @@ function GraphViewer(props) {
2757
3328
  }, [config.paletteColors, resolvedTheme]);
2758
3329
  const [nodes, setNodes, onNodesChange] = useNodesState([]);
2759
3330
  const [edges, setEdges, onEdgesChange] = useEdgesState([]);
2760
- const reactFlowRef = React10.useRef(null);
2761
- const initialDataRef = React10.useRef(null);
2762
- const rawGraphDataRef = React10.useRef(null);
2763
- const layoutCacheRef = React10.useRef(null);
2764
- const [expandedControllers, setExpandedControllers] = React10.useState(/* @__PURE__ */ new Set());
2765
- const toggleCollapse = React10.useCallback((controllerId) => {
3331
+ const reactFlowRef = React12.useRef(null);
3332
+ const initialDataRef = React12.useRef(null);
3333
+ const rawGraphDataRef = React12.useRef(null);
3334
+ const layoutCacheRef = React12.useRef(null);
3335
+ const [expandedControllers, setExpandedControllers] = React12.useState(/* @__PURE__ */ new Set());
3336
+ const toggleCollapse = React12.useCallback((controllerId) => {
2766
3337
  setExpandedControllers((prev) => {
2767
3338
  const next = new Set(prev);
2768
3339
  if (next.has(controllerId)) next.delete(controllerId);
@@ -2770,87 +3341,124 @@ function GraphViewer(props) {
2770
3341
  return next;
2771
3342
  });
2772
3343
  }, []);
2773
- const [foldedControllers, setFoldedControllers] = React10.useState(/* @__PURE__ */ new Set());
2774
- const toggleFold = React10.useCallback((controllerId, options) => {
2775
- setFoldedControllers((prev) => {
2776
- const next = new Set(prev);
2777
- const shouldFold = !next.has(controllerId);
2778
- const raw = rawGraphDataRef.current;
2779
- const targets = !(options == null ? void 0 : options.soloMode) && (raw == null ? void 0 : raw.graphspec) && raw.analysis ? findCousinControllers(controllerId, raw.graphspec, raw.analysis.controllerNodeIds) : /* @__PURE__ */ new Set([controllerId]);
2780
- for (const id of targets) {
2781
- if (shouldFold) next.add(id);
2782
- else next.delete(id);
2783
- }
2784
- return next;
2785
- });
3344
+ const [foldedControllers, setFoldedControllers] = React12.useState(/* @__PURE__ */ new Set());
3345
+ const styleDefaultFoldsRef = React12.useRef(/* @__PURE__ */ new Set());
3346
+ const readerOpenedRef = React12.useRef(/* @__PURE__ */ new Set());
3347
+ const markReaderFolds = React12.useCallback((ids, folded) => {
3348
+ for (const id of ids) {
3349
+ styleDefaultFoldsRef.current.delete(id);
3350
+ if (folded) readerOpenedRef.current.delete(id);
3351
+ else readerOpenedRef.current.add(id);
3352
+ }
2786
3353
  }, []);
3354
+ const toggleFold = React12.useCallback(
3355
+ (controllerId, options) => {
3356
+ setFoldedControllers((prev) => {
3357
+ const next = new Set(prev);
3358
+ const shouldFold = !next.has(controllerId);
3359
+ const raw = rawGraphDataRef.current;
3360
+ const targets = !(options == null ? void 0 : options.soloMode) && (raw == null ? void 0 : raw.graphspec) && raw.analysis ? findCousinControllers(controllerId, raw.graphspec, raw.analysis.controllerNodeIds) : /* @__PURE__ */ new Set([controllerId]);
3361
+ for (const id of targets) {
3362
+ if (shouldFold) next.add(id);
3363
+ else next.delete(id);
3364
+ }
3365
+ markReaderFolds(targets, shouldFold);
3366
+ return next;
3367
+ });
3368
+ },
3369
+ [markReaderFolds]
3370
+ );
2787
3371
  const edgeType = config.edgeType || EDGE_TYPE.DEFAULT;
2788
- const layoutConfig = React10.useMemo(
3372
+ const layoutConfig = React12.useMemo(
2789
3373
  () => ({ nodesep: config.nodesep, ranksep: config.ranksep }),
2790
3374
  [config.nodesep, config.ranksep]
2791
3375
  );
2792
- const showControllersRef = React10.useRef(showControllers);
3376
+ const showControllersRef = React12.useRef(showControllers);
2793
3377
  showControllersRef.current = showControllers;
2794
- const directionRef = React10.useRef(direction);
3378
+ const directionRef = React12.useRef(direction);
2795
3379
  directionRef.current = direction;
2796
- const layoutConfigRef = React10.useRef(layoutConfig);
3380
+ const layoutConfigRef = React12.useRef(layoutConfig);
2797
3381
  layoutConfigRef.current = layoutConfig;
2798
- const initialZoomRef = React10.useRef(config.initialZoom);
3382
+ const initialZoomRef = React12.useRef(config.initialZoom);
2799
3383
  initialZoomRef.current = config.initialZoom;
2800
- const panToTopRef = React10.useRef(config.panToTop);
3384
+ const panToTopRef = React12.useRef(config.panToTop);
2801
3385
  panToTopRef.current = config.panToTop;
2802
- const expandedRef = React10.useRef(expandedControllers);
3386
+ const expandedRef = React12.useRef(expandedControllers);
2803
3387
  expandedRef.current = expandedControllers;
2804
- const toggleCollapseRef = React10.useRef(toggleCollapse);
3388
+ const toggleCollapseRef = React12.useRef(toggleCollapse);
2805
3389
  toggleCollapseRef.current = toggleCollapse;
2806
- const foldedRef = React10.useRef(foldedControllers);
3390
+ const foldedRef = React12.useRef(foldedControllers);
2807
3391
  foldedRef.current = foldedControllers;
2808
- const toggleFoldRef = React10.useRef(toggleFold);
3392
+ const toggleFoldRef = React12.useRef(toggleFold);
2809
3393
  toggleFoldRef.current = toggleFold;
2810
- const isFirstFoldEffect = React10.useRef(true);
2811
- const prevFoldSizeRef = React10.useRef(0);
2812
- const skipNextFoldEffectRef = React10.useRef(false);
2813
- const statusMapRef = React10.useRef(statusMap);
3394
+ const isFirstFoldEffect = React12.useRef(true);
3395
+ const prevFoldSizeRef = React12.useRef(0);
3396
+ const skipNextFoldEffectRef = React12.useRef(false);
3397
+ const statusMapRef = React12.useRef(statusMap);
2814
3398
  statusMapRef.current = statusMap;
2815
- const validationIssuesRef = React10.useRef(validationIssues);
3399
+ const validationIssuesRef = React12.useRef(validationIssues);
2816
3400
  validationIssuesRef.current = validationIssues;
2817
- const [validationOpen, setValidationOpen] = React10.useState(false);
2818
- const openValidationPanel = React10.useCallback(() => setValidationOpen(true), []);
3401
+ const selectedNodeIdRef = React12.useRef(null);
3402
+ selectedNodeIdRef.current = (_d = detailSelection == null ? void 0 : detailSelection.nodeId) != null ? _d : null;
3403
+ const [validationOpen, setValidationOpen] = React12.useState(false);
3404
+ const openValidationPanel = React12.useCallback(() => setValidationOpen(true), []);
2819
3405
  const validationWidgetAvailable = validationState !== void 0 && !hideToolbar;
2820
- const validationWidgetAvailableRef = React10.useRef(validationWidgetAvailable);
3406
+ const validationWidgetAvailableRef = React12.useRef(validationWidgetAvailable);
2821
3407
  validationWidgetAvailableRef.current = validationWidgetAvailable;
2822
- const decorateNodes = React10.useCallback(
3408
+ const decorateNodes = React12.useCallback(
2823
3409
  (nodes2) => {
2824
- var _a2, _b2;
3410
+ var _a2, _b2, _c2;
2825
3411
  const raw = rawGraphDataRef.current;
2826
3412
  const decorations = buildValidationDecorations(
2827
3413
  validationIssuesRef.current,
2828
3414
  (_a2 = raw == null ? void 0 : raw.graphspec) != null ? _a2 : null,
2829
3415
  (_b2 = raw == null ? void 0 : raw.childToCtrl) != null ? _b2 : {},
2830
- foldedRef.current
3416
+ foldedRef.current,
3417
+ (_c2 = initialDataRef.current) == null ? void 0 : _c2._standIns
2831
3418
  );
2832
- return applyValidationDecorations(
3419
+ const decorated = applyValidationDecorations(
2833
3420
  applyStatusOverrides(toAppNodes(hydrateLabels(nodes2)), statusMapRef.current),
2834
3421
  decorations,
2835
3422
  validationWidgetAvailableRef.current ? openValidationPanel : void 0
2836
3423
  );
3424
+ const selectedId = selectedNodeIdRef.current;
3425
+ return selectedId ? decorated.map((n) => n.id === selectedId ? __spreadProps(__spreadValues({}, n), { selected: true }) : n) : decorated;
2837
3426
  },
2838
3427
  [openValidationPanel]
2839
3428
  );
2840
- const nodesRef = React10.useRef([]);
3429
+ const frameLayout = React12.useCallback(
3430
+ (style, layout, graphspec2, analysis) => GRAPH_STYLE_PIPELINES[style].frame({
3431
+ nodes: cloneCachedNodes(layout.nodes),
3432
+ edges: layout.edges,
3433
+ graphspec: graphspec2,
3434
+ analysis,
3435
+ controllerPositions: layout.controllerPositions,
3436
+ showControllers: showControllersRef.current,
3437
+ expandedControllers: expandedRef.current,
3438
+ onToggleCollapse: toggleCollapseRef.current,
3439
+ onToggleFold: toggleFoldRef.current
3440
+ }),
3441
+ []
3442
+ );
3443
+ const cacheMatchesData = () => {
3444
+ const cache = layoutCacheRef.current;
3445
+ const data = initialDataRef.current;
3446
+ return cache !== null && data !== null && cache.graphspec === data._graphspec && cache.graphStyle === data._graphStyle;
3447
+ };
3448
+ const nodesRef = React12.useRef([]);
2841
3449
  nodesRef.current = nodes;
2842
- const onValidationIssueClickRef = React10.useRef(onValidationIssueClick);
3450
+ const onValidationIssueClickRef = React12.useRef(onValidationIssueClick);
2843
3451
  onValidationIssueClickRef.current = onValidationIssueClick;
2844
- const flashTimeoutRef = React10.useRef(null);
2845
- React10.useEffect(
3452
+ const flashTimeoutRef = React12.useRef(null);
3453
+ React12.useEffect(
2846
3454
  () => () => {
2847
3455
  if (flashTimeoutRef.current) clearTimeout(flashTimeoutRef.current);
2848
3456
  },
2849
3457
  []
2850
3458
  );
2851
- const handleValidationIssueClick = React10.useCallback(
3459
+ const handleValidationIssueClick = React12.useCallback(
2852
3460
  (index, issue) => {
2853
- var _a2, _b2;
3461
+ var _a2, _b2, _c2;
2854
3462
  (_a2 = onValidationIssueClickRef.current) == null ? void 0 : _a2.call(onValidationIssueClickRef, index, issue);
2855
3463
  const raw = rawGraphDataRef.current;
2856
3464
  if (!(raw == null ? void 0 : raw.graphspec) || !raw.analysis) return;
@@ -2859,10 +3467,11 @@ function GraphViewer(props) {
2859
3467
  raw.graphspec,
2860
3468
  raw.childToCtrl,
2861
3469
  foldedRef.current,
2862
- new Set(nodesRef.current.map((n) => n.id))
3470
+ new Set(nodesRef.current.map((n) => n.id)),
3471
+ (_b2 = initialDataRef.current) == null ? void 0 : _b2._standIns
2863
3472
  );
2864
3473
  if (!targetId) return;
2865
- void ((_b2 = reactFlowRef.current) == null ? void 0 : _b2.fitView({
3474
+ void ((_c2 = reactFlowRef.current) == null ? void 0 : _c2.fitView({
2866
3475
  nodes: [{ id: targetId }],
2867
3476
  duration: 500,
2868
3477
  padding: 0.4
@@ -2890,10 +3499,11 @@ function GraphViewer(props) {
2890
3499
  },
2891
3500
  [setNodes]
2892
3501
  );
2893
- React10.useEffect(() => {
3502
+ React12.useEffect(() => {
2894
3503
  if (!initialDataRef.current) return;
2895
3504
  let cancelled = false;
2896
3505
  void (async () => {
3506
+ var _a2;
2897
3507
  try {
2898
3508
  const data = initialDataRef.current;
2899
3509
  if (!data) return;
@@ -2901,7 +3511,7 @@ function GraphViewer(props) {
2901
3511
  data.nodes,
2902
3512
  data.edges,
2903
3513
  direction,
2904
- layoutConfig,
3514
+ (_a2 = GRAPH_STYLES[data._graphStyle].layout) != null ? _a2 : layoutConfig,
2905
3515
  data._graphspec,
2906
3516
  data._analysis
2907
3517
  );
@@ -2910,18 +3520,14 @@ function GraphViewer(props) {
2910
3520
  nodes: relayouted.nodes,
2911
3521
  edges: relayouted.edges,
2912
3522
  controllerPositions: relayouted.controllerPositions,
2913
- graphspec: data._graphspec
3523
+ graphspec: data._graphspec,
3524
+ graphStyle: data._graphStyle
2914
3525
  };
2915
- const withControllers = applyControllers(
2916
- cloneCachedNodes(relayouted.nodes),
2917
- relayouted.edges,
3526
+ const withControllers = frameLayout(
3527
+ data._graphStyle,
3528
+ relayouted,
2918
3529
  data._graphspec,
2919
- data._analysis,
2920
- showControllersRef.current,
2921
- expandedRef.current,
2922
- toggleCollapseRef.current,
2923
- relayouted.controllerPositions,
2924
- toggleFoldRef.current
3530
+ data._analysis
2925
3531
  );
2926
3532
  setNodes(decorateNodes(withControllers.nodes));
2927
3533
  setEdges(toAppEdges(withControllers.edges));
@@ -2938,26 +3544,16 @@ function GraphViewer(props) {
2938
3544
  cancelled = true;
2939
3545
  };
2940
3546
  }, [direction, layoutConfig]);
2941
- React10.useEffect(() => {
2942
- if (!layoutCacheRef.current || !initialDataRef.current) return;
2943
- if (layoutCacheRef.current.graphspec !== initialDataRef.current._graphspec) return;
2944
- const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
2945
- const cachedEdges = layoutCacheRef.current.edges;
2946
- const withControllers = applyControllers(
2947
- cachedNodes,
2948
- cachedEdges,
2949
- initialDataRef.current._graphspec,
2950
- initialDataRef.current._analysis,
2951
- showControllers,
2952
- expandedControllers,
2953
- toggleCollapse,
2954
- layoutCacheRef.current.controllerPositions,
2955
- toggleFold
2956
- );
3547
+ React12.useEffect(() => {
3548
+ const cache = layoutCacheRef.current;
3549
+ const data = initialDataRef.current;
3550
+ if (!cache || !data || !cacheMatchesData()) return;
3551
+ const withControllers = frameLayout(cache.graphStyle, cache, data._graphspec, data._analysis);
2957
3552
  setNodes(decorateNodes(withControllers.nodes));
2958
3553
  setEdges(toAppEdges(withControllers.edges));
2959
3554
  }, [showControllers, expandedControllers, toggleCollapse, toggleFold, decorateNodes]);
2960
- React10.useEffect(() => {
3555
+ React12.useEffect(() => {
3556
+ var _a2;
2961
3557
  if (!graphspec) {
2962
3558
  initialDataRef.current = null;
2963
3559
  rawGraphDataRef.current = null;
@@ -2967,8 +3563,13 @@ function GraphViewer(props) {
2967
3563
  return;
2968
3564
  }
2969
3565
  let cancelled = false;
2970
- setExpandedControllers(/* @__PURE__ */ new Set());
2971
- expandedRef.current = /* @__PURE__ */ new Set();
3566
+ const sameSpec = ((_a2 = rawGraphDataRef.current) == null ? void 0 : _a2.graphspec) === graphspec;
3567
+ if (!sameSpec) {
3568
+ setExpandedControllers(/* @__PURE__ */ new Set());
3569
+ expandedRef.current = /* @__PURE__ */ new Set();
3570
+ }
3571
+ const style = graphStyleRef.current;
3572
+ const pipeline = GRAPH_STYLE_PIPELINES[style];
2972
3573
  const { graphData, analysis } = buildGraph(graphspec, edgeType);
2973
3574
  rawGraphDataRef.current = {
2974
3575
  nodes: graphData.nodes,
@@ -2977,12 +3578,24 @@ function GraphViewer(props) {
2977
3578
  graphspec,
2978
3579
  childToCtrl: analysis ? buildChildToControllerMap(graphspec, analysis) : {}
2979
3580
  };
2980
- const seedSet = analysis ? seedFoldedControllers(foldModeRef.current, analysis.controllerNodeIds) : /* @__PURE__ */ new Set();
3581
+ if (!sameSpec) readerOpenedRef.current = /* @__PURE__ */ new Set();
3582
+ let seedSet = /* @__PURE__ */ new Set();
3583
+ const styleDefaults = /* @__PURE__ */ new Set();
3584
+ if (analysis) {
3585
+ const kept = sameSpec ? [...foldedRef.current].filter((id) => !styleDefaultFoldsRef.current.has(id)) : [...seedFoldedControllers(foldModeRef.current, analysis.controllerNodeIds)];
3586
+ seedSet = new Set(kept);
3587
+ for (const id of pipeline.defaultFolds(graphspec, analysis)) {
3588
+ if (seedSet.has(id) || readerOpenedRef.current.has(id)) continue;
3589
+ styleDefaults.add(id);
3590
+ seedSet.add(id);
3591
+ }
3592
+ }
3593
+ styleDefaultFoldsRef.current = styleDefaults;
2981
3594
  setFoldedControllers(seedSet);
2982
3595
  foldedRef.current = seedSet;
2983
3596
  skipNextFoldEffectRef.current = seedSet.size > 0;
2984
3597
  prevFoldSizeRef.current = seedSet.size;
2985
- if (seedSet.size > 0 && !showControllersRef.current) {
3598
+ if (seedSet.size > 0 && GRAPH_STYLES[style].capabilities.controllerFrameToggle && !showControllersRef.current) {
2986
3599
  setShowControllers(true);
2987
3600
  showControllersRef.current = true;
2988
3601
  }
@@ -2993,29 +3606,38 @@ function GraphViewer(props) {
2993
3606
  seedSet,
2994
3607
  toggleFoldRef.current
2995
3608
  ) : { nodes: graphData.nodes, edges: graphData.edges, analysis };
2996
- initialDataRef.current = {
3609
+ const projected = pipeline.project({
3610
+ graphspec,
2997
3611
  nodes: folded.nodes,
2998
3612
  edges: folded.edges,
2999
- _analysis: folded.analysis,
3000
- _graphspec: graphspec
3001
- };
3613
+ analysis: folded.analysis,
3614
+ rawAnalysis: analysis
3615
+ });
3616
+ initialDataRef.current = __spreadValues({
3617
+ nodes: projected.nodes,
3618
+ edges: projected.edges,
3619
+ _analysis: projected.analysis,
3620
+ _graphspec: graphspec,
3621
+ _graphStyle: style
3622
+ }, projected.standIns ? { _standIns: projected.standIns } : {});
3002
3623
  void (async () => {
3624
+ var _a3;
3003
3625
  try {
3004
3626
  const currentDirection = directionRef.current;
3005
- const currentLayoutConfig = layoutConfigRef.current;
3006
- const needsLayout = folded.nodes.some(
3627
+ const currentLayoutConfig = (_a3 = GRAPH_STYLES[style].layout) != null ? _a3 : layoutConfigRef.current;
3628
+ const needsLayout = projected.nodes.some(
3007
3629
  (n) => !n.position || n.position.x === 0 && n.position.y === 0
3008
3630
  );
3009
3631
  const layouted = needsLayout ? await getLayoutedElements(
3010
- folded.nodes,
3011
- folded.edges,
3632
+ projected.nodes,
3633
+ projected.edges,
3012
3634
  currentDirection,
3013
3635
  currentLayoutConfig,
3014
3636
  graphspec,
3015
- folded.analysis
3637
+ projected.analysis
3016
3638
  ) : {
3017
- nodes: folded.nodes,
3018
- edges: folded.edges,
3639
+ nodes: projected.nodes,
3640
+ edges: projected.edges,
3019
3641
  controllerPositions: {}
3020
3642
  };
3021
3643
  if (cancelled) return;
@@ -3023,19 +3645,10 @@ function GraphViewer(props) {
3023
3645
  nodes: layouted.nodes,
3024
3646
  edges: layouted.edges,
3025
3647
  controllerPositions: layouted.controllerPositions,
3026
- graphspec
3027
- };
3028
- const withControllers = applyControllers(
3029
- cloneCachedNodes(layouted.nodes),
3030
- layouted.edges,
3031
3648
  graphspec,
3032
- folded.analysis,
3033
- showControllersRef.current,
3034
- expandedRef.current,
3035
- toggleCollapseRef.current,
3036
- layouted.controllerPositions,
3037
- toggleFoldRef.current
3038
- );
3649
+ graphStyle: style
3650
+ };
3651
+ const withControllers = frameLayout(style, layouted, graphspec, projected.analysis);
3039
3652
  setNodes(decorateNodes(withControllers.nodes));
3040
3653
  setEdges(toAppEdges(withControllers.edges));
3041
3654
  setTimeout(() => {
@@ -3057,8 +3670,8 @@ function GraphViewer(props) {
3057
3670
  return () => {
3058
3671
  cancelled = true;
3059
3672
  };
3060
- }, [graphspec, edgeType]);
3061
- React10.useEffect(() => {
3673
+ }, [graphspec, edgeType, graphStyle]);
3674
+ React12.useEffect(() => {
3062
3675
  if (isFirstFoldEffect.current) {
3063
3676
  isFirstFoldEffect.current = false;
3064
3677
  prevFoldSizeRef.current = foldedControllers.size;
@@ -3078,6 +3691,7 @@ function GraphViewer(props) {
3078
3691
  const currentAnalysis = raw.analysis;
3079
3692
  if (!currentGraphspec || !currentAnalysis) return;
3080
3693
  let cancelled = false;
3694
+ const style = graphStyleRef.current;
3081
3695
  const folded = applyFolds(
3082
3696
  { nodes: raw.nodes, edges: raw.edges },
3083
3697
  currentAnalysis,
@@ -3085,40 +3699,40 @@ function GraphViewer(props) {
3085
3699
  foldedControllers,
3086
3700
  toggleFold
3087
3701
  );
3088
- initialDataRef.current = {
3702
+ const projected = GRAPH_STYLE_PIPELINES[style].project({
3703
+ graphspec: currentGraphspec,
3089
3704
  nodes: folded.nodes,
3090
3705
  edges: folded.edges,
3091
- _analysis: folded.analysis,
3092
- _graphspec: currentGraphspec
3093
- };
3706
+ analysis: folded.analysis,
3707
+ rawAnalysis: currentAnalysis
3708
+ });
3709
+ initialDataRef.current = __spreadValues({
3710
+ nodes: projected.nodes,
3711
+ edges: projected.edges,
3712
+ _analysis: projected.analysis,
3713
+ _graphspec: currentGraphspec,
3714
+ _graphStyle: style
3715
+ }, projected.standIns ? { _standIns: projected.standIns } : {});
3094
3716
  void (async () => {
3717
+ var _a2;
3095
3718
  try {
3096
3719
  const layouted = await getLayoutedElements(
3097
- folded.nodes,
3098
- folded.edges,
3720
+ projected.nodes,
3721
+ projected.edges,
3099
3722
  directionRef.current,
3100
- layoutConfigRef.current,
3723
+ (_a2 = GRAPH_STYLES[style].layout) != null ? _a2 : layoutConfigRef.current,
3101
3724
  currentGraphspec,
3102
- folded.analysis
3725
+ projected.analysis
3103
3726
  );
3104
3727
  if (cancelled) return;
3105
3728
  layoutCacheRef.current = {
3106
3729
  nodes: layouted.nodes,
3107
3730
  edges: layouted.edges,
3108
3731
  controllerPositions: layouted.controllerPositions,
3109
- graphspec: currentGraphspec
3732
+ graphspec: currentGraphspec,
3733
+ graphStyle: style
3110
3734
  };
3111
- const withControllers = applyControllers(
3112
- cloneCachedNodes(layouted.nodes),
3113
- layouted.edges,
3114
- currentGraphspec,
3115
- folded.analysis,
3116
- showControllersRef.current,
3117
- expandedRef.current,
3118
- toggleCollapseRef.current,
3119
- layouted.controllerPositions,
3120
- toggleFoldRef.current
3121
- );
3735
+ const withControllers = frameLayout(style, layouted, currentGraphspec, projected.analysis);
3122
3736
  setNodes(decorateNodes(withControllers.nodes));
3123
3737
  setEdges(toAppEdges(withControllers.edges));
3124
3738
  setTimeout(() => {
@@ -3134,51 +3748,29 @@ function GraphViewer(props) {
3134
3748
  cancelled = true;
3135
3749
  };
3136
3750
  }, [foldedControllers, toggleFold]);
3137
- React10.useEffect(() => {
3138
- if (!layoutCacheRef.current || !initialDataRef.current) return;
3139
- if (layoutCacheRef.current.graphspec !== initialDataRef.current._graphspec) return;
3140
- const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
3141
- const cachedEdges = layoutCacheRef.current.edges;
3142
- const withControllers = applyControllers(
3143
- cachedNodes,
3144
- cachedEdges,
3145
- initialDataRef.current._graphspec,
3146
- initialDataRef.current._analysis,
3147
- showControllersRef.current,
3148
- expandedRef.current,
3149
- toggleCollapseRef.current,
3150
- layoutCacheRef.current.controllerPositions,
3151
- toggleFoldRef.current
3152
- );
3751
+ React12.useEffect(() => {
3752
+ const cache = layoutCacheRef.current;
3753
+ const data = initialDataRef.current;
3754
+ if (!cache || !data || !cacheMatchesData()) return;
3755
+ const withControllers = frameLayout(cache.graphStyle, cache, data._graphspec, data._analysis);
3153
3756
  setNodes(decorateNodes(withControllers.nodes));
3154
3757
  setEdges(toAppEdges(withControllers.edges));
3155
3758
  }, [statusMap, decorateNodes]);
3156
- React10.useEffect(() => {
3157
- if (!layoutCacheRef.current || !initialDataRef.current) return;
3158
- if (layoutCacheRef.current.graphspec !== initialDataRef.current._graphspec) return;
3159
- const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
3160
- const withControllers = applyControllers(
3161
- cachedNodes,
3162
- layoutCacheRef.current.edges,
3163
- initialDataRef.current._graphspec,
3164
- initialDataRef.current._analysis,
3165
- showControllersRef.current,
3166
- expandedRef.current,
3167
- toggleCollapseRef.current,
3168
- layoutCacheRef.current.controllerPositions,
3169
- toggleFoldRef.current
3170
- );
3759
+ React12.useEffect(() => {
3760
+ const cache = layoutCacheRef.current;
3761
+ const data = initialDataRef.current;
3762
+ if (!cache || !data || !cacheMatchesData()) return;
3763
+ const withControllers = frameLayout(cache.graphStyle, cache, data._graphspec, data._analysis);
3171
3764
  setNodes(decorateNodes(withControllers.nodes));
3172
3765
  }, [validationIssues, validationWidgetAvailable, decorateNodes]);
3173
- const onNodeClick = React10.useCallback(
3766
+ const onNodeClick = React12.useCallback(
3174
3767
  (event, node) => {
3175
- var _a2;
3176
3768
  const nodeData = node.data;
3177
3769
  onNodeSelect == null ? void 0 : onNodeSelect(node.id, nodeData, event);
3178
3770
  if ((nodeData.isController || nodeData.isPipe) && nodeData.pipeType !== BINDING_STEP_TYPE) {
3179
3771
  const code = nodeData.pipeCode || nodeData.labelText;
3180
3772
  if (code && onNavigateToPipe) {
3181
- onNavigateToPipe(code, (_a2 = nodeData.pipeCardData) == null ? void 0 : _a2.status);
3773
+ onNavigateToPipe(code, nodeRunStatus(nodeData));
3182
3774
  }
3183
3775
  } else if (nodeData.isStuff && onStuffNodeClick && graphspec) {
3184
3776
  const found = findStuffByDigest(graphspec, stuffDigestFromId(node.id));
@@ -3212,7 +3804,7 @@ function GraphViewer(props) {
3212
3804
  conceptOverride
3213
3805
  ]
3214
3806
  );
3215
- const onInit = React10.useCallback(
3807
+ const onInit = React12.useCallback(
3216
3808
  (reactFlowInstance) => {
3217
3809
  reactFlowRef.current = reactFlowInstance;
3218
3810
  if (onReactFlowInit) {
@@ -3221,12 +3813,12 @@ function GraphViewer(props) {
3221
3813
  },
3222
3814
  [onReactFlowInit]
3223
3815
  );
3224
- const handlePaneClick = React10.useCallback(() => {
3816
+ const handlePaneClick = React12.useCallback(() => {
3225
3817
  setDetailSelection(null);
3226
3818
  setConceptOverride(null);
3227
3819
  onPaneClick == null ? void 0 : onPaneClick();
3228
3820
  }, [onPaneClick]);
3229
- const handleConceptClick = React10.useCallback(
3821
+ const handleConceptClick = React12.useCallback(
3230
3822
  (conceptCode) => {
3231
3823
  if (!graphspec) return;
3232
3824
  const info = resolveConceptRef(graphspec, conceptCode);
@@ -3240,10 +3832,11 @@ function GraphViewer(props) {
3240
3832
  toolbarPositionProp,
3241
3833
  config.toolbarPosition
3242
3834
  );
3243
- const rawAnalysis = (_d = rawGraphDataRef.current) == null ? void 0 : _d.analysis;
3835
+ const rawAnalysis = (_e = rawGraphDataRef.current) == null ? void 0 : _e.analysis;
3244
3836
  const allControllerIds = rawAnalysis == null ? void 0 : rawAnalysis.controllerNodeIds;
3245
- const foldAllProps = React10.useMemo(() => {
3246
- if (!showControllers || !allControllerIds || allControllerIds.size === 0) {
3837
+ const foldControlsAvailable = styleCapabilities.foldAll && (!styleCapabilities.controllerFrameToggle || showControllers);
3838
+ const foldAllProps = React12.useMemo(() => {
3839
+ if (!foldControlsAvailable || !allControllerIds || allControllerIds.size === 0) {
3247
3840
  return {
3248
3841
  onFoldAll: void 0,
3249
3842
  onExpandAll: void 0,
@@ -3252,24 +3845,32 @@ function GraphViewer(props) {
3252
3845
  };
3253
3846
  }
3254
3847
  return {
3255
- onFoldAll: () => setFoldedControllers(new Set(allControllerIds)),
3256
- onExpandAll: () => setFoldedControllers(/* @__PURE__ */ new Set()),
3848
+ onFoldAll: () => {
3849
+ markReaderFolds(allControllerIds, true);
3850
+ setFoldedControllers(new Set(allControllerIds));
3851
+ },
3852
+ onExpandAll: () => {
3853
+ markReaderFolds(allControllerIds, false);
3854
+ setFoldedControllers(/* @__PURE__ */ new Set());
3855
+ },
3257
3856
  foldAllDisabled: foldedControllers.size === allControllerIds.size,
3258
3857
  expandAllDisabled: foldedControllers.size === 0
3259
3858
  };
3260
- }, [showControllers, allControllerIds, foldedControllers]);
3261
- return /* @__PURE__ */ jsxs24(
3859
+ }, [foldControlsAvailable, allControllerIds, foldedControllers, markReaderFolds]);
3860
+ const styleMenuOptions = React12.useMemo(() => resolveStyleMenu(styleMenu), [styleMenu]);
3861
+ return /* @__PURE__ */ jsxs26(
3262
3862
  "div",
3263
3863
  {
3264
3864
  ref: containerRef,
3265
3865
  className: `react-flow-container react-flow-container--theme-${resolvedTheme} react-flow-container--mode-${mode}`,
3266
3866
  children: [
3267
- /* @__PURE__ */ jsxs24(
3867
+ /* @__PURE__ */ jsxs26(
3268
3868
  ReactFlow,
3269
3869
  {
3270
3870
  nodes,
3271
3871
  edges,
3272
3872
  nodeTypes,
3873
+ edgeTypes,
3273
3874
  onNodesChange,
3274
3875
  onEdgesChange,
3275
3876
  onNodeClick,
@@ -3283,7 +3884,7 @@ function GraphViewer(props) {
3283
3884
  proOptions: { hideAttribution: true },
3284
3885
  panActivationKeyCode: null,
3285
3886
  children: [
3286
- /* @__PURE__ */ jsx25(
3887
+ /* @__PURE__ */ jsx28(
3287
3888
  Background,
3288
3889
  {
3289
3890
  variant: BackgroundVariant.Dots,
@@ -3292,13 +3893,16 @@ function GraphViewer(props) {
3292
3893
  color: "var(--color-bg-dots)"
3293
3894
  }
3294
3895
  ),
3295
- !hideToolbar && /* @__PURE__ */ jsx25(
3896
+ !hideToolbar && /* @__PURE__ */ jsx28(
3296
3897
  GraphToolbar,
3297
3898
  {
3298
3899
  direction,
3299
3900
  onDirectionChange: setDirection,
3300
3901
  showControllers,
3301
- onShowControllersChange: setShowControllers,
3902
+ onShowControllersChange: styleCapabilities.controllerFrameToggle ? setShowControllers : void 0,
3903
+ graphStyle,
3904
+ styleMenuOptions,
3905
+ onGraphStyleChange: setGraphStyle,
3302
3906
  onZoomIn: () => {
3303
3907
  var _a2;
3304
3908
  void ((_a2 = reactFlowRef.current) == null ? void 0 : _a2.zoomIn());
@@ -3329,7 +3933,7 @@ function GraphViewer(props) {
3329
3933
  ]
3330
3934
  }
3331
3935
  ),
3332
- /* @__PURE__ */ jsxs24(
3936
+ /* @__PURE__ */ jsxs26(
3333
3937
  DetailPanel,
3334
3938
  {
3335
3939
  isOpen: detailOpen,
@@ -3338,14 +3942,14 @@ function GraphViewer(props) {
3338
3942
  isDragging: isPanelDragging,
3339
3943
  onResizeHandleMouseDown: onResizeMouseDown,
3340
3944
  children: [
3341
- conceptOverride ? /* @__PURE__ */ jsx25(ConceptDetailPanel, { concept: conceptOverride }) : selectedSpecNode && graphspec ? /* @__PURE__ */ jsx25(
3945
+ conceptOverride ? /* @__PURE__ */ jsx28(ConceptDetailPanel, { concept: conceptOverride }) : selectedSpecNode && graphspec ? /* @__PURE__ */ jsx28(
3342
3946
  PipeDetailPanel,
3343
3947
  {
3344
3948
  node: selectedSpecNode,
3345
3949
  spec: graphspec,
3346
3950
  onConceptClick: handleConceptClick
3347
3951
  }
3348
- ) : (detailSelection == null ? void 0 : detailSelection.stuffData) ? /* @__PURE__ */ jsx25(
3952
+ ) : (detailSelection == null ? void 0 : detailSelection.stuffData) ? /* @__PURE__ */ jsx28(
3349
3953
  StuffNodeDetail,
3350
3954
  {
3351
3955
  nodeId: detailSelection.nodeId,