@octaviaflow/core 3.0.18-beta.2 → 3.0.18-beta.21

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 (174) 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-76TP67ED.js +2984 -0
  20. package/dist/chunk-76TP67ED.js.map +1 -0
  21. package/dist/chunk-A6KMO4JV.js +2949 -0
  22. package/dist/chunk-A6KMO4JV.js.map +1 -0
  23. package/dist/chunk-B7FTWSTM.js +2938 -0
  24. package/dist/chunk-B7FTWSTM.js.map +1 -0
  25. package/dist/chunk-BCO6M26F.js +2940 -0
  26. package/dist/chunk-BCO6M26F.js.map +1 -0
  27. package/dist/chunk-C3UD2AZ5.js +2637 -0
  28. package/dist/chunk-C3UD2AZ5.js.map +1 -0
  29. package/dist/chunk-CEUP4NK2.js +2850 -0
  30. package/dist/chunk-CEUP4NK2.js.map +1 -0
  31. package/dist/chunk-DBNSBJO7.js +2993 -0
  32. package/dist/chunk-DBNSBJO7.js.map +1 -0
  33. package/dist/chunk-ECIHUVU7.js +2986 -0
  34. package/dist/chunk-ECIHUVU7.js.map +1 -0
  35. package/dist/chunk-EERNYLFL.js +2860 -0
  36. package/dist/chunk-EERNYLFL.js.map +1 -0
  37. package/dist/chunk-EKFDJX4G.js +2872 -0
  38. package/dist/chunk-EKFDJX4G.js.map +1 -0
  39. package/dist/chunk-GJA3GJUZ.js +2844 -0
  40. package/dist/chunk-GJA3GJUZ.js.map +1 -0
  41. package/dist/chunk-HDOTOZNA.js +2936 -0
  42. package/dist/chunk-HDOTOZNA.js.map +1 -0
  43. package/dist/chunk-IOKUV7FD.js +2658 -0
  44. package/dist/chunk-IOKUV7FD.js.map +1 -0
  45. package/dist/chunk-IUIICQU5.js +2946 -0
  46. package/dist/chunk-IUIICQU5.js.map +1 -0
  47. package/dist/chunk-J2UYZI6D.js +2946 -0
  48. package/dist/chunk-J2UYZI6D.js.map +1 -0
  49. package/dist/chunk-J7YASALS.js +2859 -0
  50. package/dist/chunk-J7YASALS.js.map +1 -0
  51. package/dist/chunk-JIEUYBQT.js +2658 -0
  52. package/dist/chunk-JIEUYBQT.js.map +1 -0
  53. package/dist/chunk-K2H7JLQW.js +2952 -0
  54. package/dist/chunk-K2H7JLQW.js.map +1 -0
  55. package/dist/chunk-KUXYBP66.js +2953 -0
  56. package/dist/chunk-KUXYBP66.js.map +1 -0
  57. package/dist/chunk-KYMYNYFV.js +2656 -0
  58. package/dist/chunk-KYMYNYFV.js.map +1 -0
  59. package/dist/chunk-MMXL343D.js +2974 -0
  60. package/dist/chunk-MMXL343D.js.map +1 -0
  61. package/dist/chunk-MXJL3EPE.js +2986 -0
  62. package/dist/chunk-MXJL3EPE.js.map +1 -0
  63. package/dist/chunk-MYZ25B2R.js +2995 -0
  64. package/dist/chunk-MYZ25B2R.js.map +1 -0
  65. package/dist/chunk-NTMEYB7B.js +2949 -0
  66. package/dist/chunk-NTMEYB7B.js.map +1 -0
  67. package/dist/chunk-PVJXX6GP.js +2640 -0
  68. package/dist/chunk-PVJXX6GP.js.map +1 -0
  69. package/dist/chunk-Q6ERDPQR.js +2981 -0
  70. package/dist/chunk-Q6ERDPQR.js.map +1 -0
  71. package/dist/chunk-S2SSBMWJ.js +2658 -0
  72. package/dist/chunk-S2SSBMWJ.js.map +1 -0
  73. package/dist/chunk-SLVDAZSX.js +2946 -0
  74. package/dist/chunk-SLVDAZSX.js.map +1 -0
  75. package/dist/chunk-UQBPYONV.js +2991 -0
  76. package/dist/chunk-UQBPYONV.js.map +1 -0
  77. package/dist/chunk-UXMNBS22.js +2955 -0
  78. package/dist/chunk-UXMNBS22.js.map +1 -0
  79. package/dist/chunk-WEGED7TA.js +2991 -0
  80. package/dist/chunk-WEGED7TA.js.map +1 -0
  81. package/dist/chunk-WEPTBLWX.js +2847 -0
  82. package/dist/chunk-WEPTBLWX.js.map +1 -0
  83. package/dist/chunk-WG4ZQMPS.js +2844 -0
  84. package/dist/chunk-WG4ZQMPS.js.map +1 -0
  85. package/dist/chunk-XEPEBHAW.js +2808 -0
  86. package/dist/chunk-XEPEBHAW.js.map +1 -0
  87. package/dist/chunk-XG2OYFX6.js +2925 -0
  88. package/dist/chunk-XG2OYFX6.js.map +1 -0
  89. package/dist/chunk-ZAMJEU42.js +2992 -0
  90. package/dist/chunk-ZAMJEU42.js.map +1 -0
  91. package/dist/chunk-ZRAM6FXB.js +2949 -0
  92. package/dist/chunk-ZRAM6FXB.js.map +1 -0
  93. package/dist/components/CsvViewer/CsvViewer.d.ts +51 -0
  94. package/dist/components/CsvViewer/CsvViewer.d.ts.map +1 -0
  95. package/dist/components/CsvViewer/index.d.ts +2 -0
  96. package/dist/components/CsvViewer/index.d.ts.map +1 -0
  97. package/dist/components/DataTable/DataTable.d.ts +19 -1
  98. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  99. package/dist/components/DropdownMenu/DropdownMenu.d.ts +12 -2
  100. package/dist/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  101. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts +8 -2
  102. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts.map +1 -1
  103. package/dist/components/FlowMinimap/FlowMinimap.d.ts +17 -1
  104. package/dist/components/FlowMinimap/FlowMinimap.d.ts.map +1 -1
  105. package/dist/components/FlowToolbar/FlowToolbar.d.ts +16 -10
  106. package/dist/components/FlowToolbar/FlowToolbar.d.ts.map +1 -1
  107. package/dist/components/JsonViewer/JsonViewer.d.ts +42 -7
  108. package/dist/components/JsonViewer/JsonViewer.d.ts.map +1 -1
  109. package/dist/components/JsonViewer/index.d.ts +1 -1
  110. package/dist/components/JsonViewer/index.d.ts.map +1 -1
  111. package/dist/components/Select/Select.d.ts.map +1 -1
  112. package/dist/components/WorkflowHeader/WorkflowHeader.d.ts +130 -0
  113. package/dist/components/WorkflowHeader/WorkflowHeader.d.ts.map +1 -0
  114. package/dist/components/WorkflowHeader/WorkflowHeaderExpanded.d.ts +69 -0
  115. package/dist/components/WorkflowHeader/WorkflowHeaderExpanded.d.ts.map +1 -0
  116. package/dist/components/WorkflowHeader/index.d.ts +3 -0
  117. package/dist/components/WorkflowHeader/index.d.ts.map +1 -0
  118. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCentered.d.ts +40 -0
  119. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCentered.d.ts.map +1 -0
  120. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCommand.d.ts +39 -0
  121. package/dist/components/WorkflowHeader/misc/WorkflowHeaderCommand.d.ts.map +1 -0
  122. package/dist/components/WorkflowHeader/misc/WorkflowHeaderMinimal.d.ts +44 -0
  123. package/dist/components/WorkflowHeader/misc/WorkflowHeaderMinimal.d.ts.map +1 -0
  124. package/dist/components/WorkflowHeader/misc/WorkflowHeaderRail.d.ts +45 -0
  125. package/dist/components/WorkflowHeader/misc/WorkflowHeaderRail.d.ts.map +1 -0
  126. package/dist/components/WorkflowHeader/misc/WorkflowHeaderStudio.d.ts +48 -0
  127. package/dist/components/WorkflowHeader/misc/WorkflowHeaderStudio.d.ts.map +1 -0
  128. package/dist/components/WorkflowHeader/misc/WorkflowHeaderTiered.d.ts +52 -0
  129. package/dist/components/WorkflowHeader/misc/WorkflowHeaderTiered.d.ts.map +1 -0
  130. package/dist/components/XmlViewer/XmlViewer.d.ts +26 -1
  131. package/dist/components/XmlViewer/XmlViewer.d.ts.map +1 -1
  132. package/dist/components/XmlViewer/index.d.ts +1 -1
  133. package/dist/components/XmlViewer/index.d.ts.map +1 -1
  134. package/dist/components/YamlViewer/YamlViewer.d.ts +26 -1
  135. package/dist/components/YamlViewer/YamlViewer.d.ts.map +1 -1
  136. package/dist/components/YamlViewer/index.d.ts +1 -1
  137. package/dist/components/YamlViewer/index.d.ts.map +1 -1
  138. package/dist/hooks/useRelativeTime.d.ts +28 -0
  139. package/dist/hooks/useRelativeTime.d.ts.map +1 -0
  140. package/dist/hooks/useWorkflowRuntime.d.ts +20 -0
  141. package/dist/hooks/useWorkflowRuntime.d.ts.map +1 -0
  142. package/dist/index.cjs +4918 -3536
  143. package/dist/index.cjs.map +1 -1
  144. package/dist/index.d.ts +7 -3
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/index.js +4317 -3305
  147. package/dist/index.js.map +1 -1
  148. package/dist/styles.css +1 -1
  149. package/dist/workflow/components/ConfigPanel/ConfigPanel.d.ts +27 -9
  150. package/dist/workflow/components/ConfigPanel/ConfigPanel.d.ts.map +1 -1
  151. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts +49 -1
  152. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts.map +1 -1
  153. package/dist/workflow/components/FlowEdge/FlowEdge.d.ts.map +1 -1
  154. package/dist/workflow/components/FxPanel/FxPanel.d.ts +61 -0
  155. package/dist/workflow/components/FxPanel/FxPanel.d.ts.map +1 -0
  156. package/dist/workflow/components/FxPanel/FxToggleButton.d.ts +9 -0
  157. package/dist/workflow/components/FxPanel/FxToggleButton.d.ts.map +1 -0
  158. package/dist/workflow/components/Handle/Handle.d.ts +9 -1
  159. package/dist/workflow/components/Handle/Handle.d.ts.map +1 -1
  160. package/dist/workflow/components/Handle/handleRegistry.d.ts +19 -0
  161. package/dist/workflow/components/Handle/handleRegistry.d.ts.map +1 -1
  162. package/dist/workflow/components/kinds/index.d.ts +4 -0
  163. package/dist/workflow/components/kinds/index.d.ts.map +1 -1
  164. package/dist/workflow/index.d.ts +3 -1
  165. package/dist/workflow/index.d.ts.map +1 -1
  166. package/dist/workflow/store/selectors.d.ts +12 -0
  167. package/dist/workflow/store/selectors.d.ts.map +1 -1
  168. package/dist/workflow/utils/parenting.d.ts +5 -3
  169. package/dist/workflow/utils/parenting.d.ts.map +1 -1
  170. package/dist/workflow.cjs +915 -446
  171. package/dist/workflow.cjs.map +1 -1
  172. package/dist/workflow.js +309 -256
  173. package/dist/workflow.js.map +1 -1
  174. package/package.json +7 -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-2ZIOFEIS.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,249 @@ 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
