@octaviaflow/core 3.0.18-beta.3 → 3.0.18-beta.30

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 (178) 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-2ZIOFEIS.js +3001 -0
  6. package/dist/chunk-2ZIOFEIS.js.map +1 -0
  7. package/dist/chunk-3DWB2PUF.js +2991 -0
  8. package/dist/chunk-3DWB2PUF.js.map +1 -0
  9. package/dist/chunk-4ZALUTZS.js +2936 -0
  10. package/dist/chunk-4ZALUTZS.js.map +1 -0
  11. package/dist/chunk-5ARKSRED.js +2951 -0
  12. package/dist/chunk-5ARKSRED.js.map +1 -0
  13. package/dist/chunk-5OSGSJMM.js +2981 -0
  14. package/dist/chunk-5OSGSJMM.js.map +1 -0
  15. package/dist/chunk-5YQQMEF3.js +2981 -0
  16. package/dist/chunk-5YQQMEF3.js.map +1 -0
  17. package/dist/chunk-6QCJK7H7.js +2991 -0
  18. package/dist/chunk-6QCJK7H7.js.map +1 -0
  19. package/dist/chunk-6QDYERZD.js +2944 -0
  20. package/dist/chunk-6QDYERZD.js.map +1 -0
  21. package/dist/chunk-76TP67ED.js +2984 -0
  22. package/dist/chunk-76TP67ED.js.map +1 -0
  23. package/dist/chunk-A6KMO4JV.js +2949 -0
  24. package/dist/chunk-A6KMO4JV.js.map +1 -0
  25. package/dist/chunk-B7FTWSTM.js +2938 -0
  26. package/dist/chunk-B7FTWSTM.js.map +1 -0
  27. package/dist/chunk-BCO6M26F.js +2940 -0
  28. package/dist/chunk-BCO6M26F.js.map +1 -0
  29. package/dist/chunk-C3UD2AZ5.js +2637 -0
  30. package/dist/chunk-C3UD2AZ5.js.map +1 -0
  31. package/dist/chunk-CEUP4NK2.js +2850 -0
  32. package/dist/chunk-CEUP4NK2.js.map +1 -0
  33. package/dist/chunk-DBNSBJO7.js +2993 -0
  34. package/dist/chunk-DBNSBJO7.js.map +1 -0
  35. package/dist/chunk-ECIHUVU7.js +2986 -0
  36. package/dist/chunk-ECIHUVU7.js.map +1 -0
  37. package/dist/chunk-EERNYLFL.js +2860 -0
  38. package/dist/chunk-EERNYLFL.js.map +1 -0
  39. package/dist/chunk-EKFDJX4G.js +2872 -0
  40. package/dist/chunk-EKFDJX4G.js.map +1 -0
  41. package/dist/chunk-GJA3GJUZ.js +2844 -0
  42. package/dist/chunk-GJA3GJUZ.js.map +1 -0
  43. package/dist/chunk-HDOTOZNA.js +2936 -0
  44. package/dist/chunk-HDOTOZNA.js.map +1 -0
  45. package/dist/chunk-IOKUV7FD.js +2658 -0
  46. package/dist/chunk-IOKUV7FD.js.map +1 -0
  47. package/dist/chunk-IUIICQU5.js +2946 -0
  48. package/dist/chunk-IUIICQU5.js.map +1 -0
  49. package/dist/chunk-J2UYZI6D.js +2946 -0
  50. package/dist/chunk-J2UYZI6D.js.map +1 -0
  51. package/dist/chunk-J7YASALS.js +2859 -0
  52. package/dist/chunk-J7YASALS.js.map +1 -0
  53. package/dist/chunk-JIEUYBQT.js +2658 -0
  54. package/dist/chunk-JIEUYBQT.js.map +1 -0
  55. package/dist/chunk-K2H7JLQW.js +2952 -0
  56. package/dist/chunk-K2H7JLQW.js.map +1 -0
  57. package/dist/chunk-KUXYBP66.js +2953 -0
  58. package/dist/chunk-KUXYBP66.js.map +1 -0
  59. package/dist/chunk-KYMYNYFV.js +2656 -0
  60. package/dist/chunk-KYMYNYFV.js.map +1 -0
  61. package/dist/chunk-MMXL343D.js +2974 -0
  62. package/dist/chunk-MMXL343D.js.map +1 -0
  63. package/dist/chunk-MXJL3EPE.js +2986 -0
  64. package/dist/chunk-MXJL3EPE.js.map +1 -0
  65. package/dist/chunk-MYZ25B2R.js +2995 -0
  66. package/dist/chunk-MYZ25B2R.js.map +1 -0
  67. package/dist/chunk-NTMEYB7B.js +2949 -0
  68. package/dist/chunk-NTMEYB7B.js.map +1 -0
  69. package/dist/chunk-PVJXX6GP.js +2640 -0
  70. package/dist/chunk-PVJXX6GP.js.map +1 -0
  71. package/dist/chunk-Q6ERDPQR.js +2981 -0
  72. package/dist/chunk-Q6ERDPQR.js.map +1 -0
  73. package/dist/chunk-S2SSBMWJ.js +2658 -0
  74. package/dist/chunk-S2SSBMWJ.js.map +1 -0
  75. package/dist/chunk-SLVDAZSX.js +2946 -0
  76. package/dist/chunk-SLVDAZSX.js.map +1 -0
  77. package/dist/chunk-UQBPYONV.js +2991 -0
  78. package/dist/chunk-UQBPYONV.js.map +1 -0
  79. package/dist/chunk-UXMNBS22.js +2955 -0
  80. package/dist/chunk-UXMNBS22.js.map +1 -0
  81. package/dist/chunk-WEGED7TA.js +2991 -0
  82. package/dist/chunk-WEGED7TA.js.map +1 -0
  83. package/dist/chunk-WEPTBLWX.js +2847 -0
  84. package/dist/chunk-WEPTBLWX.js.map +1 -0
  85. package/dist/chunk-WG4ZQMPS.js +2844 -0
  86. package/dist/chunk-WG4ZQMPS.js.map +1 -0
  87. package/dist/chunk-XEPEBHAW.js +2808 -0
  88. package/dist/chunk-XEPEBHAW.js.map +1 -0
  89. package/dist/chunk-XG2OYFX6.js +2925 -0
  90. package/dist/chunk-XG2OYFX6.js.map +1 -0
  91. package/dist/chunk-ZAMJEU42.js +2992 -0
  92. package/dist/chunk-ZAMJEU42.js.map +1 -0
  93. package/dist/chunk-ZRAM6FXB.js +2949 -0
  94. package/dist/chunk-ZRAM6FXB.js.map +1 -0
  95. package/dist/components/CsvViewer/CsvViewer.d.ts +51 -0
  96. package/dist/components/CsvViewer/CsvViewer.d.ts.map +1 -0
  97. package/dist/components/CsvViewer/index.d.ts +2 -0
  98. package/dist/components/CsvViewer/index.d.ts.map +1 -0
  99. package/dist/components/DataTable/DataTable.d.ts +19 -1
  100. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  101. package/dist/components/DropdownMenu/DropdownMenu.d.ts +12 -2
  102. package/dist/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  103. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts +8 -2
  104. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts.map +1 -1
  105. package/dist/components/FlowMinimap/FlowMinimap.d.ts +17 -1
  106. package/dist/components/FlowMinimap/FlowMinimap.d.ts.map +1 -1
  107. package/dist/components/FlowToolbar/FlowToolbar.d.ts +16 -10
  108. package/dist/components/FlowToolbar/FlowToolbar.d.ts.map +1 -1
  109. package/dist/components/JsonViewer/JsonViewer.d.ts +42 -7
  110. package/dist/components/JsonViewer/JsonViewer.d.ts.map +1 -1
  111. package/dist/components/JsonViewer/index.d.ts +1 -1
  112. package/dist/components/JsonViewer/index.d.ts.map +1 -1
  113. package/dist/components/Select/Select.d.ts.map +1 -1
  114. package/dist/components/WorkflowHeader/WorkflowHeader.d.ts +130 -0
  115. package/dist/components/WorkflowHeader/WorkflowHeader.d.ts.map +1 -0
  116. package/dist/components/WorkflowHeader/WorkflowHeaderExpanded.d.ts +69 -0
  117. package/dist/components/WorkflowHeader/WorkflowHeaderExpanded.d.ts.map +1 -0
  118. package/dist/components/WorkflowHeader/index.d.ts +3 -0
  119. package/dist/components/WorkflowHeader/index.d.ts.map +1 -0
  120. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCentered.d.ts +40 -0
  121. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCentered.d.ts.map +1 -0
  122. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCommand.d.ts +39 -0
  123. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCommand.d.ts.map +1 -0
  124. package/dist/components/WorkflowHeader/misc/WorkflowHeaderMinimal.d.ts +44 -0
  125. package/dist/components/WorkflowHeader/misc/WorkflowHeaderMinimal.d.ts.map +1 -0
  126. package/dist/components/WorkflowHeader/misc/WorkflowHeaderRail.d.ts +45 -0
  127. package/dist/components/WorkflowHeader/misc/WorkflowHeaderRail.d.ts.map +1 -0
  128. package/dist/components/WorkflowHeader/misc/WorkflowHeaderStudio.d.ts +48 -0
  129. package/dist/components/WorkflowHeader/misc/WorkflowHeaderStudio.d.ts.map +1 -0
  130. package/dist/components/WorkflowHeader/misc/WorkflowHeaderTiered.d.ts +52 -0
  131. package/dist/components/WorkflowHeader/misc/WorkflowHeaderTiered.d.ts.map +1 -0
  132. package/dist/components/XmlViewer/XmlViewer.d.ts +26 -1
  133. package/dist/components/XmlViewer/XmlViewer.d.ts.map +1 -1
  134. package/dist/components/XmlViewer/index.d.ts +1 -1
  135. package/dist/components/XmlViewer/index.d.ts.map +1 -1
  136. package/dist/components/YamlViewer/YamlViewer.d.ts +26 -1
  137. package/dist/components/YamlViewer/YamlViewer.d.ts.map +1 -1
  138. package/dist/components/YamlViewer/index.d.ts +1 -1
  139. package/dist/components/YamlViewer/index.d.ts.map +1 -1
  140. package/dist/hooks/useRelativeTime.d.ts +28 -0
  141. package/dist/hooks/useRelativeTime.d.ts.map +1 -0
  142. package/dist/hooks/useWorkflowRuntime.d.ts +20 -0
  143. package/dist/hooks/useWorkflowRuntime.d.ts.map +1 -0
  144. package/dist/index.cjs +4884 -3581
  145. package/dist/index.cjs.map +1 -1
  146. package/dist/index.d.ts +7 -3
  147. package/dist/index.d.ts.map +1 -1
  148. package/dist/index.js +4505 -3515
  149. package/dist/index.js.map +1 -1
  150. package/dist/styles.css +1 -1
  151. package/dist/workflow/components/ConfigPanel/ConfigPanel.d.ts +27 -9
  152. package/dist/workflow/components/ConfigPanel/ConfigPanel.d.ts.map +1 -1
  153. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts +49 -1
  154. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts.map +1 -1
  155. package/dist/workflow/components/FlowEdge/FlowEdge.d.ts.map +1 -1
  156. package/dist/workflow/components/FxPanel/DataRefButton.d.ts +9 -0
  157. package/dist/workflow/components/FxPanel/DataRefButton.d.ts.map +1 -0
  158. package/dist/workflow/components/FxPanel/FxPanel.d.ts +74 -0
  159. package/dist/workflow/components/FxPanel/FxPanel.d.ts.map +1 -0
  160. package/dist/workflow/components/FxPanel/FxToggleButton.d.ts +9 -0
  161. package/dist/workflow/components/FxPanel/FxToggleButton.d.ts.map +1 -0
  162. package/dist/workflow/components/Handle/Handle.d.ts +9 -1
  163. package/dist/workflow/components/Handle/Handle.d.ts.map +1 -1
  164. package/dist/workflow/components/Handle/handleRegistry.d.ts +19 -0
  165. package/dist/workflow/components/Handle/handleRegistry.d.ts.map +1 -1
  166. package/dist/workflow/components/kinds/index.d.ts +4 -0
  167. package/dist/workflow/components/kinds/index.d.ts.map +1 -1
  168. package/dist/workflow/index.d.ts +3 -1
  169. package/dist/workflow/index.d.ts.map +1 -1
  170. package/dist/workflow/store/selectors.d.ts +12 -0
  171. package/dist/workflow/store/selectors.d.ts.map +1 -1
  172. package/dist/workflow/utils/parenting.d.ts +5 -3
  173. package/dist/workflow/utils/parenting.d.ts.map +1 -1
  174. package/dist/workflow.cjs +1108 -471
  175. package/dist/workflow.cjs.map +1 -1
  176. package/dist/workflow.js +535 -250
  177. package/dist/workflow.js.map +1 -1
  178. package/package.json +8 -3
