@octaviaflow/core 3.0.18-beta.1 → 3.0.18-beta.11

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 (139) hide show
  1. package/dist/chunk-2NGC7AI3.js +2637 -0
  2. package/dist/chunk-2NGC7AI3.js.map +1 -0
  3. package/dist/chunk-2O6K5PLY.js +2637 -0
  4. package/dist/chunk-2O6K5PLY.js.map +1 -0
  5. package/dist/chunk-4ZALUTZS.js +2936 -0
  6. package/dist/chunk-4ZALUTZS.js.map +1 -0
  7. package/dist/chunk-5ARKSRED.js +2951 -0
  8. package/dist/chunk-5ARKSRED.js.map +1 -0
  9. package/dist/chunk-5OSGSJMM.js +2981 -0
  10. package/dist/chunk-5OSGSJMM.js.map +1 -0
  11. package/dist/chunk-5YQQMEF3.js +2981 -0
  12. package/dist/chunk-5YQQMEF3.js.map +1 -0
  13. package/dist/chunk-A6KMO4JV.js +2949 -0
  14. package/dist/chunk-A6KMO4JV.js.map +1 -0
  15. package/dist/chunk-B7FTWSTM.js +2938 -0
  16. package/dist/chunk-B7FTWSTM.js.map +1 -0
  17. package/dist/chunk-BCO6M26F.js +2940 -0
  18. package/dist/chunk-BCO6M26F.js.map +1 -0
  19. package/dist/chunk-C3UD2AZ5.js +2637 -0
  20. package/dist/chunk-C3UD2AZ5.js.map +1 -0
  21. package/dist/chunk-CEUP4NK2.js +2850 -0
  22. package/dist/chunk-CEUP4NK2.js.map +1 -0
  23. package/dist/chunk-EERNYLFL.js +2860 -0
  24. package/dist/chunk-EERNYLFL.js.map +1 -0
  25. package/dist/chunk-EKFDJX4G.js +2872 -0
  26. package/dist/chunk-EKFDJX4G.js.map +1 -0
  27. package/dist/chunk-GJA3GJUZ.js +2844 -0
  28. package/dist/chunk-GJA3GJUZ.js.map +1 -0
  29. package/dist/chunk-HDOTOZNA.js +2936 -0
  30. package/dist/chunk-HDOTOZNA.js.map +1 -0
  31. package/dist/chunk-IOKUV7FD.js +2658 -0
  32. package/dist/chunk-IOKUV7FD.js.map +1 -0
  33. package/dist/chunk-IUIICQU5.js +2946 -0
  34. package/dist/chunk-IUIICQU5.js.map +1 -0
  35. package/dist/chunk-J2UYZI6D.js +2946 -0
  36. package/dist/chunk-J2UYZI6D.js.map +1 -0
  37. package/dist/chunk-J7YASALS.js +2859 -0
  38. package/dist/chunk-J7YASALS.js.map +1 -0
  39. package/dist/chunk-JIEUYBQT.js +2658 -0
  40. package/dist/chunk-JIEUYBQT.js.map +1 -0
  41. package/dist/chunk-K2H7JLQW.js +2952 -0
  42. package/dist/chunk-K2H7JLQW.js.map +1 -0
  43. package/dist/chunk-KUXYBP66.js +2953 -0
  44. package/dist/chunk-KUXYBP66.js.map +1 -0
  45. package/dist/chunk-KYMYNYFV.js +2656 -0
  46. package/dist/chunk-KYMYNYFV.js.map +1 -0
  47. package/dist/chunk-MMXL343D.js +2974 -0
  48. package/dist/chunk-MMXL343D.js.map +1 -0
  49. package/dist/chunk-NTMEYB7B.js +2949 -0
  50. package/dist/chunk-NTMEYB7B.js.map +1 -0
  51. package/dist/chunk-PVJXX6GP.js +2640 -0
  52. package/dist/chunk-PVJXX6GP.js.map +1 -0
  53. package/dist/chunk-S2SSBMWJ.js +2658 -0
  54. package/dist/chunk-S2SSBMWJ.js.map +1 -0
  55. package/dist/chunk-SLVDAZSX.js +2946 -0
  56. package/dist/chunk-SLVDAZSX.js.map +1 -0
  57. package/dist/chunk-UXMNBS22.js +2955 -0
  58. package/dist/chunk-UXMNBS22.js.map +1 -0
  59. package/dist/chunk-WEPTBLWX.js +2847 -0
  60. package/dist/chunk-WEPTBLWX.js.map +1 -0
  61. package/dist/chunk-WG4ZQMPS.js +2844 -0
  62. package/dist/chunk-WG4ZQMPS.js.map +1 -0
  63. package/dist/chunk-XEPEBHAW.js +2808 -0
  64. package/dist/chunk-XEPEBHAW.js.map +1 -0
  65. package/dist/chunk-XG2OYFX6.js +2925 -0
  66. package/dist/chunk-XG2OYFX6.js.map +1 -0
  67. package/dist/chunk-ZRAM6FXB.js +2949 -0
  68. package/dist/chunk-ZRAM6FXB.js.map +1 -0
  69. package/dist/components/CsvViewer/CsvViewer.d.ts +51 -0
  70. package/dist/components/CsvViewer/CsvViewer.d.ts.map +1 -0
  71. package/dist/components/CsvViewer/index.d.ts +2 -0
  72. package/dist/components/CsvViewer/index.d.ts.map +1 -0
  73. package/dist/components/DataTable/DataTable.d.ts +19 -1
  74. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  75. package/dist/components/DropdownMenu/DropdownMenu.d.ts +12 -2
  76. package/dist/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  77. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts +8 -2
  78. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts.map +1 -1
  79. package/dist/components/FlowMinimap/FlowMinimap.d.ts +17 -1
  80. package/dist/components/FlowMinimap/FlowMinimap.d.ts.map +1 -1
  81. package/dist/components/FlowToolbar/FlowToolbar.d.ts +16 -10
  82. package/dist/components/FlowToolbar/FlowToolbar.d.ts.map +1 -1
  83. package/dist/components/JsonViewer/JsonViewer.d.ts +42 -7
  84. package/dist/components/JsonViewer/JsonViewer.d.ts.map +1 -1
  85. package/dist/components/JsonViewer/index.d.ts +1 -1
  86. package/dist/components/JsonViewer/index.d.ts.map +1 -1
  87. package/dist/components/Select/Select.d.ts.map +1 -1
  88. package/dist/components/WorkflowHeader/WorkflowHeader.d.ts +130 -0
  89. package/dist/components/WorkflowHeader/WorkflowHeader.d.ts.map +1 -0
  90. package/dist/components/WorkflowHeader/WorkflowHeaderExpanded.d.ts +69 -0
  91. package/dist/components/WorkflowHeader/WorkflowHeaderExpanded.d.ts.map +1 -0
  92. package/dist/components/WorkflowHeader/index.d.ts +3 -0
  93. package/dist/components/WorkflowHeader/index.d.ts.map +1 -0
  94. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCentered.d.ts +40 -0
  95. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCentered.d.ts.map +1 -0
  96. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCommand.d.ts +39 -0
  97. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCommand.d.ts.map +1 -0
  98. package/dist/components/WorkflowHeader/misc/WorkflowHeaderMinimal.d.ts +44 -0
  99. package/dist/components/WorkflowHeader/misc/WorkflowHeaderMinimal.d.ts.map +1 -0
  100. package/dist/components/WorkflowHeader/misc/WorkflowHeaderRail.d.ts +45 -0
  101. package/dist/components/WorkflowHeader/misc/WorkflowHeaderRail.d.ts.map +1 -0
  102. package/dist/components/WorkflowHeader/misc/WorkflowHeaderStudio.d.ts +48 -0
  103. package/dist/components/WorkflowHeader/misc/WorkflowHeaderStudio.d.ts.map +1 -0
  104. package/dist/components/WorkflowHeader/misc/WorkflowHeaderTiered.d.ts +52 -0
  105. package/dist/components/WorkflowHeader/misc/WorkflowHeaderTiered.d.ts.map +1 -0
  106. package/dist/components/XmlViewer/XmlViewer.d.ts +26 -1
  107. package/dist/components/XmlViewer/XmlViewer.d.ts.map +1 -1
  108. package/dist/components/XmlViewer/index.d.ts +1 -1
  109. package/dist/components/XmlViewer/index.d.ts.map +1 -1
  110. package/dist/components/YamlViewer/YamlViewer.d.ts +26 -1
  111. package/dist/components/YamlViewer/YamlViewer.d.ts.map +1 -1
  112. package/dist/components/YamlViewer/index.d.ts +1 -1
  113. package/dist/components/YamlViewer/index.d.ts.map +1 -1
  114. package/dist/hooks/useRelativeTime.d.ts +28 -0
  115. package/dist/hooks/useRelativeTime.d.ts.map +1 -0
  116. package/dist/hooks/useWorkflowRuntime.d.ts +20 -0
  117. package/dist/hooks/useWorkflowRuntime.d.ts.map +1 -0
  118. package/dist/index.cjs +4874 -3512
  119. package/dist/index.cjs.map +1 -1
  120. package/dist/index.d.ts +7 -3
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +4317 -3305
  123. package/dist/index.js.map +1 -1
  124. package/dist/styles.css +1 -1
  125. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts +49 -1
  126. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts.map +1 -1
  127. package/dist/workflow/components/kinds/index.d.ts +4 -0
  128. package/dist/workflow/components/kinds/index.d.ts.map +1 -1
  129. package/dist/workflow/index.d.ts +1 -1
  130. package/dist/workflow/index.d.ts.map +1 -1
  131. package/dist/workflow/store/selectors.d.ts +12 -0
  132. package/dist/workflow/store/selectors.d.ts.map +1 -1
  133. package/dist/workflow/utils/parenting.d.ts +5 -3
  134. package/dist/workflow/utils/parenting.d.ts.map +1 -1
  135. package/dist/workflow.cjs +576 -361
  136. package/dist/workflow.cjs.map +1 -1
  137. package/dist/workflow.js +19 -205
  138. package/dist/workflow.js.map +1 -1
  139. package/package.json +10 -6
package/dist/workflow.cjs CHANGED
@@ -77,7 +77,8 @@ __export(workflow_exports, {
77
77
  useNodeData: () => useNodeData,
78
78
  useNodes: () => useNodes,
79
79
  useSelection: () => useSelection,
80
- useViewport: () => useViewport
80
+ useViewport: () => useViewport,
81
+ useViewportOrNull: () => useViewportOrNull
81
82
  });