+ useState as useState4
624
+ } from "react";
625
+ import {
626
+ ChevronRightIcon,
627
+ CloseIcon,
628
+ SearchIcon
629
+ } from "@octaviaflow/icons";
630
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
631
+ var KIND_GLYPH = {
632
+ function: "\u0192",
633
+ variable: "\u2B21"
634
+ };
635
+ function FxPanel({
636
+ categories,
637
+ title = "FX / IO",
638
+ hint = /* @__PURE__ */ jsxs2(Fragment2, { children: [
639
+ "Drag items into any input field with the ",
640
+ /* @__PURE__ */ jsx2("strong", { children: "FX" }),
641
+ " indicator"
642
+ ] }),
643
+ search: controlledSearch,
644
+ defaultSearch = "",
645
+ onSearchChange,
646
+ expandedCategory: controlledExpanded,
647
+ defaultExpandedCategory,
648
+ onExpandedCategoryChange,
649
+ onClose,
650
+ onItemDragStart,
651
+ onItemSelect,
652
+ width = 292,
653
+ emptyLabel = "No matches",
654
+ searchPlaceholder = "Search functions & variables\u2026",
655
+ className,
656
+ style
668
657
  }) {
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
- };
692
- };
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);
728
- }
729
- }
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 }
736
- });
737
- onResize?.({ width: nextW, height: nextH });
658
+ const [internalSearch, setInternalSearch] = useState4(defaultSearch);
659
+ const search = controlledSearch ?? internalSearch;
660
+ const setSearch = (next) => {
661
+ if (controlledSearch === void 0) setInternalSearch(next);
662
+ onSearchChange?.(next);
738
663
  };
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
- });
747
- }
748
- dragRef.current = null;
749
- }
664
+ const [internalExpanded, setInternalExpanded] = useState4(
665
+ defaultExpandedCategory !== void 0 ? defaultExpandedCategory : categories.find((c) => c.items.length > 0)?.id ?? null
666
+ );
667
+ const expanded = controlledExpanded ?? internalExpanded;
668
+ const setExpanded = (id) => {
669
+ if (controlledExpanded === void 0) setInternalExpanded(id);
670
+ onExpandedCategoryChange?.(id);
750
671
  };
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%" };
672
+ const [draggingId, setDraggingId] = useState4(null);
673
+ const filtered = useMemo2(() => {
674
+ const q = search.trim().toLowerCase();
675
+ if (!q) return categories;
676
+ return categories.map((cat) => {
677
+ if (cat.label.toLowerCase().includes(q)) return cat;
678
+ const items = cat.items.filter(
679
+ (it) => it.label.toLowerCase().includes(q) || (it.description?.toLowerCase().includes(q) ?? false)
680
+ );
681
+ return { ...cat, items };
682
+ }).filter((cat) => cat.items.length > 0);
683
+ }, [categories, search]);
684
+ const hasResults = filtered.length > 0;
685
+ const handleDragStart = (item, category) => (e) => {
686
+ setDraggingId(item.id);
687
+ if (onItemDragStart) {
688
+ onItemDragStart(item, category, e);
689
+ } else {
690
+ e.dataTransfer.setData("text/plain", item.insertValue);
691
+ e.dataTransfer.setData("application/x-fx-insert", item.insertValue);
692
+ e.dataTransfer.setData(
693
+ "application/x-fx-type",
694
+ category.kind ?? "function"
695
+ );
696
+ e.dataTransfer.effectAllowed = "copy";
774
697
  }
775
698
  };
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",
699
+ return /* @__PURE__ */ jsxs2(
700
+ "aside",
778
701
  {
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
- )) });
702
+ className: cn("ods-flow-fx-panel", className),
703
+ style: { width, ...style },
704
+ "aria-label": typeof title === "string" ? title : "FX / IO",
705
+ children: [
706
+ /* @__PURE__ */ jsxs2("header", { className: "ods-flow-fx-panel__header", children: [
707
+ /* @__PURE__ */ jsx2("h3", { className: "ods-flow-fx-panel__title", children: title }),
708
+ onClose && /* @__PURE__ */ jsx2(
709
+ "button",
710
+ {
711
+ type: "button",
712
+ className: "ods-flow-fx-panel__close",
713
+ onClick: onClose,
714
+ "aria-label": "Close FX panel",
715
+ children: /* @__PURE__ */ jsx2(CloseIcon, { size: "sm" })
716
+ }
717
+ )
718
+ ] }),
719
+ /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__search", children: [
720
+ /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(SearchIcon, { size: "sm" }) }),
721
+ /* @__PURE__ */ jsx2(
722
+ "input",
723
+ {
724
+ type: "text",
725
+ className: "ods-flow-fx-panel__search-input",
726
+ placeholder: searchPlaceholder,
727
+ "aria-label": "Search functions and variables",
728
+ value: search,
729
+ onChange: (e) => setSearch(e.target.value)
730
+ }
731
+ ),
732
+ search && /* @__PURE__ */ jsx2(
733
+ "button",
734
+ {
735
+ type: "button",
736
+ className: "ods-flow-fx-panel__search-clear",
737
+ onClick: () => setSearch(""),
738
+ "aria-label": "Clear search",
739
+ children: /* @__PURE__ */ jsx2(CloseIcon, { size: "sm" })
740
+ }
741
+ )
742
+ ] }),
743
+ hint && /* @__PURE__ */ jsx2("p", { className: "ods-flow-fx-panel__hint", children: hint }),
744
+ /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__list", children: [
745
+ filtered.map((cat) => {
746
+ const isOpen = expanded === cat.id;
747
+ const kind = cat.kind ?? "function";
748
+ return /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__category", children: [
749
+ /* @__PURE__ */ jsxs2(
750
+ "button",
751
+ {
752
+ type: "button",
753
+ className: "ods-flow-fx-panel__category-header",
754
+ "aria-expanded": isOpen,
755
+ onClick: () => setExpanded(isOpen ? null : cat.id),
756
+ children: [
757
+ /* @__PURE__ */ jsx2(
758
+ ChevronRightIcon,
759
+ {
760
+ size: "sm",
761
+ className: cn(
762
+ "ods-flow-fx-panel__chevron",
763
+ isOpen && "ods-flow-fx-panel__chevron--open"
764
+ )
765
+ }
766
+ ),
767
+ /* @__PURE__ */ jsxs2(
768
+ "span",
769
+ {
770
+ className: cn(
771
+ "ods-flow-fx-panel__badge",
772
+ `ods-flow-fx-panel__badge--${kind}`
773
+ ),
774
+ children: [
775
+ /* @__PURE__ */ jsx2(
776
+ "span",
777
+ {
778
+ className: "ods-flow-fx-panel__badge-glyph",
779
+ "aria-hidden": "true",
780
+ children: KIND_GLYPH[kind]
781
+ }
782
+ ),
783
+ cat.label
784
+ ]
785
+ }
786
+ ),
787
+ /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__count", children: cat.items.length })
788
+ ]
789
+ }
790
+ ),
791
+ isOpen && /* @__PURE__ */ jsx2("div", { className: "ods-flow-fx-panel__items", children: cat.items.map((item) => /* @__PURE__ */ jsxs2(
792
+ "div",
793
+ {
794
+ className: cn(
795
+ "ods-flow-fx-panel__item",
796
+ draggingId === item.id && "ods-flow-fx-panel__item--dragging"
797
+ ),
798
+ draggable: true,
799
+ title: item.insertValue,
800
+ onDragStart: handleDragStart(item, cat),
801
+ onDragEnd: () => setDraggingId(null),
802
+ onClick: onItemSelect ? () => onItemSelect(item, cat) : void 0,
803
+ children: [
804
+ /* @__PURE__ */ jsx2("code", { className: "ods-flow-fx-panel__item-label", children: item.label }),
805
+ item.description && /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__item-desc", children: item.description })
806
+ ]
807
+ },
808
+ item.id
809
+ )) })
810
+ ] }, cat.id);
811
+ }),
812
+ !hasResults && /* @__PURE__ */ jsx2("div", { className: "ods-flow-fx-panel__empty", children: emptyLabel })
813
+ ] })
814
+ ]
815
+ }
816
+ );
788
817
  }
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
- }
818
+
819
+ // src/workflow/components/FxPanel/FxToggleButton.tsx
820
+ import { FunctionIcon } from "@octaviaflow/icons";
821
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
822
+ function FxToggleButton({
823
+ active = false,
824
+ label = "FX",
825
+ className,
826
+ type = "button",
827
+ ...rest
828
+ }) {
829
+ return /* @__PURE__ */ jsxs3(
830
+ "button",
831
+ {
832
+ ...rest,
833
+ type,
834
+ className: cn(
835
+ "ods-flow-fx-toggle",
836
+ active && "ods-flow-fx-toggle--active",
837
+ label == null && "ods-flow-fx-toggle--icon-only",
838
+ className
839
+ ),
840
+ "aria-pressed": active,
841
+ title: active ? "Hide FX / IO" : "Show FX / IO",
842
+ children: [
843
+ /* @__PURE__ */ jsx3(FunctionIcon, { size: "sm", className: "ods-flow-fx-toggle__icon" }),
844
+ label != null && /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-toggle__label", children: label })
845
+ ]
846
+ }
847
+ );
798
848
  }