package/dist/workflow.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  GroupNode,
13
13
  Handle,
14
14
  HttpRequestNode,
15
+ NodeResizer,
15
16
  OutputNode,
16
17
  ParallelNode,
17
18
  StickyNode,
@@ -35,10 +36,21 @@ import {
35
36
  smoothStepPath,
36
37
  stepPath,
37
38
  straightPath,
39
+ useConnection,
40
+ useEdgeById,
41
+ useEdges,
38
42
  useFlow,
39
43
  useFlowNodeContext,
40
- useFlowStore
41
- } from "./chunk-2RD5OERK.js";
44
+ useFlowSelector,
45
+ useIsEdgeSelected,
46
+ useIsNodeSelected,
47
+ useNodeById,
48
+ useNodeData,
49
+ useNodes,
50
+ useSelection,
51
+ useViewport,
52
+ useViewportOrNull
53
+ } from "./chunk-6QDYERZD.js";
42
54
  import {
43
55
  cn
44
56
  } from "./chunk-ZAUUGK2Y.js";
@@ -339,60 +351,6 @@ function createElkEngine(elk, defaults = {}) {
339
351
  };
340
352
  }
341
353
 
342
- // src/workflow/store/selectors.ts
343
- import { useMemo as useMemo2, useSyncExternalStore } from "react";
344
- function useFlowSelector(selector, isEqual = Object.is) {
345
- void isEqual;
346
- const store = useFlowStore();
347
- return useSyncExternalStore(
348
- store.subscribe,
349
- () => selector(store.getSnapshot()),
350
- () => selector(store.getSnapshot())
351
- );
352
- }
353
- function useNodes() {
354
- return useFlowSelector((s) => s.nodes);
355
- }
356
- function useEdges() {
357
- return useFlowSelector((s) => s.edges);
358
- }
359
- function useViewport() {
360
- return useFlowSelector((s) => s.viewport);
361
- }
362
- function useNodeById(id) {
363
- return useFlowSelector((s) => s.nodes.find((n) => n.id === id));
364
- }
365
- function useNodeData(id) {
366
- return useFlowSelector(
367
- (s) => s.nodes.find((n) => n.id === id)?.data ?? void 0
368
- );
369
- }
370
- function useEdgeById(id) {
371
- return useFlowSelector((s) => s.edges.find((e) => e.id === id));
372
- }
373
- function useIsNodeSelected(id) {
374
- return useFlowSelector((s) => s.selectedNodeIds.has(id));
375
- }
376
- function useIsEdgeSelected(id) {
377
- return useFlowSelector((s) => s.selectedEdgeIds.has(id));
378
- }
379
- function useConnection() {
380
- return useFlowSelector((s) => s.connection);
381
- }
382
- function useSelection() {
383
- const nodes = useNodes();
384
- const edges = useEdges();
385
- const selectedNodeIds = useFlowSelector((s) => s.selectedNodeIds);
386
- const selectedEdgeIds = useFlowSelector((s) => s.selectedEdgeIds);
387
- return useMemo2(
388
- () => ({
389
- nodes: nodes.filter((n) => selectedNodeIds.has(n.id)),
390
- edges: edges.filter((e) => selectedEdgeIds.has(e.id))
391
- }),
392
- [nodes, edges, selectedNodeIds, selectedEdgeIds]
393
- );
394
- }
395
-
396
354
  // src/workflow/components/ConfigPanel/ConfigPanel.tsx