82
83
  module.exports = __toCommonJS(workflow_exports);
83
84
 
@@ -646,6 +647,23 @@ function useEdges() {
646
647
  function useViewport() {
647
648
  return useFlowSelector((s) => s.viewport);
648
649
  }
650
+ var VIEWPORT_OR_NULL_NO_STORE_SUBSCRIBE = (_cb) => () => {
651
+ };
652
+ var VIEWPORT_OR_NULL_NO_STORE_SNAPSHOT = () => null;
653
+ function useViewportOrNull() {
654
+ const store = (0, import_react5.useContext)(FlowStoreContext);
655
+ const { sub, snap } = (0, import_react5.useMemo)(
656
+ () => store ? {
657
+ sub: store.subscribe,
658
+ snap: () => store.getSnapshot().viewport
659
+ } : {
660
+ sub: VIEWPORT_OR_NULL_NO_STORE_SUBSCRIBE,
661
+ snap: VIEWPORT_OR_NULL_NO_STORE_SNAPSHOT
662
+ },
663
+ [store]
664
+ );
665
+ return (0, import_react5.useSyncExternalStore)(sub, snap, snap);
666
+ }
649
667
  function useNodeById(id) {
650
668
  return useFlowSelector((s) => s.nodes.find((n) => n.id === id));
651
669
  }
@@ -943,7 +961,7 @@ function ConfigPanel({
943
961
  }
944
962
 
945
963
  // src/workflow/components/FlowCanvas/FlowCanvas.tsx
946
- var import_react14 = require("react");
964
+ var import_react15 = require("react");
947
965
 
948
966
  // src/workflow/store/createFlowStore.ts
949
967
  var DEFAULT_VIEWPORT = { x: 0, y: 0, zoom: 1 };
@@ -1126,7 +1144,7 @@ function findContainingGroup(point, nodes, exclude = []) {
1126
1144
  for (let i = nodes.length - 1; i >= 0; i--) {
1127
1145
  const n = nodes[i];
1128
1146
  if (exclude.includes(n.id)) continue;
1129
- if (n.type !== "group") continue;
1147
+ if (n.type !== "group" && n.type !== "forEach") continue;
1130
1148
  if (n.data && typeof n.data === "object" && n.data.collapsed) {
1131
1149
  continue;
1132
1150
  }
@@ -1791,10 +1809,155 @@ function handleSideStyle(side, index, total) {
1791
1809
  }
1792
1810
  }
1793
1811
 
1794
- // src/workflow/components/kinds/BaseNode.tsx
1795
- var import_icons = require("@octaviaflow/icons");
1812
+ // src/workflow/components/NodeResizer/NodeResizer.tsx
1796
1813
  var import_react13 = require("react");
1797
1814
  var import_jsx_runtime5 = require("react/jsx-runtime");
1815
+ function NodeResizer({
1816
+ isVisible,
1817
+ minWidth = 80,
1818
+ minHeight = 60,
1819
+ maxWidth,
1820
+ maxHeight,
1821
+ keepAspectRatio = false,
1822
+ onResize,
1823
+ onResizeEnd,
1824
+ color
1825
+ }) {
1826
+ const { node, selected } = useFlowNodeContext();
1827
+ const viewport = useViewport();
1828
+ const flow = useFlow();
1829
+ const dragRef = (0, import_react13.useRef)(null);
1830
+ const show = isVisible ?? selected;
1831
+ if (!show) return null;
1832
+ const beginResize = (e, corner) => {
1833
+ e.preventDefault();
1834
+ e.stopPropagation();
1835
+ e.target.setPointerCapture(e.pointerId);
1836
+ const w = node.width ?? DEFAULT_NODE_WIDTH;
1837
+ const h = node.height ?? DEFAULT_NODE_HEIGHT;
1838
+ dragRef.current = {
1839
+ pointerId: e.pointerId,
1840
+ corner,
1841
+ startClientX: e.clientX,
1842
+ startClientY: e.clientY,
1843
+ startWidth: w,
1844
+ startHeight: h,
1845
+ startX: node.position.x,
1846
+ startY: node.position.y,
1847
+ aspect: w / Math.max(1, h)
1848
+ };
1849
+ };
1850
+ const onMove = (e) => {
1851
+ const drag = dragRef.current;
1852
+ if (!drag || drag.pointerId !== e.pointerId) return;
1853
+ const dx = (e.clientX - drag.startClientX) / viewport.zoom;
1854
+ const dy = (e.clientY - drag.startClientY) / viewport.zoom;
1855
+ let nextW = drag.startWidth;
1856
+ let nextH = drag.startHeight;
1857
+ let nextX = drag.startX;
1858
+ let nextY = drag.startY;
1859
+ switch (drag.corner) {
1860
+ case "se":
1861
+ nextW = drag.startWidth + dx;
1862
+ nextH = drag.startHeight + dy;
1863
+ break;
1864
+ case "sw":
1865
+ nextW = drag.startWidth - dx;
1866
+ nextH = drag.startHeight + dy;
1867
+ nextX = drag.startX + dx;
1868
+ break;
1869
+ case "ne":
1870
+ nextW = drag.startWidth + dx;
1871
+ nextH = drag.startHeight - dy;
1872
+ nextY = drag.startY + dy;
1873
+ break;
1874
+ case "nw":
1875
+ nextW = drag.startWidth - dx;
1876
+ nextH = drag.startHeight - dy;
1877
+ nextX = drag.startX + dx;
1878
+ nextY = drag.startY + dy;
1879
+ break;
1880
+ }
1881
+ if (keepAspectRatio) {
1882
+ nextH = nextW / drag.aspect;
1883
+ if (drag.corner === "nw" || drag.corner === "ne") {
1884
+ nextY = drag.startY + (drag.startHeight - nextH);
1885
+ }
1886
+ }
1887
+ nextW = Math.max(minWidth, maxWidth ? Math.min(maxWidth, nextW) : nextW);
1888
+ nextH = Math.max(minHeight, maxHeight ? Math.min(maxHeight, nextH) : nextH);
1889
+ flow.updateNode(node.id, {
1890
+ width: nextW,
1891
+ height: nextH,
1892
+ position: { x: nextX, y: nextY }
1893
+ });
1894
+ onResize?.({ width: nextW, height: nextH });
1895
+ };
1896
+ const onUp = (e) => {
1897
+ if (dragRef.current?.pointerId === e.pointerId) {
1898
+ const cur = flow.getNode(node.id);
1899
+ if (cur) {
1900
+ onResizeEnd?.({
1901
+ width: cur.width ?? DEFAULT_NODE_WIDTH,
1902
+ height: cur.height ?? DEFAULT_NODE_HEIGHT
1903
+ });
1904
+ }
1905
+ dragRef.current = null;
1906
+ }
1907
+ };
1908
+ const handleColor = color ?? "var(--ods-accent)";
1909
+ const handleStyle = (corner) => {
1910
+ const base = {
1911
+ position: "absolute",
1912
+ width: 12,
1913
+ height: 12,
1914
+ background: "var(--ods-surface-canvas)",
1915
+ border: `2px solid ${handleColor}`,
1916
+ borderRadius: 2,
1917
+ cursor: cursorFor(corner),
1918
+ touchAction: "none",
1919
+ // Place each handle so its CENTRE sits on the corresponding corner.
1920
+ transform: "translate(-50%, -50%)"
1921
+ };
1922
+ switch (corner) {
1923
+ case "nw":
1924
+ return { ...base, top: 0, left: 0 };
1925
+ case "ne":
1926
+ return { ...base, top: 0, left: "100%" };
1927
+ case "sw":
1928
+ return { ...base, top: "100%", left: 0 };
1929
+ case "se":
1930
+ return { ...base, top: "100%", left: "100%" };
1931
+ }
1932
+ };
1933
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: cn("ods-node-resizer"), "data-flow-no-drag": "true", children: ["nw", "ne", "sw", "se"].map((corner) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1934
+ "div",
1935
+ {
1936
+ style: handleStyle(corner),
1937
+ onPointerDown: (e) => beginResize(e, corner),
1938
+ onPointerMove: onMove,
1939
+ onPointerUp: onUp,
1940
+ onPointerCancel: onUp,
1941
+ "aria-label": `Resize ${corner}`
1942
+ },
1943
+ corner
1944
+ )) });
1945
+ }
1946
+ function cursorFor(corner) {
1947
+ switch (corner) {
1948
+ case "nw":
1949
+ case "se":
1950
+ return "nwse-resize";
1951
+ case "ne":
1952
+ case "sw":
1953
+ return "nesw-resize";
1954
+ }
1955
+ }
1956
+
1957
+ // src/workflow/components/kinds/BaseNode.tsx
1958
+ var import_icons = require("@octaviaflow/icons");
1959
+ var import_react14 = require("react");
1960
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1798
1961
  function BaseNode({
1799
1962
  kind,
1800
1963
  kindIcon,
@@ -1810,10 +1973,10 @@ function BaseNode({
1810
1973
  className,
1811
1974
  children
1812
1975
  }) {
1813
- const ctx = (0, import_react13.useContext)(FlowNodeContext);
1814
- const bridge = (0, import_react13.useContext)(FlowNodeBridgeContext);
1976
+ const ctx = (0, import_react14.useContext)(FlowNodeContext);
1977
+ const bridge = (0, import_react14.useContext)(FlowNodeBridgeContext);
1815
1978
  const deleteHandler = onDelete === false ? void 0 : onDelete ?? (ctx && bridge ? () => bridge.deleteNode(ctx.id) : void 0);
1816
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1979
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1817
1980
  "div",
1818
1981
  {
1819
1982
  className: cn(
@@ -1823,31 +1986,31 @@ function BaseNode({
1823
1986
  className
1824
1987
  ),
1825
1988
  children: [
1826
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ods-flow-base-node__pill", children: [
1827
- kindIcon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ods-flow-base-node__pill-icon", "aria-hidden": "true", children: kindIcon }),
1828
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ods-flow-base-node__pill-label", children: kind })
1989
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ods-flow-base-node__pill", children: [
1990
+ kindIcon && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-base-node__pill-icon", "aria-hidden": "true", children: kindIcon }),
1991
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-base-node__pill-label", children: kind })
1829
1992
  ] }),
1830
- status && status !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1993
+ status && status !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1831
1994
  "span",
1832
1995
  {
1833
1996
  className: cn("ods-flow-base-node__status", `ods-flow-base-node__status--${status}`),
1834
1997
  "aria-hidden": "true"
1835
1998
  }
1836
1999
  ),
1837
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ods-flow-base-node__body", children: [
1838
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ods-flow-base-node__content", children: [
1839
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ods-flow-base-node__bubble", "aria-hidden": "true", children: icon }),
1840
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ods-flow-base-node__content-text", children: [
1841
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ods-flow-base-node__content-title", children: title }),
1842
- (chip !== void 0 || description !== void 0 || valueChip !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ods-flow-base-node__content-info", children: [
1843
- chip !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ods-flow-base-node__chip", children: chip }),
1844
- description !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ods-flow-base-node__description", children: description }),
1845
- valueChip !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ods-flow-base-node__value-chip", children: valueChip })
2000
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ods-flow-base-node__body", children: [
2001
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ods-flow-base-node__content", children: [
2002
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ods-flow-base-node__bubble", "aria-hidden": "true", children: icon }),
2003
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ods-flow-base-node__content-text", children: [
2004
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ods-flow-base-node__content-title", children: title }),
2005
+ (chip !== void 0 || description !== void 0 || valueChip !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ods-flow-base-node__content-info", children: [
2006
+ chip !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-base-node__chip", children: chip }),
2007
+ description !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-base-node__description", children: description }),
2008
+ valueChip !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-base-node__value-chip", children: valueChip })
1846
2009
  ] })
1847
2010
  ] })
