@particle-academy/fancy-flow 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/index.cjs +60 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -1
- package/dist/styles.css +38 -0
- package/dist/styles.css.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -108,10 +108,28 @@ editor.current?.run();
|
|
|
108
108
|
Three ways, all of which prune the edges attached to the node (a dangling edge
|
|
109
109
|
would survive into the schema and break the runner):
|
|
110
110
|
|
|
111
|
+
- **right-click a node** → Delete / Duplicate,
|
|
111
112
|
- the **Delete** toolbar button (enabled when a node is selected),
|
|
112
113
|
- the <kbd>Delete</kbd> or <kbd>Backspace</kbd> key on the canvas,
|
|
113
114
|
- `api.deleteSelected()` / `api.deleteNodes(ids)` from code.
|
|
114
115
|
|
|
116
|
+
Swap the menu for your own with `slots.contextMenu`, or turn it off with
|
|
117
|
+
`builtins={{ contextMenu: false }}` (passing your own
|
|
118
|
+
`canvasProps.onNodeContextMenu` also takes over):
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
<FlowEditor
|
|
122
|
+
slots={{
|
|
123
|
+
contextMenu: (api, nodeId, close) => (
|
|
124
|
+
<>
|
|
125
|
+
<button onClick={() => { api.duplicateNode(nodeId); close(); }}>Duplicate</button>
|
|
126
|
+
<button onClick={() => { pinNode(nodeId); close(); }}>Pin</button>
|
|
127
|
+
</>
|
|
128
|
+
),
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
```
|
|
132
|
+
|
|
115
133
|
`onDelete(ids)` fires after either path, so a host can sync its own store.
|
|
116
134
|
|
|
117
135
|
If you want none of the above chrome, skip `<FlowEditor>` entirely and compose
|
package/dist/index.cjs
CHANGED
|
@@ -10428,6 +10428,26 @@ function FlowEditorInner({
|
|
|
10428
10428
|
const selected2 = ReactExports.useMemo(() => flow.nodes.find((n) => n.id === selectedId) ?? null, [flow.nodes, selectedId]);
|
|
10429
10429
|
ReactExports.useEffect(() => onSelectionChange?.(selected2), [selected2, onSelectionChange]);
|
|
10430
10430
|
const handleNodeClick2 = (_e, node) => setSelectedId(node.id);
|
|
10431
|
+
const [menu, setMenu] = ReactExports.useState(null);
|
|
10432
|
+
const closeMenu = ReactExports.useCallback(() => setMenu(null), []);
|
|
10433
|
+
const handleNodeContextMenu = (event, node) => {
|
|
10434
|
+
event.preventDefault();
|
|
10435
|
+
setSelectedId(node.id);
|
|
10436
|
+
setMenu({ x: event.clientX, y: event.clientY, nodeId: node.id });
|
|
10437
|
+
};
|
|
10438
|
+
ReactExports.useEffect(() => {
|
|
10439
|
+
if (menu === null) return;
|
|
10440
|
+
const close = () => setMenu(null);
|
|
10441
|
+
const onKey = (e) => e.key === "Escape" && setMenu(null);
|
|
10442
|
+
window.addEventListener("click", close);
|
|
10443
|
+
window.addEventListener("scroll", close, true);
|
|
10444
|
+
window.addEventListener("keydown", onKey);
|
|
10445
|
+
return () => {
|
|
10446
|
+
window.removeEventListener("click", close);
|
|
10447
|
+
window.removeEventListener("scroll", close, true);
|
|
10448
|
+
window.removeEventListener("keydown", onKey);
|
|
10449
|
+
};
|
|
10450
|
+
}, [menu]);
|
|
10431
10451
|
ReactExports.useEffect(() => {
|
|
10432
10452
|
if (!controlled) onChange?.({ nodes: flow.nodes, edges: flow.edges });
|
|
10433
10453
|
}, [flow.nodes, flow.edges, onChange, controlled]);
|
|
@@ -10548,6 +10568,7 @@ function FlowEditorInner({
|
|
|
10548
10568
|
onEdgesChange: flow.onEdgesChange,
|
|
10549
10569
|
onConnect: flow.onConnect,
|
|
10550
10570
|
onNodeClick: handleNodeClick2,
|
|
10571
|
+
onNodeContextMenu: builtins.contextMenu === false ? void 0 : handleNodeContextMenu,
|
|
10551
10572
|
onNodesDelete: (deleted) => onDelete?.(deleted.map((n) => n.id)),
|
|
10552
10573
|
deleteKeyCode: ["Delete", "Backspace"],
|
|
10553
10574
|
height: "100%",
|
|
@@ -10556,6 +10577,45 @@ function FlowEditorInner({
|
|
|
10556
10577
|
}
|
|
10557
10578
|
),
|
|
10558
10579
|
slots.empty && api.nodes.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-editor__empty", children: slots.empty(api) }),
|
|
10580
|
+
menu !== null && builtins.contextMenu !== false && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10581
|
+
"div",
|
|
10582
|
+
{
|
|
10583
|
+
className: "ff-editor__ctx",
|
|
10584
|
+
style: { top: menu.y, left: menu.x },
|
|
10585
|
+
role: "menu",
|
|
10586
|
+
onClick: (e) => e.stopPropagation(),
|
|
10587
|
+
children: slots.contextMenu ? slots.contextMenu(api, menu.nodeId, closeMenu) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10588
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10589
|
+
"button",
|
|
10590
|
+
{
|
|
10591
|
+
type: "button",
|
|
10592
|
+
role: "menuitem",
|
|
10593
|
+
className: "ff-editor__ctx-item",
|
|
10594
|
+
"data-action": "ctx-duplicate",
|
|
10595
|
+
onClick: () => {
|
|
10596
|
+
api.duplicateNode(menu.nodeId);
|
|
10597
|
+
closeMenu();
|
|
10598
|
+
},
|
|
10599
|
+
children: "Duplicate"
|
|
10600
|
+
}
|
|
10601
|
+
),
|
|
10602
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10603
|
+
"button",
|
|
10604
|
+
{
|
|
10605
|
+
type: "button",
|
|
10606
|
+
role: "menuitem",
|
|
10607
|
+
className: "ff-editor__ctx-item ff-editor__ctx-item--danger",
|
|
10608
|
+
"data-action": "ctx-delete",
|
|
10609
|
+
onClick: () => {
|
|
10610
|
+
api.deleteNodes([menu.nodeId]);
|
|
10611
|
+
closeMenu();
|
|
10612
|
+
},
|
|
10613
|
+
children: "Delete"
|
|
10614
|
+
}
|
|
10615
|
+
)
|
|
10616
|
+
] })
|
|
10617
|
+
}
|
|
10618
|
+
),
|
|
10559
10619
|
showFeed && (slots.feed ? slots.feed(api) : /* @__PURE__ */ jsxRuntime.jsx(FlowRunFeed, { entries: runner.feed, className: "ff-editor__feed" }))
|
|
10560
10620
|
] }),
|
|
10561
10621
|
showPanel && (slots.panel ? slots.panel(api) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ff-editor__panel-wrap", children: [
|