397
355
  import {
398
356
  useCallback as useCallback3,
@@ -400,7 +358,7 @@ import {
400
358
  useRef as useRef3,
401
359
  useState as useState3
402
360
  } from "react";
403
- import { jsx, jsxs } from "react/jsx-runtime";
361
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
404
362
  var SAVE_STATE_LABEL = {
405
363
  clean: "Saved",
406
364
  dirty: "Unsaved changes",
@@ -418,26 +376,27 @@ var SAVE_STATE_DOT = {
418
376
  function ConfigPanel({
419
377
  open = true,
420
378
  title,
421
- kindLabel,
422
379
  icon,
380
+ headerActions,
423
381
  banner,
424
382
  tabs,
425
383
  activeTab: controlledActive,
426
384
  defaultActiveTab,
427
385
  onTabChange,
428
- saveState = "clean",
386
+ saveState,
429
387
  onTitleChange,
430
388
  onClose,
431
389
  onSave,
432
390
  onCancel,
391
+ padding = 12,
433
392
  resizable = true,
434
- defaultWidth = 360,
435
- minWidth = 280,
393
+ defaultWidth = 400,
394
+ minWidth = 400,
436
395
  maxWidth = 720,
437
396
  maxWidthContainerInset = 80,
438
397
  variant = "pinned",
439
398
  children,
440
- footer,
399
+ footerActions,
441
400
  className,
442
401
  style
443
402
  }) {
@@ -534,55 +493,53 @@ function ConfigPanel({
534
493
  "aria-hidden": "true"
535
494
  }
536
495
  ),
537
- /* @__PURE__ */ jsxs("header", { className: "ods-flow-config-panel__header", children: [
538
- kindLabel && /* @__PURE__ */ jsx("span", { className: "ods-flow-config-panel__breadcrumb", children: kindLabel }),
539
- /* @__PURE__ */ jsxs("div", { className: "ods-flow-config-panel__title-row", children: [
540
- icon && /* @__PURE__ */ jsx("span", { className: "ods-flow-config-panel__icon", children: icon }),
541
- editingTitle ? /* @__PURE__ */ jsx(
542
- "input",
543
- {
544
- className: "ods-flow-config-panel__title-input",
545
- value: draftTitle,
546
- autoFocus: true,
547
- onChange: (e) => setDraftTitle(e.target.value),
548
- onBlur: () => commitTitle(draftTitle),
549
- onKeyDown: titleKeyDown,
550
- "aria-label": "Edit title"
551
- }
552
- ) : /* @__PURE__ */ jsx(
553
- "button",
554
- {
555
- type: "button",
556
- className: "ods-flow-config-panel__title",
557
- onDoubleClick: () => {
558
- if (!onTitleChange) return;
559
- setDraftTitle(title ?? "");
560
- setEditingTitle(true);
561
- },
562
- title: onTitleChange ? "Double-click to rename" : void 0,
563
- children: title ?? "Untitled"
564
- }
565
- ),
566
- onClose && /* @__PURE__ */ jsx(
567
- "button",
568
- {
569
- type: "button",
570
- className: "ods-flow-config-panel__close",
571
- onClick: onClose,
572
- "aria-label": "Close panel",
573
- children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
574
- "path",
575
- {
576
- d: "M3 3l8 8M11 3l-8 8",
577
- stroke: "currentColor",
578
- strokeWidth: "1.5",
579
- strokeLinecap: "round"
580
- }
581
- ) })
582
- }
583
- )
584
- ] })
585
- ] }),
496
+ /* @__PURE__ */ jsx("header", { className: "ods-flow-config-panel__header", children: /* @__PURE__ */ jsxs("div", { className: "ods-flow-config-panel__title-row", children: [
497
+ icon && /* @__PURE__ */ jsx("span", { className: "ods-flow-config-panel__icon", children: icon }),
498
+ editingTitle ? /* @__PURE__ */ jsx(
499
+ "input",
500
+ {
501
+ className: "ods-flow-config-panel__title-input",
502
+ value: draftTitle,
503
+ autoFocus: true,
504
+ onChange: (e) => setDraftTitle(e.target.value),
505
+ onBlur: () => commitTitle(draftTitle),
506
+ onKeyDown: titleKeyDown,
507
+ "aria-label": "Edit title"
508
+ }
509
+ ) : /* @__PURE__ */ jsx(
510
+ "button",
511
+ {
512
+ type: "button",
513
+ className: "ods-flow-config-panel__title",
514
+ onDoubleClick: () => {
515
+ if (!onTitleChange) return;
516
+ setDraftTitle(title ?? "");
517
+ setEditingTitle(true);
518
+ },
519
+ title: onTitleChange ? "Double-click to rename" : void 0,
520
+ children: title ?? "Untitled"
521
+ }
522
+ ),
523
+ headerActions && /* @__PURE__ */ jsx("div", { className: "ods-flow-config-panel__header-actions", children: headerActions }),
524
+ onClose && /* @__PURE__ */ jsx(
525
+ "button",
526
+ {
527
+ type: "button",
528
+ className: "ods-flow-config-panel__close",
529
+ onClick: onClose,
530
+ "aria-label": "Close panel",
531
+ children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
532
+ "path",
533
+ {
534
+ d: "M3 3l8 8M11 3l-8 8",
535
+ stroke: "currentColor",
536
+ strokeWidth: "1.5",
537
+ strokeLinecap: "round"
538
+ }
539
+ ) })
540
+ }
541
+ )
542
+ ] }) }),
586
543
  tabs && tabs.length > 1 && /* @__PURE__ */ jsx("nav", { className: "ods-flow-config-panel__tabs", role: "tablist", children: tabs.map((t) => /* @__PURE__ */ jsxs(
587
544
  "button",
588
545
  {
@@ -603,9 +560,17 @@ function ConfigPanel({
603
560
  t.id
604
561
  )) }),
605
562
  banner && /* @__PURE__ */ jsx("div", { className: "ods-flow-config-panel__banner", children: banner }),
606
- /* @__PURE__ */ jsx("div", { className: "ods-flow-config-panel__body", role: "tabpanel", children: tabs ? activeTab?.content : children }),
563
+ /* @__PURE__ */ jsx(
564
+ "div",
565
+ {
566
+ className: "ods-flow-config-panel__body",
567
+ role: "tabpanel",
568
+ style: { padding },
569
+ children: tabs ? activeTab?.content : children
570
+ }
571
+ ),
607
572
  /* @__PURE__ */ jsxs("footer", { className: "ods-flow-config-panel__footer", children: [
608
- /* @__PURE__ */ jsxs(
573
+ saveState && /* @__PURE__ */ jsxs(
609
574
  "span",
610
575
  {
611
576
  className: cn(
@@ -625,7 +590,7 @@ function ConfigPanel({
625
590
  ]
626
591
  }
627
592
  ),
628
- footer ?? /* @__PURE__ */ jsxs("div", { className: "ods-flow-config-panel__footer-actions", children: [
593
+ /* @__PURE__ */ jsx("div", { className: "ods-flow-config-panel__footer-actions", children: footerActions ?? /* @__PURE__ */ jsxs(Fragment, { children: [
629
594
  onCancel && /* @__PURE__ */ jsx(
630
595
  "button",
631
596
  {
@@ -641,164 +606,481 @@ function ConfigPanel({
641
606
  type: "button",
642
607
  className: "ods-flow-config-panel__btn ods-flow-config-panel__btn--primary",
643
608
  onClick: onSave,
644
- disabled: saveState === "saving" || saveState === "clean",
609
+ disabled: saveState === "saving",
645
610
  children: saveState === "saving" ? "Saving\u2026" : "Save"
646
611
  }
647
612
  )
648
- ] })
613
+ ] }) })
649
614
  ] })
650
615
  ]
651
616
  }
652
617
  );
653
618
  }
654
619
 
655
- // src/workflow/components/NodeResizer/NodeResizer.tsx
656
- import { useRef as useRef4 } from "react";
657
- import { jsx as jsx2 } from "react/jsx-runtime";
658
- function NodeResizer({
659
- isVisible,
660
- minWidth = 80,
661
- minHeight = 60,
662
- maxWidth,
663
- maxHeight,
664
- keepAspectRatio = false,
665
- onResize,
666
- onResizeEnd,
667
- color
620
+ // src/workflow/components/FxPanel/FxPanel.tsx
621
+ import {
622
+ useMemo as useMemo2,
623
+ useRef as useRef4,
624
+ useState as useState4
625
+ } from "react";
626
+ import {
627
+ ChevronDownIcon,
628
+ ChevronRightIcon,
629
+ CloseIcon,
630
+ CollapseAllIcon,
631
+ DraggableIcon,
632
+ ExpandAllIcon,
633
+ FunctionMathIcon,
634
+ SearchIcon,
635
+ ValueVariableIcon
636
+ } from "@octaviaflow/icons";
637
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
638
+ var KIND_ICON = {
639
+ function: FunctionMathIcon,
640
+ variable: ValueVariableIcon
641
+ };
642
+ function countLeaves(items) {
643
+ let n = 0;
644
+ for (const it of items) {
645
+ if (it.children && it.children.length > 0) n += countLeaves(it.children);
646
+ else n += 1;
647
+ }
648
+ return n;
649
+ }
650
+ function collectBranchIds(items, out) {
651
+ for (const it of items) {
652
+ if (it.children && it.children.length > 0) {
653
+ out.add(it.id);
654
+ collectBranchIds(it.children, out);
655
+ }
656
+ }
657
+ }
658
+ function flattenTree(items, depth, expandedItems, out) {
659
+ for (const it of items) {
660
+ const hasChildren = !!it.children && it.children.length > 0;
661
+ const expanded = hasChildren && expandedItems.has(it.id);
662
+ out.push({ item: it, depth, hasChildren, expanded });
663
+ if (expanded) flattenTree(it.children, depth + 1, expandedItems, out);
664
+ }
665
+ }
666
+ function collectHits(items, ancestors, q, out) {
667
+ for (const it of items) {
668
+ if (it.children && it.children.length > 0) {
669
+ collectHits(it.children, [...ancestors, it.label], q, out);
670
+ } else {
671
+ const path = [...ancestors, it.label].join(" / ");
672
+ const hay = `${it.label} ${it.description ?? ""} ${path} ${it.insertValue ?? ""}`.toLowerCase();
673
+ if (hay.includes(q)) out.push({ item: it, ancestors });
674
+ }
675
+ }
676
+ }
677
+ function FxPanel({
678
+ categories,
679
+ title = "Data References",
680
+ hint = "Drag onto a field, or click an item to insert it.",
681
+ search: controlledSearch,
682
+ defaultSearch = "",
683
+ onSearchChange,
684
+ expandedCategory: controlledExpanded,
685
+ defaultExpandedCategory,
686
+ onExpandedCategoryChange,
687
+ onClose,
688
+ onItemDragStart,
689
+ onItemSelect,
690
+ width = 300,
691
+ emptyLabel = "No matches",
692
+ searchPlaceholder = "Search fields, functions & variables\u2026",
693
+ className,
694
+ style
668
695
  }) {
669
- const { node, selected } = useFlowNodeContext();
670
- const viewport = useViewport();
671
- const flow = useFlow();
672
- const dragRef = useRef4(null);
673
- const show = isVisible ?? selected;
674
- if (!show) return null;
675
- const beginResize = (e, corner) => {
676
- e.preventDefault();
677
- e.stopPropagation();
678
- e.target.setPointerCapture(e.pointerId);
679
- const w = node.width ?? DEFAULT_NODE_WIDTH;
680
- const h = node.height ?? DEFAULT_NODE_HEIGHT;
681
- dragRef.current = {
682
- pointerId: e.pointerId,
683
- corner,
684
- startClientX: e.clientX,
685
- startClientY: e.clientY,
686
- startWidth: w,
687
- startHeight: h,
688
- startX: node.position.x,
689
- startY: node.position.y,
690
- aspect: w / Math.max(1, h)
691
- };
696
+ const [internalSearch, setInternalSearch] = useState4(defaultSearch);
697
+ const search = controlledSearch ?? internalSearch;
698
+ const query = search.trim().toLowerCase();
699
+ const setSearch = (next) => {
700
+ if (controlledSearch === void 0) setInternalSearch(next);
701
+ onSearchChange?.(next);
692
702
  };
693
- const onMove = (e) => {
694
- const drag = dragRef.current;
695
- if (!drag || drag.pointerId !== e.pointerId) return;
696
- const dx = (e.clientX - drag.startClientX) / viewport.zoom;
697
- const dy = (e.clientY - drag.startClientY) / viewport.zoom;
698
- let nextW = drag.startWidth;
699
- let nextH = drag.startHeight;
700
- let nextX = drag.startX;
701
- let nextY = drag.startY;
702
- switch (drag.corner) {
703
- case "se":
704
- nextW = drag.startWidth + dx;
705
- nextH = drag.startHeight + dy;
706
- break;
707
- case "sw":
708
- nextW = drag.startWidth - dx;
709
- nextH = drag.startHeight + dy;
710
- nextX = drag.startX + dx;
711
- break;
712
- case "ne":
713
- nextW = drag.startWidth + dx;
714
- nextH = drag.startHeight - dy;
715
- nextY = drag.startY + dy;
716
- break;
717
- case "nw":
718
- nextW = drag.startWidth - dx;
719
- nextH = drag.startHeight - dy;
720
- nextX = drag.startX + dx;
721
- nextY = drag.startY + dy;
722
- break;
723
- }
724
- if (keepAspectRatio) {
725
- nextH = nextW / drag.aspect;
726
- if (drag.corner === "nw" || drag.corner === "ne") {
727
- nextY = drag.startY + (drag.startHeight - nextH);
703
+ const visibleCategories = useMemo2(
704
+ () => categories.filter((c) => c.items.length > 0),
705
+ [categories]
706
+ );
707
+ const [internalCat, setInternalCat] = useState4(
708
+ defaultExpandedCategory !== void 0 ? defaultExpandedCategory : visibleCategories[0]?.id ?? null
709
+ );
710
+ const openCategoryId = controlledExpanded ?? internalCat;
711
+ const setOpenCategory = (id) => {
712
+ if (controlledExpanded === void 0) setInternalCat(id);
713
+ onExpandedCategoryChange?.(id);
714
+ };
715
+ const [expandedItems, setExpandedItems] = useState4(() => {
716
+ const ids = /* @__PURE__ */ new Set();
717
+ for (const cat of categories) {
718
+ for (const item of cat.items) {
719
+ if (item.children && item.children.length > 0) ids.add(item.id);
728
720
  }
729
721
  }
730
- nextW = Math.max(minWidth, maxWidth ? Math.min(maxWidth, nextW) : nextW);
731
- nextH = Math.max(minHeight, maxHeight ? Math.min(maxHeight, nextH) : nextH);
732
- flow.updateNode(node.id, {
733
- width: nextW,
734
- height: nextH,
735
- position: { x: nextX, y: nextY }
722
+ return ids;
723
+ });
724
+ const toggleItem = (id) => {
725
+ setExpandedItems((prev) => {
726
+ const next = new Set(prev);
727
+ if (next.has(id)) next.delete(id);
728
+ else next.add(id);
729
+ return next;
736
730
  });
737
- onResize?.({ width: nextW, height: nextH });
738
731
  };
739
- const onUp = (e) => {
740
- if (dragRef.current?.pointerId === e.pointerId) {
741
- const cur = flow.getNode(node.id);
742
- if (cur) {
743
- onResizeEnd?.({
744
- width: cur.width ?? DEFAULT_NODE_WIDTH,
745
- height: cur.height ?? DEFAULT_NODE_HEIGHT
746
- });
732
+ const setCategoryExpansion = (cat, expand) => {
733
+ const branchIds = /* @__PURE__ */ new Set();
734
+ collectBranchIds(cat.items, branchIds);
735
+ setExpandedItems((prev) => {
736
+ const next = new Set(prev);
737
+ for (const id of branchIds) {
738
+ if (expand) next.add(id);
739
+ else next.delete(id);
747
740
  }
748
- dragRef.current = null;
741
+ return next;
742
+ });
743
+ };
744
+ const [draggingId, setDraggingId] = useState4(null);
745
+ const [focusedId, setFocusedId] = useState4(null);
746
+ const hits = useMemo2(() => {
747
+ if (!query) return null;
748
+ const all = [];
749
+ for (const cat of visibleCategories) {
750
+ const out = [];
751
+ collectHits(cat.items, [], query, out);
752
+ for (const hit of out) all.push({ category: cat, hit });
753
+ }
754
+ return all;
755
+ }, [query, visibleCategories]);
756
+ const handleDragStart = (item, category) => (e) => {
757
+ setDraggingId(item.id);
758
+ if (onItemDragStart) {
759
+ onItemDragStart(item, category, e);
760
+ } else if (item.insertValue) {
761
+ e.dataTransfer.setData("text/plain", item.insertValue);
762
+ e.dataTransfer.setData("application/x-fx-insert", item.insertValue);
763
+ e.dataTransfer.setData(
764
+ "application/x-fx-type",
765
+ category.kind ?? "function"
766
+ );
767
+ e.dataTransfer.effectAllowed = "copy";
749
768
  }
750
769
  };
751
- const handleColor = color ?? "var(--ods-accent)";
752
- const handleStyle = (corner) => {
753
- const base = {
754
- position: "absolute",
755
- width: 12,
756
- height: 12,
757
- background: "var(--ods-surface-canvas)",
758
- border: `2px solid ${handleColor}`,
759
- borderRadius: 2,
760
- cursor: cursorFor(corner),
761
- touchAction: "none",
762
- // Place each handle so its CENTRE sits on the corresponding corner.
763
- transform: "translate(-50%, -50%)"
764
- };
765
- switch (corner) {
766
- case "nw":
767
- return { ...base, top: 0, left: 0 };
768
- case "ne":
769
- return { ...base, top: 0, left: "100%" };
770
- case "sw":
771
- return { ...base, top: "100%", left: 0 };
772
- case "se":
773
- return { ...base, top: "100%", left: "100%" };
770
+ const listRef = useRef4(null);
771
+ const focusRow = (id) => {
772
+ setFocusedId(id);
773
+ requestAnimationFrame(() => {
774
+ listRef.current?.querySelector(`[data-fx-row="${CSS.escape(id)}"]`)?.focus();
775
+ });
776
+ };
777
+ const onRowKeyDown = (e, rows, row, category) => {
778
+ const idx = rows.findIndex((r) => r.item.id === row.item.id);
779
+ if (idx < 0) return;
780
+ switch (e.key) {
781
+ case "ArrowDown":
782
+ e.preventDefault();
783
+ if (idx < rows.length - 1) focusRow(rows[idx + 1].item.id);
784
+ break;
785
+ case "ArrowUp":
786
+ e.preventDefault();
787
+ if (idx > 0) focusRow(rows[idx - 1].item.id);
788
+ break;
789
+ case "ArrowRight":
790
+ if (row.hasChildren) {
791
+ e.preventDefault();
792
+ if (!row.expanded) toggleItem(row.item.id);
793
+ else if (idx < rows.length - 1) focusRow(rows[idx + 1].item.id);
794
+ }
795
+ break;
796
+ case "ArrowLeft":
797
+ if (row.hasChildren && row.expanded) {
798
+ e.preventDefault();
799
+ toggleItem(row.item.id);
800
+ } else {
801
+ for (let i = idx - 1; i >= 0; i--) {
802
+ if (rows[i].depth < row.depth) {
803
+ e.preventDefault();
804
+ focusRow(rows[i].item.id);
805
+ break;
806
+ }
807
+ }
808
+ }
809
+ break;
810
+ case "Home":
811
+ e.preventDefault();
812
+ if (rows.length) focusRow(rows[0].item.id);
813
+ break;
814
+ case "End":
815
+ e.preventDefault();
816
+ if (rows.length) focusRow(rows[rows.length - 1].item.id);
817
+ break;
818
+ case "Enter":
819
+ case " ":
820
+ e.preventDefault();
821
+ if (row.hasChildren) toggleItem(row.item.id);
822
+ else onItemSelect?.(row.item, category);
823
+ break;
824
+ default:
825
+ break;
774
826
  }
775
827
  };
776
- return /* @__PURE__ */ jsx2("div", { className: cn("ods-node-resizer"), "data-flow-no-drag": "true", children: ["nw", "ne", "sw", "se"].map((corner) => /* @__PURE__ */ jsx2(
777
- "div",
828
+ const searchRows = useMemo2(
829
+ () => hits ? hits.map(({ hit }) => ({
830
+ item: hit.item,
831
+ depth: 0,
832
+ hasChildren: false,
833
+ expanded: false
834
+ })) : [],
835
+ [hits]
836
+ );
837
+ const renderRow = (row, category, rows, crumb) => {
838
+ const { item, depth, hasChildren, expanded } = row;
839
+ const mono = category.kind === "function";
840
+ const draggable = !!item.insertValue;
841
+ const isFocused = focusedId === item.id;
842
+ return /* @__PURE__ */ jsxs2(
843
+ "div",
844
+ {
845
+ "data-fx-row": item.id,
846
+ className: cn(
847
+ "ods-flow-fx-panel__row",
848
+ hasChildren ? "ods-flow-fx-panel__row--branch" : "ods-flow-fx-panel__row--leaf",
849
+ draggingId === item.id && "ods-flow-fx-panel__row--dragging",
850
+ isFocused && "ods-flow-fx-panel__row--focused"
851
+ ),
852
+ role: "treeitem",
853
+ "aria-expanded": hasChildren ? expanded : void 0,
854
+ "aria-level": depth + 1,
855
+ tabIndex: isFocused || focusedId === null && rows[0]?.item.id === item.id ? 0 : -1,
856
+ draggable,
857
+ onDragStart: draggable ? handleDragStart(item, category) : void 0,
858
+ onDragEnd: () => setDraggingId(null),
859
+ onFocus: () => setFocusedId(item.id),
860
+ onKeyDown: (e) => onRowKeyDown(e, rows, row, category),
861
+ onClick: () => {
862
+ if (hasChildren) toggleItem(item.id);
863
+ else onItemSelect?.(item, category);
864
+ },
865
+ title: item.insertValue,
866
+ children: [
867
+ Array.from({ length: depth }, (_, i) => /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__indent", "aria-hidden": "true" }, i)),
868
+ hasChildren ? /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__twisty", "aria-hidden": "true", children: expanded ? /* @__PURE__ */ jsx2(ChevronDownIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(ChevronRightIcon, { size: "sm" }) }) : /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__grip", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(DraggableIcon, { size: "sm" }) }),
869
+ /* @__PURE__ */ jsxs2("span", { className: "ods-flow-fx-panel__row-main", children: [
870
+ /* @__PURE__ */ jsxs2("span", { className: "ods-flow-fx-panel__row-line", children: [
871
+ mono ? /* @__PURE__ */ jsx2("code", { className: "ods-flow-fx-panel__row-label ods-flow-fx-panel__row-label--mono", children: item.label }) : /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__row-label", children: item.label }),
872
+ item.valueType && /* @__PURE__ */ jsx2(
873
+ "span",
874
+ {
875
+ className: cn(
876
+ "ods-flow-fx-panel__type",
877
+ `ods-flow-fx-panel__type--${item.valueType}`
878
+ ),
879
+ children: item.valueType
880
+ }
881
+ )
882
+ ] }),
883
+ (item.description || crumb) && /* @__PURE__ */ jsxs2("span", { className: "ods-flow-fx-panel__row-sub", children: [
884
+ crumb && /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__crumb", children: crumb }),
885
+ item.description
886
+ ] })
887
+ ] })
888
+ ]
889
+ },
890
+ item.id
891
+ );
892
+ };
893
+ return /* @__PURE__ */ jsxs2(
894
+ "aside",
778
895
  {
779
- style: handleStyle(corner),
780
- onPointerDown: (e) => beginResize(e, corner),
781
- onPointerMove: onMove,
782
- onPointerUp: onUp,
783
- onPointerCancel: onUp,
784
- "aria-label": `Resize ${corner}`
785
- },
786
- corner
787
- )) });
896
+ className: cn("ods-flow-fx-panel", className),
897
+ style: { width, ...style },
898
+ "aria-label": typeof title === "string" ? title : "Data References",
899
+ children: [
900
+ /* @__PURE__ */ jsxs2("header", { className: "ods-flow-fx-panel__header", children: [
901
+ /* @__PURE__ */ jsx2("h3", { className: "ods-flow-fx-panel__title", children: title }),
902
+ onClose && /* @__PURE__ */ jsx2(
903
+ "button",
904
+ {
905
+ type: "button",
906
+ className: "ods-flow-fx-panel__close",
907
+ onClick: onClose,
908
+ "aria-label": "Close data references",
909
+ children: /* @__PURE__ */ jsx2(CloseIcon, { size: "sm" })
910
+ }
911
+ )
912
+ ] }),
913
+ /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__search", children: [
914
+ /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(SearchIcon, { size: "sm" }) }),
915
+ /* @__PURE__ */ jsx2(
916
+ "input",
917
+ {
918
+ type: "text",
919
+ className: "ods-flow-fx-panel__search-input",
920
+ placeholder: searchPlaceholder,
921
+ "aria-label": "Search fields, functions and variables",
922
+ value: search,
923
+ onChange: (e) => setSearch(e.target.value)
924
+ }
925
+ ),
926
+ search && /* @__PURE__ */ jsx2(
927
+ "button",
928
+ {
929
+ type: "button",
930
+ className: "ods-flow-fx-panel__search-clear",
931
+ onClick: () => setSearch(""),
932
+ "aria-label": "Clear search",
933
+ children: /* @__PURE__ */ jsx2(CloseIcon, { size: "sm" })
934
+ }
935
+ )
936
+ ] }),
937
+ hint && !query && /* @__PURE__ */ jsx2("p", { className: "ods-flow-fx-panel__hint", children: hint }),
938
+ /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__list", ref: listRef, role: "tree", children: [
939
+ query && hits && (hits.length > 0 ? /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__results", children: [
940
+ /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__results-count", children: [
941
+ hits.length,
942
+ " ",
943
+ hits.length === 1 ? "match" : "matches"
944
+ ] }),
945
+ hits.map(
946
+ ({ category, hit }, i) => renderRow(
947
+ searchRows[i],
948
+ category,
949
+ searchRows,
950
+ hit.ancestors.length ? hit.ancestors.join(" / ") : category.label
951
+ )
952
+ )
953
+ ] }) : /* @__PURE__ */ jsx2("div", { className: "ods-flow-fx-panel__empty", children: emptyLabel })),
954
+ !query && visibleCategories.map((cat) => {
955
+ const isOpen = openCategoryId === cat.id;
956
+ const kind = cat.kind ?? "function";
957
+ const KindIcon = KIND_ICON[kind];
958
+ const branchIds = /* @__PURE__ */ new Set();
959
+ collectBranchIds(cat.items, branchIds);
960
+ const hasTree = branchIds.size > 0;
961
+ const rows = [];
962
+ if (isOpen) flattenTree(cat.items, 0, expandedItems, rows);
963
+ const allExpanded = hasTree && [...branchIds].every((id) => expandedItems.has(id));
964
+ return /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__category", children: [
965
+ /* @__PURE__ */ jsxs2(
966
+ "div",
967
+ {
968
+ className: cn(
969
+ "ods-flow-fx-panel__cat-header",
970
+ isOpen && "ods-flow-fx-panel__cat-header--open"
971
+ ),
972
+ children: [
973
+ /* @__PURE__ */ jsxs2(
974
+ "button",
975
+ {
976
+ type: "button",
977
+ className: "ods-flow-fx-panel__cat-toggle",
978
+ "aria-expanded": isOpen,
979
+ onClick: () => setOpenCategory(isOpen ? null : cat.id),
980
+ children: [
981
+ /* @__PURE__ */ jsx2(
982
+ ChevronRightIcon,
983
+ {
984
+ size: "sm",
985
+ className: cn(
986
+ "ods-flow-fx-panel__chevron",
987
+ isOpen && "ods-flow-fx-panel__chevron--open"
988
+ )
989
+ }
990
+ ),
991
+ /* @__PURE__ */ jsxs2(
992
+ "span",
993
+ {
994
+ className: cn(
995
+ "ods-flow-fx-panel__badge",
996
+ `ods-flow-fx-panel__badge--${kind}`
997
+ ),
998
+ children: [
999
+ /* @__PURE__ */ jsx2(
1000
+ KindIcon,
1001
+ {
1002
+ size: "sm",
1003
+ className: "ods-flow-fx-panel__badge-icon"
1004
+ }
1005
+ ),
1006
+ cat.label
1007
+ ]
1008
+ }
1009
+ ),
1010
+ /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__count", children: countLeaves(cat.items) })
1011
+ ]
1012
+ }
1013
+ ),
1014
+ isOpen && hasTree && /* @__PURE__ */ jsx2(
1015
+ "button",
1016
+ {
1017
+ type: "button",
1018
+ className: "ods-flow-fx-panel__cat-action",
1019
+ "aria-label": allExpanded ? "Collapse all" : "Expand all",
1020
+ title: allExpanded ? "Collapse all" : "Expand all",
1021
+ onClick: () => setCategoryExpansion(cat, !allExpanded),
1022
+ children: allExpanded ? /* @__PURE__ */ jsx2(CollapseAllIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(ExpandAllIcon, { size: "sm" })
1023
+ }
1024
+ )
1025
+ ]
1026
+ }
1027
+ ),
1028
+ isOpen && /* @__PURE__ */ jsx2(
1029
+ "div",
1030
+ {
1031
+ className: "ods-flow-fx-panel__rows",
1032
+ role: "group",
1033
+ "aria-label": cat.label,
1034
+ children: rows.map((row) => renderRow(row, cat, rows))
1035
+ }
1036
+ )
1037
+ ] }, cat.id);
1038
+ })
1039
+ ] })
1040
+ ]
1041
+ }
1042
+ );
788
1043
  }