1848
2011
  ] }),
1849
- footer && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ods-flow-base-node__footer", children: footer }),
1850
- deleteHandler && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2012
+ footer && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ods-flow-base-node__footer", children: footer }),
2013
+ deleteHandler && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1851
2014
  "button",
1852
2015
  {
1853
2016
  type: "button",
@@ -1859,7 +2022,7 @@ function BaseNode({
1859
2022
  "aria-label": "Delete node",
1860
2023
  "data-flow-no-drag": "true",
1861
2024
  title: "Delete node",
1862
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons.TrashCanIcon, { size: 16, "aria-hidden": true })
2025
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_icons.TrashCanIcon, { size: 16, "aria-hidden": true })
1863
2026
  }
1864
2027
  )
1865
2028
  ] }),
@@ -1870,12 +2033,12 @@ function BaseNode({
1870
2033
  }
1871
2034
 
1872
2035
  // src/workflow/components/kinds/index.tsx
1873
- var import_jsx_runtime6 = require("react/jsx-runtime");
2036
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1874
2037
  var ActionNode = ({
1875
2038
  node
1876
2039
  }) => {
1877
2040
  const d = node.data ?? {};
1878
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2041
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1879
2042
  BaseNode,
1880
2043
  {
1881
2044
  kind: d.kind ?? "ACTION",
@@ -1887,8 +2050,8 @@ var ActionNode = ({
1887
2050
  status: d.status,
1888
2051
  accent: "green",
1889
2052
  children: [
1890
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top" }),
1891
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom" })
2053
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top" }),
2054
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom" })
1892
2055
  ]
1893
2056
  }
1894
2057
  );
@@ -1897,7 +2060,7 @@ var TriggerNode = ({
1897
2060
  node
1898
2061
  }) => {
1899
2062
  const d = node.data ?? {};
1900
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2063
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1901
2064
  BaseNode,
1902
2065
  {
1903
2066
  kind: d.kind ?? "TRIGGER",
@@ -1908,7 +2071,7 @@ var TriggerNode = ({
1908
2071
  valueChip: d.valueChip,
1909
2072
  status: d.status,
1910
2073
  accent: "green",
1911
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom" })
2074
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom" })
1912
2075
  }
1913
2076
  );
1914
2077
  };
@@ -1920,7 +2083,7 @@ var ConditionNode = ({
1920
2083
  { id: "true", label: "true" },
1921
2084
  { id: "false", label: "false" }
1922
2085
  ];
1923
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2086
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1924
2087
  BaseNode,
1925
2088
  {
1926
2089
  kind: d.kind ?? "CONDITION",
@@ -1932,8 +2095,8 @@ var ConditionNode = ({
1932
2095
  status: d.status,
1933
2096
  accent: "amber",
1934
2097
  children: [
1935
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top" }),
1936
- branches.map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2098
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top" }),
2099
+ branches.map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1937
2100
  Handle,
1938
2101
  {
1939
2102
  type: "source",
@@ -1954,24 +2117,27 @@ var GroupNode = ({
1954
2117
  }) => {
1955
2118
  const d = node.data ?? {};
1956
2119
  const collapsed = !!d.collapsed;
2120
+ const disabled = !!d.disabled;
1957
2121
  const hiddenCount = d.hiddenCount;
1958
2122
  const bridge = useFlowNodeBridge();
1959
2123
  const onChevronClick = (e) => {
1960
2124
  e.stopPropagation();
1961
2125
  bridge.toggleNodeCollapse(node.id);
1962
2126
  };
1963
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2127
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1964
2128
  "div",
1965
2129
  {
1966
2130
  className: "ods-flow-group",
1967
2131
  "data-collapsed": collapsed ? "true" : "false",
2132
+ "data-disabled": disabled ? "true" : void 0,
1968
2133
  style: {
1969
2134
  width: node.width ?? 360,
1970
2135
  height: collapsed ? 36 : node.height ?? 200
1971
2136
  },
1972
2137
  children: [
1973
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ods-flow-group__header", "data-flow-no-drag": "false", children: [
1974
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2138
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NodeResizer, { minWidth: 240, minHeight: 120 }),
2139
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ods-flow-group__header", "data-flow-no-drag": "false", children: [
2140
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1975
2141
  "button",
1976
2142
  {
1977
2143
  type: "button",
@@ -1984,15 +2150,16 @@ var GroupNode = ({
1984
2150
  children: collapsed ? "\u25B8" : "\u25BE"
1985
2151
  }
1986
2152
  ),
1987
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-group__title", children: d.title ?? "Group" }),
1988
- d.subtitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-group__subtitle", children: d.subtitle }),
1989
- collapsed && hiddenCount !== void 0 && hiddenCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ods-flow-group__count", "aria-label": `${hiddenCount} hidden steps`, children: [
2153
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ods-flow-group__title", children: d.title ?? "Group" }),
2154
+ d.subtitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ods-flow-group__subtitle", children: d.subtitle }),
2155
+ disabled && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ods-flow-group__disabled-badge", "aria-label": "Disabled subflow", children: "Disabled" }),
2156
+ collapsed && hiddenCount !== void 0 && hiddenCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ods-flow-group__count", "aria-label": `${hiddenCount} hidden steps`, children: [
1990
2157
  hiddenCount,
1991
2158
  " steps"
1992
2159
  ] })
1993
2160
  ] }),
1994
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top", id: "__group_in" }),
1995
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom", id: "__group_out" })
2161
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top", id: "__group_in" }),
2162
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom", id: "__group_out" })
1996
2163
  ]
1997
2164
  }
1998
2165
  );
@@ -2003,24 +2170,27 @@ var ForEachNode = ({
2003
2170
  const d = node.data ?? {};
2004
2171
  const iteratorExpr = d.iterator ?? d.description ?? "items[]";
2005
2172
  const collapsed = !!d.collapsed;
2173
+ const disabled = !!d.disabled;
2006
2174
  const hiddenCount = d.hiddenCount;
2007
2175
  const bridge = useFlowNodeBridge();
2008
2176
  const onChevronClick = (e) => {
2009
2177
  e.stopPropagation();
2010
2178
  bridge.toggleNodeCollapse(node.id);
2011
2179
  };
2012
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2180
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2013
2181
  "div",
2014
2182
  {
2015
2183
  className: "ods-flow-foreach",
2016
2184
  "data-collapsed": collapsed ? "true" : "false",
2185
+ "data-disabled": disabled ? "true" : void 0,
2017
2186
  style: {
2018
2187
  width: node.width ?? 420,
2019
2188
  height: collapsed ? 40 : node.height ?? 260
2020
2189
  },
2021
2190
  children: [
2022
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ods-flow-foreach__header", children: [
2023
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2191
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NodeResizer, { minWidth: 240, minHeight: 120 }),
2192
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ods-flow-foreach__header", children: [
2193
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2024
2194
  "button",
2025
2195
  {
2026
2196
  type: "button",
@@ -2033,24 +2203,57 @@ var ForEachNode = ({
2033
2203
  children: collapsed ? "\u25B8" : "\u25BE"
2034
2204
  }
2035
2205
  ),
2036
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-foreach__icon", "aria-hidden": "true", children: "\u21BB" }),
2037
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ods-flow-foreach__title", children: d.title ?? "For each" }),
2038
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "ods-flow-foreach__iterator", children: iteratorExpr }),
2039
- collapsed && hiddenCount !== void 0 && hiddenCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ods-flow-foreach__count", "aria-label": `${hiddenCount} hidden steps`, children: [
2206
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ods-flow-foreach__icon", "aria-hidden": "true", children: "\u21BB" }),
2207
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ods-flow-foreach__title", children: d.title ?? "For each" }),
2208
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { className: "ods-flow-foreach__iterator", children: iteratorExpr }),
2209
+ disabled && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2210
+ "span",
2211
+ {
2212
+ className: "ods-flow-foreach__disabled-badge",
2213
+ "aria-label": "Disabled subflow",
2214
+ children: "Disabled"
2215
+ }
2216
+ ),
2217
+ collapsed && hiddenCount !== void 0 && hiddenCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ods-flow-foreach__count", "aria-label": `${hiddenCount} hidden steps`, children: [
2040
2218
  hiddenCount,
2041
2219
  " steps"
2042
2220
  ] })
2043
2221
  ] }),
2044
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top", id: "__group_in" }),
2045
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom", id: "__group_out" }),
2046
- !collapsed && // Expanded mode full 3-handle iterator surface (in / item / done).
2047
- // `in` shares the top edge with `__group_in`; consumers wiring an
2048
- // explicit `targetHandle: "in"` get the labelled, visible variant.
2049
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2050
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top", id: "in", label: "in" }),
2051
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "right", id: "item", label: "item" }),
2052
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom", id: "done", label: "done" })
2053
- ] })
2222
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top", id: "__group_in", label: !collapsed ? "in" : void 0 }),
2223
+ collapsed ? (
2224
+ // Collapsed: single bottom exit so the container behaves like a
2225
+ // regular action in the chain.
2226
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom", id: "__group_out" })
2227
+ ) : (
2228
+ // Expanded: two bottom outputs spread across the bottom edge.
2229
+ // Index/total tell the Handle to position them at 33% and 66%
2230
+ // along the edge (per `handleSideStyle`). `each` is left of
2231
+ // centre, `__group_out` (labelled "done") is right of centre.
2232
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2233
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2234
+ Handle,
2235
+ {
2236
+ type: "source",
2237
+ position: "bottom",
2238
+ id: "each",
2239
+ label: "each",
2240
+ index: 0,
2241
+ total: 2
2242
+ }
2243
+ ),
2244
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2245
+ Handle,
2246
+ {
2247
+ type: "source",
2248
+ position: "bottom",
2249
+ id: "__group_out",
2250
+ label: "done",
2251
+ index: 1,
2252
+ total: 2
2253
+ }
2254
+ )
2255
+ ] })
2256
+ )
2054
2257
  ]