799
849
 
800
850
  // src/workflow/components/NodeToolbar/NodeToolbar.tsx
801
- import { jsx as jsx3 } from "react/jsx-runtime";
851
+ import { jsx as jsx4 } from "react/jsx-runtime";
802
852
  function NodeToolbar({
803
853
  isVisible,
804
854
  position = "top",
@@ -813,7 +863,7 @@ function NodeToolbar({
813
863
  const show = isVisible ?? node.selected;
814
864
  if (!show) return null;
815
865
  const inverseScale = 1 / viewport.zoom;
816
- return /* @__PURE__ */ jsx3(
866
+ return /* @__PURE__ */ jsx4(
817
867
  "div",
818
868
  {
819
869
  className: cn("ods-node-toolbar", `ods-node-toolbar--${position}`, className),
@@ -825,7 +875,7 @@ function NodeToolbar({
825
875
  onPointerDown: (e) => e.stopPropagation(),
826
876
  onMouseDown: (e) => e.stopPropagation(),
827
877
  onClick: (e) => e.stopPropagation(),
828
- children: /* @__PURE__ */ jsx3(
878
+ children: /* @__PURE__ */ jsx4(
829
879
  "div",
830
880
  {
831
881
  className: "ods-node-toolbar__inner",
@@ -978,6 +1028,8 @@ export {
978
1028
  FlowEdge,
979
1029
  FlowNode,
980
1030
  ForEachNode,
1031
+ FxPanel,
1032
+ FxToggleButton,
981
1033
  GroupNode,
982
1034
  Handle,
983
1035
  HttpRequestNode,
@@ -1024,6 +1076,7 @@ export {
1024
1076
  useNodeData,
1025
1077
  useNodes,
1026
1078
  useSelection,
1027
- useViewport
1079
+ useViewport,
1080
+ useViewportOrNull
1028
1081
  };
1029
1082
  //# sourceMappingURL=workflow.js.map