@octaviaflow/core 3.0.18-beta.20 → 3.0.18-beta.22

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.
@@ -0,0 +1,61 @@
1
+ import { type CSSProperties, type DragEvent, type ReactNode } from "react";
2
+ export type FxItemKind = "function" | "variable";
3
+ export interface FxPanelItem {
4
+ /** Stable key. */
5
+ id: string;
6
+ /** Display label — usually a function signature or variable name. */
7
+ label: string;
8
+ /** The string handed to `dataTransfer` / inserted into a field. */
9
+ insertValue: string;
10
+ /** Short one-line description shown under the label. */
11
+ description?: string;
12
+ }
13
+ export interface FxPanelCategory {
14
+ /** Stable key + accordion identity. */
15
+ id: string;
16
+ /** Section heading. */
17
+ label: string;
18
+ /** Drives the badge glyph + drag payload. Defaults to "function". */
19
+ kind?: FxItemKind;
20
+ items: FxPanelItem[];
21
+ }
22
+ export interface FxPanelProps {
23
+ /** Categorised entries. Empty categories are skipped from render. */
24
+ categories: FxPanelCategory[];
25
+ /** Header title. Default "FX / IO". */
26
+ title?: ReactNode;
27
+ /** Instructional line under the search. Pass `null` to hide it. */
28
+ hint?: ReactNode;
29
+ /** Controlled search term. */
30
+ search?: string;
31
+ /** Initial search term when uncontrolled. */
32
+ defaultSearch?: string;
33
+ onSearchChange?: (next: string) => void;
34
+ /** Controlled open category (single-open accordion). `null` = all closed. */
35
+ expandedCategory?: string | null;
36
+ /** Initial open category when uncontrolled. */
37
+ defaultExpandedCategory?: string | null;
38
+ onExpandedCategoryChange?: (id: string | null) => void;
39
+ /** Close (✕) handler. Omit to hide the close button. */
40
+ onClose?: () => void;
41
+ /**
42
+ * Fires when an item begins dragging. Use it to populate
43
+ * `e.dataTransfer`. When omitted, FxPanel writes a sensible default:
44
+ * - `text/plain` → insertValue
45
+ * - `application/x-fx-insert`→ insertValue
46
+ * - `application/x-fx-type` → category kind
47
+ */
48
+ onItemDragStart?: (item: FxPanelItem, category: FxPanelCategory, e: DragEvent<HTMLElement>) => void;
49
+ /** Fires on a plain click of an item (e.g. insert at cursor). */
50
+ onItemSelect?: (item: FxPanelItem, category: FxPanelCategory) => void;
51
+ /** Panel width (px). Default 292. */
52
+ width?: number;
53
+ /** Message shown when a search matches nothing. Default "No matches". */
54
+ emptyLabel?: ReactNode;
55
+ /** Placeholder for the search box. */
56
+ searchPlaceholder?: string;
57
+ className?: string;
58
+ style?: CSSProperties;
59
+ }
60
+ export declare function FxPanel({ categories, title, hint, search: controlledSearch, defaultSearch, onSearchChange, expandedCategory: controlledExpanded, defaultExpandedCategory, onExpandedCategoryChange, onClose, onItemDragStart, onItemSelect, width, emptyLabel, searchPlaceholder, className, style, }: FxPanelProps): import("react/jsx-runtime").JSX.Element;
61
+ //# sourceMappingURL=FxPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FxPanel.d.ts","sourceRoot":"","sources":["../../../../src/workflow/components/FxPanel/FxPanel.tsx"],"names":[],"mappings":"AAcA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAQf,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,kBAAkB;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,uCAAuC;IACvC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mEAAmE;IACnE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,+CAA+C;IAC/C,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,wBAAwB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAChB,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,eAAe,EACzB,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,KACtB,IAAI,CAAC;IACV,iEAAiE;IACjE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;IACtE,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,sCAAsC;IACtC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAOD,wBAAgB,OAAO,CAAC,EACtB,UAAU,EACV,KAAiB,EACjB,IAIC,EACD,MAAM,EAAE,gBAAgB,EACxB,aAAkB,EAClB,cAAc,EACd,gBAAgB,EAAE,kBAAkB,EACpC,uBAAuB,EACvB,wBAAwB,EACxB,OAAO,EACP,eAAe,EACf,YAAY,EACZ,KAAW,EACX,UAAyB,EACzB,iBAAmD,EACnD,SAAS,EACT,KAAK,GACN,EAAE,YAAY,2CA8Ld"}
@@ -0,0 +1,9 @@
1
+ import { type ButtonHTMLAttributes, type ReactNode } from "react";
2
+ export interface FxToggleButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
3
+ /** Whether the FxPanel is currently open. Drives `aria-pressed`. */
4
+ active?: boolean;
5
+ /** Visible label beside the glyph. Default "FX". Pass `null` for icon-only. */
6
+ label?: ReactNode;
7
+ }
8
+ export declare function FxToggleButton({ active, label, className, type, ...rest }: FxToggleButtonProps): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=FxToggleButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FxToggleButton.d.ts","sourceRoot":"","sources":["../../../../src/workflow/components/FxPanel/FxToggleButton.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIlE,MAAM,WAAW,mBACf,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,UAAU,CAAC;IACjE,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAc,EACd,KAAY,EACZ,SAAS,EACT,IAAe,EACf,GAAG,IAAI,EACR,EAAE,mBAAmB,2CAoBrB"}
@@ -11,6 +11,8 @@ export { ConfigPanel, type ConfigPanelProps, type ConfigPanelSaveState, type Con
11
11
  export { FlowCanvas, type FlowCanvasProps } from "./components/FlowCanvas/FlowCanvas";
12
12
  export { FlowEdge, type FlowEdgeProps } from "./components/FlowEdge/FlowEdge";
13
13
  export { FlowNode, type FlowNodeProps } from "./components/FlowNode/FlowNode";
14
+ export { FxPanel, type FxItemKind, type FxPanelCategory, type FxPanelItem, type FxPanelProps, } from "./components/FxPanel/FxPanel";
15
+ export { FxToggleButton, type FxToggleButtonProps, } from "./components/FxPanel/FxToggleButton";
14
16
  export { type FlowNodeContextValue, useFlowNodeContext, } from "./components/FlowNode/FlowNodeContext";
15
17
  export { buildNodeKindRegistry, type NodeKindComponent, type NodeKindProps, type NodeKindRegistry, } from "./components/FlowNode/nodeKinds";
16
18
  export { Handle, type HandleProps } from "./components/Handle/Handle";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":"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"}
package/dist/workflow.cjs CHANGED
@@ -31,6 +31,8 @@ __export(workflow_exports, {
31
31
  FlowEdge: () => FlowEdge,
32
32
  FlowNode: () => FlowNode,
33
33
  ForEachNode: () => ForEachNode,
34
+ FxPanel: () => FxPanel,
35
+ FxToggleButton: () => FxToggleButton,
34
36
  GroupNode: () => GroupNode,
35
37
  Handle: () => Handle,
36
38
  HttpRequestNode: () => HttpRequestNode,
@@ -3577,8 +3579,231 @@ var EdgesLayer = (0, import_react15.memo)(function EdgesLayer2({
3577
3579
  );
3578
3580
  });
3579
3581
 
3580
- // src/workflow/components/NodeToolbar/NodeToolbar.tsx
3582
+ // src/workflow/components/FxPanel/FxPanel.tsx
3583
+ var import_react16 = require("react");
3584
+ var import_icons2 = require("@octaviaflow/icons");
3581
3585
  var import_jsx_runtime9 = require("react/jsx-runtime");
3586
+ var KIND_GLYPH = {
3587
+ function: "\u0192",
3588
+ variable: "\u2B21"
3589
+ };
3590
+ function FxPanel({
3591
+ categories,
3592
+ title = "FX / IO",
3593
+ hint = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
3594
+ "Drag items into any input field with the ",
3595
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "FX" }),
3596
+ " indicator"
3597
+ ] }),
3598
+ search: controlledSearch,
3599
+ defaultSearch = "",
3600
+ onSearchChange,
3601
+ expandedCategory: controlledExpanded,
3602
+ defaultExpandedCategory,
3603
+ onExpandedCategoryChange,
3604
+ onClose,
3605
+ onItemDragStart,
3606
+ onItemSelect,
3607
+ width = 292,
3608
+ emptyLabel = "No matches",
3609
+ searchPlaceholder = "Search functions & variables\u2026",
3610
+ className,
3611
+ style
3612
+ }) {
3613
+ const [internalSearch, setInternalSearch] = (0, import_react16.useState)(defaultSearch);
3614
+ const search = controlledSearch ?? internalSearch;
3615
+ const setSearch = (next) => {
3616
+ if (controlledSearch === void 0) setInternalSearch(next);
3617
+ onSearchChange?.(next);
3618
+ };
3619
+ const [internalExpanded, setInternalExpanded] = (0, import_react16.useState)(
3620
+ defaultExpandedCategory !== void 0 ? defaultExpandedCategory : categories.find((c) => c.items.length > 0)?.id ?? null
3621
+ );
3622
+ const expanded = controlledExpanded ?? internalExpanded;
3623
+ const setExpanded = (id) => {
3624
+ if (controlledExpanded === void 0) setInternalExpanded(id);
3625
+ onExpandedCategoryChange?.(id);
3626
+ };
3627
+ const [draggingId, setDraggingId] = (0, import_react16.useState)(null);
3628
+ const filtered = (0, import_react16.useMemo)(() => {
3629
+ const q = search.trim().toLowerCase();
3630
+ const matched = q ? categories.map((cat) => {
3631
+ if (cat.label.toLowerCase().includes(q)) return cat;
3632
+ const items = cat.items.filter(
3633
+ (it) => it.label.toLowerCase().includes(q) || (it.description?.toLowerCase().includes(q) ?? false)
3634
+ );
3635
+ return { ...cat, items };
3636
+ }) : categories;
3637
+ return matched.filter((cat) => cat.items.length > 0);
3638
+ }, [categories, search]);
3639
+ const hasResults = filtered.length > 0;
3640
+ const handleDragStart = (item, category) => (e) => {
3641
+ setDraggingId(item.id);
3642
+ if (onItemDragStart) {
3643
+ onItemDragStart(item, category, e);
3644
+ } else {
3645
+ e.dataTransfer.setData("text/plain", item.insertValue);
3646
+ e.dataTransfer.setData("application/x-fx-insert", item.insertValue);
3647
+ e.dataTransfer.setData(
3648
+ "application/x-fx-type",
3649
+ category.kind ?? "function"
3650
+ );
3651
+ e.dataTransfer.effectAllowed = "copy";
3652
+ }
3653
+ };
3654
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3655
+ "aside",
3656
+ {
3657
+ className: cn("ods-flow-fx-panel", className),
3658
+ style: { width, ...style },
3659
+ "aria-label": typeof title === "string" ? title : "FX / IO",
3660
+ children: [
3661
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { className: "ods-flow-fx-panel__header", children: [
3662
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { className: "ods-flow-fx-panel__title", children: title }),
3663
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3664
+ "button",
3665
+ {
3666
+ type: "button",
3667
+ className: "ods-flow-fx-panel__close",
3668
+ onClick: onClose,
3669
+ "aria-label": "Close FX panel",
3670
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_icons2.CloseIcon, { size: "sm" })
3671
+ }
3672
+ )
3673
+ ] }),
3674
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ods-flow-fx-panel__search", children: [
3675
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ods-flow-fx-panel__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_icons2.SearchIcon, { size: "sm" }) }),
3676
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3677
+ "input",
3678
+ {
3679
+ type: "text",
3680
+ className: "ods-flow-fx-panel__search-input",
3681
+ placeholder: searchPlaceholder,
3682
+ "aria-label": "Search functions and variables",
3683
+ value: search,
3684
+ onChange: (e) => setSearch(e.target.value)
3685
+ }
3686
+ ),
3687
+ search && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3688
+ "button",
3689
+ {
3690
+ type: "button",
3691
+ className: "ods-flow-fx-panel__search-clear",
3692
+ onClick: () => setSearch(""),
3693
+ "aria-label": "Clear search",
3694
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_icons2.CloseIcon, { size: "sm" })
3695
+ }
3696
+ )
3697
+ ] }),
3698
+ hint && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "ods-flow-fx-panel__hint", children: hint }),
3699
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ods-flow-fx-panel__list", children: [
3700
+ filtered.map((cat) => {
3701
+ const isOpen = expanded === cat.id;
3702
+ const kind = cat.kind ?? "function";
3703
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ods-flow-fx-panel__category", children: [
3704
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3705
+ "button",
3706
+ {
3707
+ type: "button",
3708
+ className: "ods-flow-fx-panel__category-header",
3709
+ "aria-expanded": isOpen,
3710
+ onClick: () => setExpanded(isOpen ? null : cat.id),
3711
+ children: [
3712
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3713
+ import_icons2.ChevronRightIcon,
3714
+ {
3715
+ size: "sm",
3716
+ className: cn(
3717
+ "ods-flow-fx-panel__chevron",
3718
+ isOpen && "ods-flow-fx-panel__chevron--open"
3719
+ )
3720
+ }
3721
+ ),
3722
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3723
+ "span",
3724
+ {
3725
+ className: cn(
3726
+ "ods-flow-fx-panel__badge",
3727
+ `ods-flow-fx-panel__badge--${kind}`
3728
+ ),
3729
+ children: [
3730
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3731
+ "span",
3732
+ {
3733
+ className: "ods-flow-fx-panel__badge-glyph",
3734
+ "aria-hidden": "true",
3735
+ children: KIND_GLYPH[kind]
3736
+ }
3737
+ ),
3738
+ cat.label
3739
+ ]
3740
+ }
3741
+ ),
3742
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ods-flow-fx-panel__count", children: cat.items.length })
3743
+ ]
3744
+ }
3745
+ ),
3746
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ods-flow-fx-panel__items", children: cat.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3747
+ "div",
3748
+ {
3749
+ className: cn(
3750
+ "ods-flow-fx-panel__item",
3751
+ draggingId === item.id && "ods-flow-fx-panel__item--dragging"
3752
+ ),
3753
+ draggable: true,
3754
+ title: item.insertValue,
3755
+ onDragStart: handleDragStart(item, cat),
3756
+ onDragEnd: () => setDraggingId(null),
3757
+ onClick: onItemSelect ? () => onItemSelect(item, cat) : void 0,
3758
+ children: [
3759
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { className: "ods-flow-fx-panel__item-label", children: item.label }),
3760
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ods-flow-fx-panel__item-desc", children: item.description })
3761
+ ]
3762
+ },
3763
+ item.id
3764
+ )) })
3765
+ ] }, cat.id);
3766
+ }),
3767
+ !hasResults && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ods-flow-fx-panel__empty", children: emptyLabel })
3768
+ ] })
3769
+ ]
3770
+ }
3771
+ );
3772
+ }
3773
+
3774
+ // src/workflow/components/FxPanel/FxToggleButton.tsx
3775
+ var import_icons3 = require("@octaviaflow/icons");
3776
+ var import_jsx_runtime10 = require("react/jsx-runtime");
3777
+ function FxToggleButton({
3778
+ active = false,
3779
+ label = "FX",
3780
+ className,
3781
+ type = "button",
3782
+ ...rest
3783
+ }) {
3784
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
3785
+ "button",
3786
+ {
3787
+ ...rest,
3788
+ type,
3789
+ className: cn(
3790
+ "ods-flow-fx-toggle",
3791
+ active && "ods-flow-fx-toggle--active",
3792
+ label == null && "ods-flow-fx-toggle--icon-only",
3793
+ className
3794
+ ),
3795
+ "aria-pressed": active,
3796
+ title: active ? "Hide FX / IO" : "Show FX / IO",
3797
+ children: [
3798
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons3.FunctionIcon, { size: "sm", className: "ods-flow-fx-toggle__icon" }),
3799
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ods-flow-fx-toggle__label", children: label })
3800
+ ]
3801
+ }
3802
+ );
3803
+ }
3804
+
3805
+ // src/workflow/components/NodeToolbar/NodeToolbar.tsx
3806
+ var import_jsx_runtime11 = require("react/jsx-runtime");
3582
3807
  function NodeToolbar({
3583
3808
  isVisible,
3584
3809
  position = "top",
@@ -3593,7 +3818,7 @@ function NodeToolbar({
3593
3818
  const show = isVisible ?? node.selected;
3594
3819
  if (!show) return null;
3595
3820
  const inverseScale = 1 / viewport.zoom;
3596
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3821
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3597
3822
  "div",
3598
3823
  {
3599
3824
  className: cn("ods-node-toolbar", `ods-node-toolbar--${position}`, className),
@@ -3605,7 +3830,7 @@ function NodeToolbar({
3605
3830
  onPointerDown: (e) => e.stopPropagation(),
3606
3831
  onMouseDown: (e) => e.stopPropagation(),
3607
3832
  onClick: (e) => e.stopPropagation(),
3608
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3833
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3609
3834
  "div",
3610
3835
  {
3611
3836
  className: "ods-node-toolbar__inner",
@@ -3759,6 +3984,8 @@ function toggleGroupCollapse(groupId, nodes) {
3759
3984
  FlowEdge,
3760
3985
  FlowNode,
3761
3986
  ForEachNode,
3987
+ FxPanel,
3988
+ FxToggleButton,
3762
3989
  GroupNode,
3763
3990
  Handle,
3764
3991
  HttpRequestNode,