2055
2258
  }
2056
2259
  );
@@ -2059,7 +2262,7 @@ var OutputNode = ({
2059
2262
  node
2060
2263
  }) => {
2061
2264
  const d = node.data ?? {};
2062
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2265
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2063
2266
  BaseNode,
2064
2267
  {
2065
2268
  kind: d.kind ?? "OUTPUT",
@@ -2069,7 +2272,7 @@ var OutputNode = ({
2069
2272
  description: d.description ?? d.subtitle,
2070
2273
  status: d.status,
2071
2274
  accent: "green",
2072
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top" })
2275
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top" })
2073
2276
  }
2074
2277
  );
2075
2278
  };
@@ -2077,7 +2280,7 @@ var ErrorNode = ({
2077
2280
  node
2078
2281
  }) => {
2079
2282
  const d = node.data ?? {};
2080
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2283
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2081
2284
  BaseNode,
2082
2285
  {
2083
2286
  kind: d.kind ?? "ERROR",
@@ -2088,8 +2291,8 @@ var ErrorNode = ({
2088
2291
  status: d.status ?? "error",
2089
2292
  accent: "red",
2090
2293
  children: [
2091
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top" }),
2092
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom" })
2294
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top" }),
2295
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom" })
2093
2296
  ]
2094
2297
  }
2095
2298
  );
@@ -2100,7 +2303,7 @@ var WaitNode = ({
2100
2303
  const d = node.data ?? {};
2101
2304
  const waitMs = d.waitMs;
2102
2305
  const durationChip = waitMs ? `${Math.round(waitMs / 100) / 10}s` : void 0;
2103
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2306
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2104
2307
  BaseNode,
2105
2308
  {
2106
2309
  kind: d.kind ?? "WAIT",
@@ -2111,8 +2314,8 @@ var WaitNode = ({
2111
2314
  status: d.status,
2112
2315
  accent: "violet",
2113
2316
  children: [
2114
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top" }),
2115
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom" })
2317
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top" }),
2318
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom" })
2116
2319
  ]
2117
2320
  }
2118
2321
  );
@@ -2125,7 +2328,7 @@ var ParallelNode = ({
2125
2328
  { id: "a", label: "a" },
2126
2329
  { id: "b", label: "b" }
2127
2330
  ];
2128
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2331
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2129
2332
  BaseNode,
2130
2333
  {
2131
2334
  kind: d.kind ?? "PARALLEL",
@@ -2136,8 +2339,8 @@ var ParallelNode = ({
2136
2339
  status: d.status,
2137
2340
  accent: "blue",
2138
2341
  children: [
2139
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top" }),
2140
- branches.map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2342
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top" }),
2343
+ branches.map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2141
2344
  Handle,
2142
2345
  {
2143
2346
  type: "source",
@@ -2157,7 +2360,7 @@ var StickyNode = ({
2157
2360
  node
2158
2361
  }) => {
2159
2362
  const d = node.data ?? {};
2160
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2363
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2161
2364
  "div",
2162
2365
  {
2163
2366
  className: "ods-flow-sticky",
@@ -2166,8 +2369,8 @@ var StickyNode = ({
2166
2369
  minHeight: node.height ?? 120
2167
2370
  },
2168
2371
  children: [
2169
- d.title && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ods-flow-sticky__title", children: d.title }),
2170
- d.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ods-flow-sticky__body", children: d.description })
2372
+ d.title && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ods-flow-sticky__title", children: d.title }),
2373
+ d.description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ods-flow-sticky__body", children: d.description })
2171
2374
  ]
2172
2375
  }
2173
2376
  );
@@ -2176,7 +2379,7 @@ var WebhookNode = ({
2176
2379
  node
2177
2380
  }) => {
2178
2381
  const d = node.data ?? {};
2179
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2382
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2180
2383
  BaseNode,
2181
2384
  {
2182
2385
  kind: d.kind ?? "WEBHOOK",
@@ -2187,7 +2390,7 @@ var WebhookNode = ({
2187
2390
  valueChip: d.valueChip,
2188
2391
  status: d.status,
2189
2392
  accent: "blue",
2190
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom" })
2393
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom" })
2191
2394
  }
2192
2395
  );
2193
2396
  };
@@ -2195,7 +2398,7 @@ var HttpRequestNode = ({
2195
2398
  node
2196
2399
  }) => {
2197
2400
  const d = node.data ?? {};
2198
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2401
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2199
2402
  BaseNode,
2200
2403
  {
2201
2404
  kind: d.kind ?? "HTTP",
@@ -2207,8 +2410,8 @@ var HttpRequestNode = ({
2207
2410
  status: d.status,
2208
2411
  accent: "blue",
2209
2412
  children: [
2210
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "target", position: "top" }),
2211
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Handle, { type: "source", position: "bottom" })
2413
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "target", position: "top" }),
2414
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Handle, { type: "source", position: "bottom" })
2212
2415
  ]
2213
2416
  }
2214
2417
  );
@@ -2229,52 +2432,60 @@ var DEFAULT_NODE_KINDS = {
2229
2432
  };
2230
2433
 
2231
2434
  // src/workflow/components/FlowCanvas/FlowCanvas.tsx
2232
- var import_jsx_runtime7 = require("react/jsx-runtime");
2435
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2233
2436
  var DEFAULT_VIEWPORT2 = { x: 0, y: 0, zoom: 1 };
2234
- function FlowCanvas({
2235
- nodes,
2236
- edges,
2237
- onNodesChange,
2238
- onEdgesChange,
2239
- viewport: controlledViewport,
2240
- defaultViewport = DEFAULT_VIEWPORT2,
2241
- onViewportChange,
2242
- minZoom = 0.25,
2243
- maxZoom = 2,
2244
- nodeKinds,
2245
- onConnect,
2246
- onConnectStart,
2247
- onConnectEnd,
2248
- isValidConnection,
2249
- onSelectionChange,
2250
- onPaneClick,
2251
- onNodeClick,
2252
- onEdgeClick,
2253
- onEdgeLabelChange,
2254
- onInit,
2255
- onBeforeDelete,
2256
- onNodeContextMenu,
2257
- onEdgeContextMenu,
2258
- onPaneContextMenu,
2259
- nodesDraggable = true,
2260
- nodesConnectable = true,
2261
- panOnDrag: panOnDragProp,
2262
- zoomOnScroll: zoomOnScrollProp,
2263
- preset = "mouse",
2264
- paneClickDistance = 4,
2265
- paneClickClearsSelection = true,
2266
- background = "dots",
2267
- gridSize = 20,
2268
- snapToGrid = false,
2269
- nodeCollisionGap = -1,
2270
- subflowCollisionGap,
2271
- height = "100%",
2272
- width = "100%",
2273
- className,
2274
- style,
2275
- children,
2276
- emptyState
2277
- }) {
2437
+ function FlowCanvas(props) {
2438
+ const viewportPropProvided = props.viewport !== void 0 || props.defaultViewport !== void 0;
2439
+ const {
2440
+ nodes,
2441
+ edges,
2442
+ onNodesChange,
2443
+ onEdgesChange,
2444
+ viewport: controlledViewport,
2445
+ defaultViewport = DEFAULT_VIEWPORT2,
2446
+ onViewportChange,
2447
+ minZoom = 0.25,
2448
+ maxZoom = 2,
2449
+ fitViewOnInit,
2450
+ nodeKinds,
2451
+ onConnect,
2452
+ onConnectStart,
2453
+ onConnectEnd,
2454
+ isValidConnection,
2455
+ onSelectionChange,
2456
+ onPaneClick,
2457
+ onNodeClick,
2458
+ onEdgeClick,
2459
+ onEdgeLabelChange,
2460
+ onInit,
2461
+ onBeforeDelete,
2462
+ onNodeContextMenu,
2463
+ onEdgeContextMenu,
2464
+ onPaneContextMenu,
2465
+ nodesDraggable = true,
2466
+ nodesConnectable = true,
2467
+ panOnDrag: panOnDragProp,
2468
+ zoomOnScroll: zoomOnScrollProp,
2469
+ preset = "mouse",
2470
+ paneClickDistance = 4,
2471
+ paneClickClearsSelection = true,
2472
+ background = "dots",
2473
+ gridSize = 20,
2474
+ snapToGrid = false,
2475
+ nodeCollisionGap = -1,
2476
+ subflowCollisionGap,
2477
+ reparentOnDrag = false,
2478
+ autoResizeContainers = false,
2479
+ containerAutoResizePadding = 32,
2480
+ containerMinWidth = 320,
2481
+ containerMinHeight = 200,
2482
+ height = "100%",
2483
+ width = "100%",
2484
+ className,
2485
+ style,
2486
+ children,
2487
+ emptyState
2488
+ } = props;
2278
2489
  const presetDefaults = {
2279
2490
  mouse: { panOnDrag: true, zoomOnScroll: true },
2280
2491
  trackpad: { panOnDrag: true, zoomOnScroll: true },
@@ -2282,46 +2493,46 @@ function FlowCanvas({
2282
2493
  };
2283
2494
  const panOnDrag = panOnDragProp ?? presetDefaults[preset].panOnDrag;
2284
2495
  const zoomOnScroll = zoomOnScrollProp ?? presetDefaults[preset].zoomOnScroll;
2285
- const store = (0, import_react14.useState)(
2496
+ const store = (0, import_react15.useState)(
2286
2497
  () => createFlowStore({
2287
2498
  initialNodes: nodes,
2288
2499
  initialEdges: edges,
2289
2500
  initialViewport: controlledViewport ?? defaultViewport
2290
2501
  })
2291
2502
  )[0];
2292
- const handleRegistry = (0, import_react14.useState)(() => createHandleRegistry())[0];
2293
- const [handleVersion, setHandleVersion] = (0, import_react14.useState)(0);
2294
- (0, import_react14.useEffect)(() => {
2503
+ const handleRegistry = (0, import_react15.useState)(() => createHandleRegistry())[0];
2504
+ const [handleVersion, setHandleVersion] = (0, import_react15.useState)(0);
2505
+ (0, import_react15.useEffect)(() => {
2295
2506
  const unsub = handleRegistry.subscribe(() => {
2296
2507
  setHandleVersion((v) => v + 1);
2297
2508
  });
2298
2509
  return unsub;
2299
2510
  }, [handleRegistry]);
2300
- const kinds = (0, import_react14.useMemo)(() => buildNodeKindRegistry(DEFAULT_NODE_KINDS, nodeKinds), [nodeKinds]);
2301
- const containerRef = (0, import_react14.useRef)(null);
2302
- (0, import_react14.useEffect)(() => store.setNodes(nodes), [store, nodes]);
2303
- (0, import_react14.useEffect)(() => store.setEdges(edges), [store, edges]);
2304
- const [uncontrolledVp, setUncontrolledVp] = (0, import_react14.useState)(controlledViewport ?? defaultViewport);
2511
+ const kinds = (0, import_react15.useMemo)(() => buildNodeKindRegistry(DEFAULT_NODE_KINDS, nodeKinds), [nodeKinds]);
2512
+ const containerRef = (0, import_react15.useRef)(null);
2513
+ (0, import_react15.useEffect)(() => store.setNodes(nodes), [store, nodes]);
2514
+ (0, import_react15.useEffect)(() => store.setEdges(edges), [store, edges]);
2515
+ const [uncontrolledVp, setUncontrolledVp] = (0, import_react15.useState)(controlledViewport ?? defaultViewport);
2305
2516
  const viewport = controlledViewport ?? uncontrolledVp;
2306
- (0, import_react14.useEffect)(() => store.setViewport(viewport), [store, viewport]);
2307
- const setViewport = (0, import_react14.useCallback)(
2517
+ (0, import_react15.useEffect)(() => store.setViewport(viewport), [store, viewport]);
2518
+ const setViewport = (0, import_react15.useCallback)(
2308
2519
  (next) => {
2309
2520
  if (controlledViewport === void 0) setUncontrolledVp(next);
2310
2521
  onViewportChange?.(next);
2311
2522
  },
2312
2523
  [controlledViewport, onViewportChange]
2313
2524
  );
2314
- const selectedNodeIds = (0, import_react14.useMemo)(() => {
2525
+ const selectedNodeIds = (0, import_react15.useMemo)(() => {
2315
2526
  const s = /* @__PURE__ */ new Set();
2316
2527
  for (const n of nodes) if (n.selected) s.add(n.id);
2317
2528
  return s;
2318
2529
  }, [nodes]);
2319
- const selectedEdgeIds = (0, import_react14.useMemo)(() => {
2530
+ const selectedEdgeIds = (0, import_react15.useMemo)(() => {
2320
2531
  const s = /* @__PURE__ */ new Set();
2321
2532
  for (const e of edges) if (e.selected) s.add(e.id);
2322
2533
  return s;
2323
2534
  }, [edges]);
2324
- (0, import_react14.useEffect)(() => {
2535
+ (0, import_react15.useEffect)(() => {
2325
2536
  store.setSelection(selectedNodeIds, selectedEdgeIds);
2326
2537
  if (onSelectionChange) {
2327
2538
  onSelectionChange({
@@ -2330,7 +2541,7 @@ function FlowCanvas({
2330
2541
  });
2331
2542
  }
2332
2543
  }, [store, selectedNodeIds, selectedEdgeIds, nodes, edges, onSelectionChange]);
2333
- const selectNode = (0, import_react14.useCallback)(
2544
+ const selectNode = (0, import_react15.useCallback)(
2334
2545
  (id, additive) => {
2335
2546
  const next = [];
2336
2547
  const nextEdges = [];
@@ -2353,14 +2564,14 @@ function FlowCanvas({
2353
2564
  },
2354
2565
  [nodes, edges, selectedNodeIds, onNodesChange, onEdgesChange]
2355
2566
  );
2356
- const notifyNodeClick = (0, import_react14.useCallback)(
2567
+ const notifyNodeClick = (0, import_react15.useCallback)(
2357
2568
  (id) => {
2358
2569
  const node = nodes.find((n) => n.id === id);
2359
2570
  if (node) onNodeClick?.(node);
2360
2571
  },
2361
2572
  [nodes, onNodeClick]
2362
2573
  );
2363
- const selectEdge = (0, import_react14.useCallback)(
2574
+ const selectEdge = (0, import_react15.useCallback)(
2364
2575
  (id, additive) => {
2365
2576
  const next = [];
2366
2577
  const nextNodes = [];
@@ -2385,7 +2596,7 @@ function FlowCanvas({
2385
2596
  },
2386
2597
  [nodes, edges, selectedEdgeIds, onEdgesChange, onNodesChange, onEdgeClick]
2387
2598
  );
2388
- const clearSelection = (0, import_react14.useCallback)(() => {
2599
+ const clearSelection = (0, import_react15.useCallback)(() => {
2389
2600
  const ns = [];
2390
2601
  const es = [];
2391
2602
  for (const n of nodes) if (n.selected) ns.push(change.node.select(n.id, false));
@@ -2393,9 +2604,9 @@ function FlowCanvas({
2393
2604
  if (ns.length) onNodesChange?.(ns);
2394
2605
  if (es.length) onEdgesChange?.(es);
2395
2606
  }, [nodes, edges, onNodesChange, onEdgesChange]);
2396
- const dragRef = (0, import_react14.useRef)(null);
2397
- const [draggingId, setDraggingId] = (0, import_react14.useState)(null);
2398
- const beginNodeDrag = (0, import_react14.useCallback)(
2607
+ const dragRef = (0, import_react15.useRef)(null);
2608
+ const [draggingId, setDraggingId] = (0, import_react15.useState)(null);
2609
+ const beginNodeDrag = (0, import_react15.useCallback)(
2399
2610
  (nodeId, pointerId, clientX, clientY, altKey = false) => {
2400
2611
  if (!nodesDraggable) return;
2401
2612
  const node = nodes.find((n) => n.id === nodeId);
@@ -2404,6 +2615,9 @@ function FlowCanvas({
2404
2615
  id: d.id,
2405
2616
  startPosition: d.position
2406
2617
  }));
2618
+ const evaluateReparent = altKey || reparentOnDragRef.current;
2619
+ const hasParent = !!node.parentId;
2620
+ const skipClamp = altKey || reparentOnDragRef.current && !hasParent;
2407
2621
  dragRef.current = {
2408
2622
  pointerId,
2409
2623
  nodeId,
@@ -2411,7 +2625,8 @@ function FlowCanvas({
2411
2625
  startClientY: clientY,
2412
2626
  startPosition: node.position,
2413
2627
  descendants: kids,
2414
- altDetach: altKey && !!node.parentId,
2628
+ skipClamp,
2629
+ evaluateReparent,
2415
2630
  rafScheduled: false,
2416
2631
  nextDelta: null
2417
2632
  };
@@ -2420,12 +2635,12 @@ function FlowCanvas({
2420
2635
  },
2421
2636
  [nodes, nodesDraggable, selectNode]
2422
2637
  );
2423
- const [conn, setConn] = (0, import_react14.useState)(null);
2424
- const connRef = (0, import_react14.useRef)(null);
2425
- (0, import_react14.useEffect)(() => {
2638
+ const [conn, setConn] = (0, import_react15.useState)(null);
2639
+ const connRef = (0, import_react15.useRef)(null);
2640
+ (0, import_react15.useEffect)(() => {
2426
2641
  connRef.current = conn;
2427
2642
  }, [conn]);
2428
- const beginConnection = (0, import_react14.useCallback)(
2643
+ const beginConnection = (0, import_react15.useCallback)(
2429
2644
  (nodeId, handleId, handleType, pointerId, clientX, clientY) => {
2430
2645
  if (!nodesConnectable) return;
2431
2646
  const node = nodes.find((n) => n.id === nodeId);
@@ -2458,63 +2673,83 @@ function FlowCanvas({
2458
2673
  },
2459
2674
  [nodes, nodesConnectable, handleRegistry, viewport, store, onConnectStart]
2460
2675
  );
2461
- const viewportRef = (0, import_react14.useRef)(viewport);
2462
- const nodesRef = (0, import_react14.useRef)(nodes);
2463
- const edgesRef = (0, import_react14.useRef)(edges);
2464
- const onNodesChangeRefForInstance = (0, import_react14.useRef)(onNodesChange);
2465
- const onEdgesChangeRefForInstance = (0, import_react14.useRef)(onEdgesChange);
2466
- const onBeforeDeleteRef = (0, import_react14.useRef)(onBeforeDelete);
2467
- const snapToGridRef = (0, import_react14.useRef)(snapToGrid);
2468
- const gridSizeRef = (0, import_react14.useRef)(gridSize);
2469
- const nodeCollisionGapRef = (0, import_react14.useRef)(nodeCollisionGap);
2470
- const subflowCollisionGapRef = (0, import_react14.useRef)(subflowCollisionGap ?? nodeCollisionGap);
2471
- (0, import_react14.useEffect)(() => {
2676
+ const viewportRef = (0, import_react15.useRef)(viewport);
2677
+ const nodesRef = (0, import_react15.useRef)(nodes);
2678
+ const edgesRef = (0, import_react15.useRef)(edges);
2679
+ const onNodesChangeRefForInstance = (0, import_react15.useRef)(onNodesChange);
2680
+ const onEdgesChangeRefForInstance = (0, import_react15.useRef)(onEdgesChange);
2681
+ const onBeforeDeleteRef = (0, import_react15.useRef)(onBeforeDelete);
2682
+ const snapToGridRef = (0, import_react15.useRef)(snapToGrid);
2683
+ const gridSizeRef = (0, import_react15.useRef)(gridSize);
2684
+ const nodeCollisionGapRef = (0, import_react15.useRef)(nodeCollisionGap);
2685
+ const subflowCollisionGapRef = (0, import_react15.useRef)(subflowCollisionGap ?? nodeCollisionGap);
2686
+ const reparentOnDragRef = (0, import_react15.useRef)(reparentOnDrag);
2687
+ const autoResizeContainersRef = (0, import_react15.useRef)(autoResizeContainers);
2688
+ const containerAutoResizePaddingRef = (0, import_react15.useRef)(containerAutoResizePadding);
2689
+ const containerMinWidthRef = (0, import_react15.useRef)(containerMinWidth);
2690
+ const containerMinHeightRef = (0, import_react15.useRef)(containerMinHeight);
2691
+ (0, import_react15.useEffect)(() => {
2472
2692
  edgesRef.current = edges;
2473
2693
  }, [edges]);
2474
- (0, import_react14.useEffect)(() => {
2694
+ (0, import_react15.useEffect)(() => {
2475
2695
  onNodesChangeRefForInstance.current = onNodesChange;
2476
2696
  }, [onNodesChange]);
2477
- (0, import_react14.useEffect)(() => {
2697
+ (0, import_react15.useEffect)(() => {
2478
2698
  onEdgesChangeRefForInstance.current = onEdgesChange;
2479
2699
  }, [onEdgesChange]);
2480
- (0, import_react14.useEffect)(() => {
2700
+ (0, import_react15.useEffect)(() => {
2481
2701
  onBeforeDeleteRef.current = onBeforeDelete;
2482
2702
  }, [onBeforeDelete]);
2483
- (0, import_react14.useEffect)(() => {
2703
+ (0, import_react15.useEffect)(() => {
2484
2704
  snapToGridRef.current = snapToGrid;
2485
2705
  }, [snapToGrid]);
2486
- (0, import_react14.useEffect)(() => {
2706
+ (0, import_react15.useEffect)(() => {
2487
2707
  gridSizeRef.current = gridSize;
2488
2708
  }, [gridSize]);
2489
- (0, import_react14.useEffect)(() => {
2709
+ (0, import_react15.useEffect)(() => {
2490
2710
  nodeCollisionGapRef.current = nodeCollisionGap;
2491
2711
  }, [nodeCollisionGap]);
2492
- (0, import_react14.useEffect)(() => {
2712
+ (0, import_react15.useEffect)(() => {
2493
2713
  subflowCollisionGapRef.current = subflowCollisionGap ?? nodeCollisionGap;
2494
2714
  }, [subflowCollisionGap, nodeCollisionGap]);
2495
- const onNodesChangeRef = (0, import_react14.useRef)(onNodesChange);
2496
- const onConnectRef = (0, import_react14.useRef)(onConnect);
2497
- const onConnectEndRef = (0, import_react14.useRef)(onConnectEnd);
2498
- const isValidConnectionRef = (0, import_react14.useRef)(isValidConnection);
2499
- (0, import_react14.useEffect)(() => {
2715
+ (0, import_react15.useEffect)(() => {
2716
+ reparentOnDragRef.current = reparentOnDrag;
2717
+ }, [reparentOnDrag]);
2718
+ (0, import_react15.useEffect)(() => {
2719
+ autoResizeContainersRef.current = autoResizeContainers;
2720
+ }, [autoResizeContainers]);
2721
+ (0, import_react15.useEffect)(() => {
2722
+ containerAutoResizePaddingRef.current = containerAutoResizePadding;
2723
+ }, [containerAutoResizePadding]);
2724
+ (0, import_react15.useEffect)(() => {
2725
+ containerMinWidthRef.current = containerMinWidth;
2726
+ }, [containerMinWidth]);
2727
+ (0, import_react15.useEffect)(() => {
2728
+ containerMinHeightRef.current = containerMinHeight;
2729
+ }, [containerMinHeight]);
2730
+ const onNodesChangeRef = (0, import_react15.useRef)(onNodesChange);
2731
+ const onConnectRef = (0, import_react15.useRef)(onConnect);
2732
+ const onConnectEndRef = (0, import_react15.useRef)(onConnectEnd);
2733
+ const isValidConnectionRef = (0, import_react15.useRef)(isValidConnection);
2734
+ (0, import_react15.useEffect)(() => {
2500
2735
  viewportRef.current = viewport;
2501
2736
  }, [viewport]);
2502
- (0, import_react14.useEffect)(() => {
2737
+ (0, import_react15.useEffect)(() => {
2503
2738
  nodesRef.current = nodes;
2504
2739
  }, [nodes]);
2505
- (0, import_react14.useEffect)(() => {
2740
+ (0, import_react15.useEffect)(() => {
2506
2741
  onNodesChangeRef.current = onNodesChange;
2507
2742
  }, [onNodesChange]);
2508
- (0, import_react14.useEffect)(() => {
2743
+ (0, import_react15.useEffect)(() => {
2509
2744
  onConnectRef.current = onConnect;
2510
2745
  }, [onConnect]);
2511
- (0, import_react14.useEffect)(() => {
2746
+ (0, import_react15.useEffect)(() => {
2512
2747
  onConnectEndRef.current = onConnectEnd;
2513
2748
  }, [onConnectEnd]);
2514
- (0, import_react14.useEffect)(() => {
2749
+ (0, import_react15.useEffect)(() => {
2515
2750
  isValidConnectionRef.current = isValidConnection;
2516
2751
  }, [isValidConnection]);
2517
- (0, import_react14.useEffect)(() => {
2752
+ (0, import_react15.useEffect)(() => {
2518
2753
  const onPointerMove = (e) => {
2519
2754
  const vp = viewportRef.current;
2520
2755
  const drag = dragRef.current;
@@ -2536,7 +2771,7 @@ function FlowCanvas({
2536
2771
  x: d.startPosition.x + delta.dx,
2537
2772
  y: d.startPosition.y + delta.dy
2538
2773
  };
2539
- const clamped = d.altDetach ? proposed : clampToParentExtent(dragNode, proposed, nodesRef.current);
2774
+ const clamped = d.skipClamp ? proposed : clampToParentExtent(dragNode, proposed, nodesRef.current);
2540
2775
  const isContainer = dragNode.type === "group" || dragNode.type === "forEach";
2541
2776
  const gap = isContainer ? subflowCollisionGapRef.current : nodeCollisionGapRef.current;
2542
2777
  const excludeIds = /* @__PURE__ */ new Set([d.nodeId, ...d.descendants.map((kid) => kid.id)]);
@@ -2588,7 +2823,7 @@ function FlowCanvas({
2588
2823
  y: Math.round(proposed.y / g) * g
2589
2824
  };
2590
2825
  }
2591
- const clamped = drag.altDetach ? proposed : clampToParentExtent(dragNode, proposed, nodesRef.current);
2826
+ const clamped = drag.skipClamp ? proposed : clampToParentExtent(dragNode, proposed, nodesRef.current);
2592
2827
  const isContainer = dragNode.type === "group" || dragNode.type === "forEach";
2593
2828
  const gap = isContainer ? subflowCollisionGapRef.current : nodeCollisionGapRef.current;
2594
2829
  const excludeIds = /* @__PURE__ */ new Set([
@@ -2611,7 +2846,7 @@ function FlowCanvas({
2611
2846
  )
2612
2847
  );
2613
2848
  }
2614
- if (drag.altDetach && dragNode.parentId) {
2849
+ if (drag.evaluateReparent) {
2615
2850
  const targetGroup = findContainingGroup(
2616
2851
  {
2617
2852
  x: finalPos.x + (dragNode.width ?? 0) / 2,
@@ -2621,14 +2856,30 @@ function FlowCanvas({
2621
2856
  [drag.nodeId, ...drag.descendants.map((d) => d.id)]
2622
2857
  );
2623
2858
  const nextParentId = targetGroup?.id;
2624
- const updated = {
2625
- ...dragNode,
2626
- position: finalPos,
2627
- parentId: nextParentId,
2628
- // Preserve extent only when staying in a group.
2629
- extent: nextParentId ? dragNode.extent : void 0
2630
- };
2631
- changes.push(change.node.replace(drag.nodeId, updated));
2859
+ if (nextParentId !== dragNode.parentId) {
2860
+ const updated = {
2861
+ ...dragNode,
2862
+ position: finalPos,
2863
+ parentId: nextParentId,
2864
+ // Adopting into a container always pins the child with
2865
+ // `extent: 'parent'` so it's clamped from the next drag
2866
+ // on. Detaching clears it.
2867
+ extent: nextParentId ? "parent" : void 0
2868
+ };
2869
+ changes.push(change.node.replace(drag.nodeId, updated));
2870
+ }
2871
+ }
2872
+ if (autoResizeContainersRef.current) {
2873
+ const containerChanges = computeContainerAutoResize(
2874
+ nodesRef.current,
2875
+ // Projected children: apply the position + reparent
2876
+ // changes we just built before measuring bboxes.
2877
+ changes,
2878
+ containerAutoResizePaddingRef.current,
2879
+ containerMinWidthRef.current,
2880
+ containerMinHeightRef.current
2881
+ );
2882
+ for (const c2 of containerChanges) changes.push(c2);
2632
2883
  }
2633
2884
  onNodesChangeRef.current?.(changes);
2634
2885
  }
@@ -2637,8 +2888,19 @@ function FlowCanvas({
2637
2888
  }
2638
2889
  const c = connRef.current;
2639
2890
  if (c && c.pointerId === e.pointerId) {
2640
- const target = e.target;
2641
- const handleEl = target?.closest("[data-handle-id]");
2891
+ let handleEl = null;
2892
+ if (typeof document !== "undefined") {
2893
+ const stack = document.elementsFromPoint(e.clientX, e.clientY);
2894
+ for (const el of stack) {
2895
+ const candidate = el.closest(
2896
+ "[data-handle-id]"
2897
+ );
2898
+ if (!candidate) continue;
2899
+ if (candidate.dataset.handleNodeId === c.from.nodeId) continue;
2900
+ handleEl = candidate;
2901
+ break;
2902
+ }
2903
+ }
2642
2904
  let connection = null;
2643
2905
  let connectedTo;
2644
2906
  if (handleEl) {
@@ -2701,7 +2963,26 @@ function FlowCanvas({
2701
2963
  window.removeEventListener("pointercancel", onPointerCancel);
2702
2964
  };
2703
2965
  }, [store]);
2704
- const panRef = (0, import_react14.useRef)(null);
2966
+ (0, import_react15.useEffect)(() => {
2967
+ if (!autoResizeContainers || draggingId) return;
2968
+ const resizeChanges = computeContainerAutoResize(
2969
+ nodes,
2970
+ [],
2971
+ containerAutoResizePadding,
2972
+ containerMinWidth,
2973
+ containerMinHeight
2974
+ );
2975
+ if (resizeChanges.length > 0) onNodesChange?.(resizeChanges);
2976
+ }, [
2977
+ nodes,
2978
+ draggingId,
2979
+ autoResizeContainers,
2980
+ containerAutoResizePadding,
2981
+ containerMinWidth,
2982
+ containerMinHeight,
2983
+ onNodesChange
2984
+ ]);
2985
+ const panRef = (0, import_react15.useRef)(null);
2705
2986
  const onCanvasPointerDown = (e) => {
2706
2987
  if (e.button !== 0) return;
2707
2988
  const t = e.target;
@@ -2726,7 +3007,7 @@ function FlowCanvas({
2726
3007
  moved: false
2727
3008
  };
2728
3009
  };
2729
- (0, import_react14.useEffect)(() => {
3010
+ (0, import_react15.useEffect)(() => {
2730
3011
  const onMove = (e) => {
2731
3012
  const pan = panRef.current;
2732
3013
  if (!pan || pan.pointerId !== e.pointerId) return;
@@ -2782,7 +3063,7 @@ function FlowCanvas({
2782
3063
  y: py - (py - viewport.y) * k
2783
3064
  });
2784
3065
  };
2785
- const dispatch = (0, import_react14.useCallback)(
3066
+ const dispatch = (0, import_react15.useCallback)(
2786
3067
  (a) => {
2787
3068
  if (a.type === "connection/start") {
2788
3069
  beginConnection(a.nodeId, a.handleId, a.handleType, a.pointerId, a.clientX, a.clientY);
@@ -2790,7 +3071,7 @@ function FlowCanvas({
2790
3071
  },
2791
3072
  [beginConnection]
2792
3073
  );
2793
- const reportDimensions = (0, import_react14.useCallback)(
3074
+ const reportDimensions = (0, import_react15.useCallback)(
2794
3075
  (nodeId, width2, height2) => {
2795
3076
  const node = nodes.find((n) => n.id === nodeId);
2796
3077
  if (!node) return;
@@ -2799,7 +3080,7 @@ function FlowCanvas({
2799
3080
  },
2800
3081
  [nodes, onNodesChange]
2801
3082
  );
2802
- const toggleNodeCollapseImpl = (0, import_react14.useCallback)(
3083
+ const toggleNodeCollapseImpl = (0, import_react15.useCallback)(
2803
3084
  (nodeId) => {
2804
3085
  const node = nodes.find((n) => n.id === nodeId);
2805
3086
  if (!node) return;
@@ -2812,7 +3093,7 @@ function FlowCanvas({
2812
3093
  },
2813
3094
  [nodes, onNodesChange]
2814
3095
  );
2815
- const deleteNodeImpl = (0, import_react14.useCallback)(
3096
+ const deleteNodeImpl = (0, import_react15.useCallback)(
2816
3097
  (nodeId) => {
2817
3098
  const incidentEdgeIds = edgesRef.current.filter((e) => e.source === nodeId || e.target === nodeId).map((e) => e.id);
2818
3099
  if (incidentEdgeIds.length > 0) {
@@ -2822,7 +3103,7 @@ function FlowCanvas({
2822
3103
  },
2823
3104
  [onNodesChange, onEdgesChange]
2824
3105
  );
2825
- const instance = (0, import_react14.useMemo)(
3106
+ const instance = (0, import_react15.useMemo)(
2826
3107
  () => ({
2827
3108
  // viewport
2828
3109
  getViewport: () => viewportRef.current,
@@ -2963,13 +3244,29 @@ function FlowCanvas({
2963
3244
  }),
2964
3245
  [setViewport, minZoom, maxZoom]
2965
3246
  );
2966
- const initFiredRef = (0, import_react14.useRef)(false);
2967
- (0, import_react14.useEffect)(() => {
3247
+ const initFiredRef = (0, import_react15.useRef)(false);
3248
+ (0, import_react15.useEffect)(() => {
2968
3249
  if (initFiredRef.current) return;
2969
3250
  initFiredRef.current = true;
2970
3251
  onInit?.(instance);
2971
3252
  }, [instance, onInit]);
2972
- (0, import_react14.useEffect)(() => {
3253
+ const fitOnInitFiredRef = (0, import_react15.useRef)(false);
3254
+ (0, import_react15.useEffect)(() => {
3255
+ if (fitOnInitFiredRef.current) return;
3256
+ const opt = fitViewOnInit;
3257
+ const shouldFit = opt === false ? false : opt !== void 0 ? true : !viewportPropProvided;
3258
+ if (!shouldFit) return;
3259
+ if (nodes.length === 0) return;
3260
+ const rect = containerRef.current?.getBoundingClientRect();
3261
+ if (!rect || rect.width === 0 || rect.height === 0) return;
3262
+ fitOnInitFiredRef.current = true;
3263
+ const fitOpts = typeof opt === "object" && opt !== null ? opt : void 0;
3264
+ const raf = requestAnimationFrame(() => {
3265
+ void instance.fitView(fitOpts);
3266
+ });
3267
+ return () => cancelAnimationFrame(raf);
3268
+ }, [fitViewOnInit, viewportPropProvided, nodes.length, instance]);
3269
+ (0, import_react15.useEffect)(() => {
2973
3270
  const onKey = (e) => {
2974
3271
  if (e.key !== "Backspace" && e.key !== "Delete") return;
2975
3272
  const target = e.target;
@@ -2990,7 +3287,7 @@ function FlowCanvas({
2990
3287
  window.addEventListener("keydown", onKey);
2991
3288
  return () => window.removeEventListener("keydown", onKey);
2992
3289
  }, [instance, store]);
2993
- const bridge = (0, import_react14.useMemo)(
3290
+ const bridge = (0, import_react15.useMemo)(
2994
3291
  () => ({
2995
3292
  beginNodeDrag,
2996
3293
  selectNode,
@@ -3010,16 +3307,16 @@ function FlowCanvas({
3010
3307
  toggleNodeCollapseImpl
3011
3308
  ]
3012
3309
  );
3013
- const [panGesture, setPanGesture] = (0, import_react14.useState)(false);
3310
+ const [panGesture, setPanGesture] = (0, import_react15.useState)(false);
3014
3311
  const isEmpty = nodes.length === 0 && edges.length === 0;
3015
3312
  const isConnecting = conn !== null;
3016
- const visibleNodes = (0, import_react14.useMemo)(() => nodes.filter((n) => !n.hidden), [nodes]);
3017
- const visibleEdges = (0, import_react14.useMemo)(() => {
3313
+ const visibleNodes = (0, import_react15.useMemo)(() => nodes.filter((n) => !n.hidden), [nodes]);
3314
+ const visibleEdges = (0, import_react15.useMemo)(() => {
3018
3315
  if (visibleNodes.length === nodes.length) return edges;
3019
3316
  const visibleIds = new Set(visibleNodes.map((n) => n.id));
3020
3317
  return edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target));
3021
3318
  }, [edges, nodes, visibleNodes]);
3022
- const orderedNodes = (0, import_react14.useMemo)(() => {
3319
+ const orderedNodes = (0, import_react15.useMemo)(() => {
3023
3320
  const isContainer = (n) => n.type === "group" || n.type === "forEach";
3024
3321
  const depth = (n) => {
3025
3322
  let d = 0;
@@ -3038,7 +3335,7 @@ function FlowCanvas({
3038
3335
  containers.sort((a, b) => depth(a) - depth(b));
3039
3336
  return [...containers, ...others];
3040
3337
  }, [visibleNodes]);
3041
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FlowStoreContext.Provider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FlowInstanceContext.Provider, { value: instance, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HandleRegistryContext.Provider, { value: handleRegistry, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FlowDispatchContext.Provider, { value: dispatch, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FlowNodeBridgeContext.Provider, { value: bridge, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3338
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FlowStoreContext.Provider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FlowInstanceContext.Provider, { value: instance, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(HandleRegistryContext.Provider, { value: handleRegistry, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FlowDispatchContext.Provider, { value: dispatch, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FlowNodeBridgeContext.Provider, { value: bridge, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3042
3339
  "div",
3043
3340
  {
3044
3341
  ref: containerRef,
@@ -3083,7 +3380,7 @@ function FlowCanvas({
3083
3380
  },
3084
3381
  "data-empty": isEmpty ? "true" : void 0,
3085
3382
  children: [
3086
- background !== "none" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3383
+ background !== "none" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3087
3384
  "div",
3088
3385
  {
3089
3386
  className: cn(
@@ -3097,7 +3394,7 @@ function FlowCanvas({
3097
3394
  }
3098
3395
  }
3099
3396
  ),
3100
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3397
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3101
3398
  "div",
3102
3399
  {
3103
3400
  className: "ods-flow-canvas-v2__viewport",
@@ -3108,7 +3405,7 @@ function FlowCanvas({
3108
3405
  transformOrigin: "0 0"
3109
3406
  },
3110
3407
  children: [
3111
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3408
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3112
3409
  EdgesLayer,
3113
3410
  {
3114
3411
  edges: visibleEdges,
@@ -3123,7 +3420,7 @@ function FlowCanvas({
3123
3420
  orderedNodes.map((node) => {
3124
3421
  const Kind = kinds[node.type] ?? kinds.action;
3125
3422
  if (!Kind) return null;
3126
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3423
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3127
3424
  FlowNode,
3128
3425
  {
3129
3426
  node,
@@ -3138,7 +3435,7 @@ function FlowCanvas({
3138
3435
  ]
3139
3436
  }
3140
3437
  ),
3141
- isEmpty && emptyState && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ods-flow-canvas-v2__empty", children: emptyState }),
3438
+ isEmpty && emptyState && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ods-flow-canvas-v2__empty", children: emptyState }),
3142
3439
  children
3143
3440
  ]
3144
3441
  }
@@ -3147,7 +3444,69 @@ function FlowCanvas({
3147
3444
  function onEdgesChangeRef(id, cb) {
3148
3445
  cb?.([change.edge.remove(id)]);
3149
3446
  }
3150
- var EdgesLayer = (0, import_react14.memo)(function EdgesLayer2({
3447
+ var CONTAINER_DROP_HEADROOM_W = 220;
3448
+ var CONTAINER_DROP_HEADROOM_H = 2 * 128;
3449
+ function computeContainerAutoResize(nodes, pending, padding, minWidth, minHeight) {
3450
+ const projected = /* @__PURE__ */ new Map();
3451
+ for (const n of nodes) projected.set(n.id, n);
3452
+ for (const c of pending) {
3453
+ if (c.type === "position" && c.position) {
3454
+ const cur = projected.get(c.id);
3455
+ if (cur) projected.set(c.id, { ...cur, position: c.position });
3456
+ } else if (c.type === "replace" && c.item) {
3457
+ projected.set(c.id, { ...projected.get(c.id), ...c.item });
3458
+ } else if (c.type === "add" && c.item) {
3459
+ projected.set(c.item.id, c.item);
3460
+ }
3461
+ }
3462
+ const HEADER = 56;
3463
+ const out = [];
3464
+ for (const parent of projected.values()) {
3465
+ if (parent.type !== "group" && parent.type !== "forEach") continue;
3466
+ const children = [];
3467
+ for (const n of projected.values()) {
3468
+ if (n.parentId === parent.id) children.push(n);
3469
+ }
3470
+ if (children.length === 0) {
3471
+ const curW2 = parent.width ?? 480;
3472
+ const curH2 = parent.height ?? 240;
3473
+ if (curW2 !== minWidth || curH2 !== minHeight) {
3474
+ out.push(change.node.dimensions(parent.id, { width: minWidth, height: minHeight }));
3475
+ }
3476
+ continue;
3477
+ }
3478
+ let minX = Number.POSITIVE_INFINITY;
3479
+ let minY = Number.POSITIVE_INFINITY;
3480
+ let maxX = Number.NEGATIVE_INFINITY;
3481
+ let maxY = Number.NEGATIVE_INFINITY;
3482
+ for (const c of children) {
3483
+ const cw = c.width ?? 240;
3484
+ const ch = c.height ?? 96;
3485
+ if (c.position.x < minX) minX = c.position.x;
3486
+ if (c.position.y < minY) minY = c.position.y;
3487
+ if (c.position.x + cw > maxX) maxX = c.position.x + cw;
3488
+ if (c.position.y + ch > maxY) maxY = c.position.y + ch;
3489
+ }
3490
+ const targetX = minX - padding;
3491
+ const targetY = minY - padding - HEADER;
3492
+ const curW = parent.width ?? 480;
3493
+ const curH = parent.height ?? 240;
3494
+ const fitW = maxX - minX + padding * 2 + CONTAINER_DROP_HEADROOM_W;
3495
+ const fitH = maxY - minY + padding * 2 + HEADER + CONTAINER_DROP_HEADROOM_H;
3496
+ const nextW = Math.max(minWidth, fitW);
3497
+ const nextH = Math.max(minHeight, fitH);
3498
+ const positionDirty = parent.position.x !== targetX || parent.position.y !== targetY;
3499
+ const sizeDirty = curW !== nextW || curH !== nextH;
3500
+ if (positionDirty) {
3501
+ out.push(change.node.position(parent.id, { x: targetX, y: targetY }, false));
3502
+ }
3503
+ if (sizeDirty) {
3504
+ out.push(change.node.dimensions(parent.id, { width: nextW, height: nextH }));
3505
+ }
3506
+ }
3507
+ return out;
3508
+ }
3509
+ var EdgesLayer = (0, import_react15.memo)(function EdgesLayer2({
3151
3510
  edges,
3152
3511
  nodes,
3153
3512
  onSelect,
@@ -3156,7 +3515,7 @@ var EdgesLayer = (0, import_react14.memo)(function EdgesLayer2({
3156
3515
  ghost,
3157
3516
  handleVersion: _handleVersion
3158
3517
  }) {
3159
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3518
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3160
3519
  "svg",
3161
3520
  {
3162
3521
  className: "ods-flow-canvas-v2__edges",
@@ -3164,7 +3523,7 @@ var EdgesLayer = (0, import_react14.memo)(function EdgesLayer2({
3164
3523
  width: "100%",
3165
3524
  height: "100%",
3166
3525
  children: [
3167
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("g", { style: { pointerEvents: "auto" }, children: edges.map((edge) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3526
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("g", { style: { pointerEvents: "auto" }, children: edges.map((edge) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3168
3527
  FlowEdge,
3169
3528
  {
3170
3529
  edge,
@@ -3176,7 +3535,7 @@ var EdgesLayer = (0, import_react14.memo)(function EdgesLayer2({
3176
3535
  },
3177
3536
  edge.id
3178
3537
  )) }),
3179
- ghost && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3538
+ ghost && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3180
3539
  "path",
3181
3540
  {
3182
3541
  d: `M ${ghost.start.x} ${ghost.start.y} L ${ghost.end.x} ${ghost.end.y}`,
@@ -3191,151 +3550,6 @@ var EdgesLayer = (0, import_react14.memo)(function EdgesLayer2({
3191
3550
  );
3192
3551
  });
3193
3552
 
3194
- // src/workflow/components/NodeResizer/NodeResizer.tsx
3195
- var import_react15 = require("react");
3196
- var import_jsx_runtime8 = require("react/jsx-runtime");
3197
- function NodeResizer({
3198
- isVisible,
3199
- minWidth = 80,
3200
- minHeight = 60,
3201
- maxWidth,
3202
- maxHeight,
3203
- keepAspectRatio = false,
3204
- onResize,
3205
- onResizeEnd,
3206
- color
3207
- }) {
3208
- const { node, selected } = useFlowNodeContext();
3209
- const viewport = useViewport();
3210
- const flow = useFlow();
3211
- const dragRef = (0, import_react15.useRef)(null);
3212
- const show = isVisible ?? selected;
3213
- if (!show) return null;
3214
- const beginResize = (e, corner) => {
3215
- e.preventDefault();
3216
- e.stopPropagation();
3217
- e.target.setPointerCapture(e.pointerId);
3218
- const w = node.width ?? DEFAULT_NODE_WIDTH;
3219
- const h = node.height ?? DEFAULT_NODE_HEIGHT;
3220
- dragRef.current = {
3221
- pointerId: e.pointerId,
3222
- corner,
3223
- startClientX: e.clientX,
3224
- startClientY: e.clientY,
3225
- startWidth: w,
3226
- startHeight: h,
3227
- startX: node.position.x,
3228
- startY: node.position.y,
3229
- aspect: w / Math.max(1, h)
3230
- };
3231
- };
3232
- const onMove = (e) => {
3233
- const drag = dragRef.current;
3234
- if (!drag || drag.pointerId !== e.pointerId) return;
3235
- const dx = (e.clientX - drag.startClientX) / viewport.zoom;
3236
- const dy = (e.clientY - drag.startClientY) / viewport.zoom;
3237
- let nextW = drag.startWidth;
3238
- let nextH = drag.startHeight;
3239
- let nextX = drag.startX;
3240
- let nextY = drag.startY;
3241
- switch (drag.corner) {
3242
- case "se":
3243
- nextW = drag.startWidth + dx;
3244
- nextH = drag.startHeight + dy;
3245
- break;
3246
- case "sw":
3247
- nextW = drag.startWidth - dx;
3248
- nextH = drag.startHeight + dy;
3249
- nextX = drag.startX + dx;
3250
- break;
3251
- case "ne":
3252
- nextW = drag.startWidth + dx;
3253
- nextH = drag.startHeight - dy;
3254
- nextY = drag.startY + dy;
3255
- break;
3256
- case "nw":
3257
- nextW = drag.startWidth - dx;
3258
- nextH = drag.startHeight - dy;
3259
- nextX = drag.startX + dx;
3260
- nextY = drag.startY + dy;
3261
- break;
3262
- }
3263
- if (keepAspectRatio) {
3264
- nextH = nextW / drag.aspect;
3265
- if (drag.corner === "nw" || drag.corner === "ne") {
3266
- nextY = drag.startY + (drag.startHeight - nextH);
3267
- }
3268
- }
3269
- nextW = Math.max(minWidth, maxWidth ? Math.min(maxWidth, nextW) : nextW);
3270
- nextH = Math.max(minHeight, maxHeight ? Math.min(maxHeight, nextH) : nextH);
3271
- flow.updateNode(node.id, {
3272
- width: nextW,
3273
- height: nextH,
3274
- position: { x: nextX, y: nextY }
3275
- });
3276
- onResize?.({ width: nextW, height: nextH });
3277
- };
3278
- const onUp = (e) => {
3279
- if (dragRef.current?.pointerId === e.pointerId) {
3280
- const cur = flow.getNode(node.id);
3281
- if (cur) {
3282
- onResizeEnd?.({
3283
- width: cur.width ?? DEFAULT_NODE_WIDTH,
3284
- height: cur.height ?? DEFAULT_NODE_HEIGHT
3285
- });
3286
- }
3287
- dragRef.current = null;
3288
- }
3289
- };
3290
- const handleColor = color ?? "var(--ods-accent)";
3291
- const handleStyle = (corner) => {
3292
- const base = {
3293
- position: "absolute",
3294
- width: 12,
3295
- height: 12,
3296
- background: "var(--ods-surface-canvas)",
3297
- border: `2px solid ${handleColor}`,
3298
- borderRadius: 2,
3299
- cursor: cursorFor(corner),
3300
- touchAction: "none",
3301
- // Place each handle so its CENTRE sits on the corresponding corner.
3302
- transform: "translate(-50%, -50%)"
3303
- };
3304
- switch (corner) {
3305
- case "nw":
3306
- return { ...base, top: 0, left: 0 };
3307
- case "ne":
3308
- return { ...base, top: 0, left: "100%" };
3309
- case "sw":
3310
- return { ...base, top: "100%", left: 0 };
3311
- case "se":
3312
- return { ...base, top: "100%", left: "100%" };
3313
- }
3314
- };
3315
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("ods-node-resizer"), "data-flow-no-drag": "true", children: ["nw", "ne", "sw", "se"].map((corner) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3316
- "div",
3317
- {
3318
- style: handleStyle(corner),
3319
- onPointerDown: (e) => beginResize(e, corner),
3320
- onPointerMove: onMove,
3321
- onPointerUp: onUp,
3322
- onPointerCancel: onUp,
3323
- "aria-label": `Resize ${corner}`
3324
- },
3325
- corner
3326
- )) });
3327
- }
3328
- function cursorFor(corner) {
3329
- switch (corner) {
3330
- case "nw":
3331
- case "se":
3332
- return "nwse-resize";
3333
- case "ne":
3334
- case "sw":
3335
- return "nesw-resize";
3336
- }
3337
- }
3338
-
3339
3553
  // src/workflow/components/NodeToolbar/NodeToolbar.tsx
3340
3554
  var import_jsx_runtime9 = require("react/jsx-runtime");
3341
3555
  function NodeToolbar({
@@ -3564,6 +3778,7 @@ function toggleGroupCollapse(groupId, nodes) {
3564
3778
  useNodeData,
3565
3779
  useNodes,
3566
3780
  useSelection,
3567
- useViewport
3781
+ useViewport,
3782
+ useViewportOrNull
3568
3783
  });
3569
3784
  //# sourceMappingURL=workflow.cjs.map