789
- function cursorFor(corner) {
790
- switch (corner) {
791
- case "nw":
792
- case "se":
793
- return "nwse-resize";
794
- case "ne":
795
- case "sw":
796
- return "nesw-resize";
797
- }
1044
+
1045
+ // src/workflow/components/FxPanel/DataRefButton.tsx
1046
+ import { DataReferenceIcon } from "@octaviaflow/icons";
1047
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1048
+ function DataRefButton({
1049
+ active = false,
1050
+ label = "Data ref",
1051
+ className,
1052
+ type = "button",
1053
+ ...rest
1054
+ }) {
1055
+ return /* @__PURE__ */ jsxs3(
1056
+ "button",
1057
+ {
1058
+ ...rest,
1059
+ type,
1060
+ className: cn(
1061
+ "ods-flow-dataref-button",
1062
+ active && "ods-flow-dataref-button--active",
1063
+ label == null && "ods-flow-dataref-button--icon-only",
1064
+ className
1065
+ ),
1066
+ "aria-pressed": active,
1067
+ title: active ? "Hide data references" : "Show data references",
1068
+ children: [
1069
+ /* @__PURE__ */ jsx3(
1070
+ DataReferenceIcon,
1071
+ {
1072
+ size: "sm",
1073
+ className: "ods-flow-dataref-button__icon"
1074
+ }
1075
+ ),
1076
+ label != null && /* @__PURE__ */ jsx3("span", { className: "ods-flow-dataref-button__label", children: label })
1077
+ ]
1078
+ }
1079
+ );
798
1080
  }
799
1081
 
800
1082
  // src/workflow/components/NodeToolbar/NodeToolbar.tsx
801
- import { jsx as jsx3 } from "react/jsx-runtime";
1083
+ import { jsx as jsx4 } from "react/jsx-runtime";
802
1084
  function NodeToolbar({
803
1085
  isVisible,
804
1086
  position = "top",
@@ -813,7 +1095,7 @@ function NodeToolbar({
813
1095
  const show = isVisible ?? node.selected;
814
1096
  if (!show) return null;
815
1097
  const inverseScale = 1 / viewport.zoom;
816
- return /* @__PURE__ */ jsx3(
1098
+ return /* @__PURE__ */ jsx4(
817
1099
  "div",
818
1100
  {
819
1101
  className: cn("ods-node-toolbar", `ods-node-toolbar--${position}`, className),
@@ -825,7 +1107,7 @@ function NodeToolbar({
825
1107
  onPointerDown: (e) => e.stopPropagation(),
826
1108
  onMouseDown: (e) => e.stopPropagation(),
827
1109
  onClick: (e) => e.stopPropagation(),
828
- children: /* @__PURE__ */ jsx3(
1110
+ children: /* @__PURE__ */ jsx4(
829
1111
  "div",
830
1112
  {
831
1113
  className: "ods-node-toolbar__inner",
@@ -973,11 +1255,13 @@ export {
973
1255
  DEFAULT_NODE_HEIGHT,
974
1256
  DEFAULT_NODE_KINDS,
975
1257
  DEFAULT_NODE_WIDTH,
1258
+ DataRefButton,
976
1259
  ErrorNode,
977
1260
  FlowCanvas,
978
1261
  FlowEdge,
979
1262
  FlowNode,
980
1263
  ForEachNode,
1264
+ FxPanel,
981
1265
  GroupNode,
982
1266
  Handle,
983
1267
  HttpRequestNode,
@@ -1024,6 +1308,7 @@ export {
1024
1308
  useNodeData,
1025
1309
  useNodes,
1026
1310
  useSelection,
1027
- useViewport
1311
+ useViewport,
1312
+ useViewportOrNull
1028
1313
  };
1029
1314
  //# sourceMappingURL=workflow.js.map