nexus-fluo
v0.7.2
Published
A basic framework for building visual flow editors
Maintainers
Readme
📈 Nexus-Fluo – A React Library for Building Node-Based Editors
Nexus-Fluo is a lightweight and extensible React library for building interactive node-based editor. Whether you're crafting flowcharts, data pipelines, or visual programming interfaces, Nexus-Fluo gives you the tools to create rich, drag-and-drop node UIs effortlessly.
✨ Features
- ⚙️ Fully customizable nodes and edges
- 🔗 Interactive edge creation with connection validation
- 🧠 Built-in state management with hooks
- 🔌 Plugin architecture for future extensions
🚀 Installation
npm install nexus-fluo⚡️ Import Library
'use client';
import React from 'react';
import {Editor} from 'nexus-fluo';
import 'nexus-fluo/dist/index.css';
import nodeConfig from './nodeConfig';
import { WORKFLOW_TEMPLATES } from './workflowTemplates';
export default function MyEasyFlowPage() {
const apiEndpoint = typeof window !== 'undefined'
? `${window.location.origin}/api/run-workflow`
: '/api/run-workflow';
return (
<div style={{ height: '100vh', width: '100%', display: 'flex', flexDirection: 'column' }}>
<Editor
categories={nodeConfig}
apiEndpoint={apiEndpoint}
workflowTemplates={WORKFLOW_TEMPLATES}
/>
</div>
);
}
🧩 Node Config:
const nodeCategories = [
{
name: "API",
nodes: [
{
title: "Request",
inputs: ["url", "headers", "body", "params"],
fields: [
{
id: "method",
type: "combo",
label: "Method",
value: "GET",
options: ["GET", "POST", "PUT", "DELETE"],
},
],
outputs: ["out"],
function: "requestAPI",
file: "./app/nodes/request.js",
},
],
},
{
name: "AI",
nodes: [
{
title: "InteractAI",
inputs: ["user_prompt", "system_prompt"],
fields: [
{
id: "provider",
type: "combo",
label: "provider",
value: "openai",
options: ["openai", "gemini", "lmstudio", "ollama"],
},
{
id: "model",
type: "combosub",
parent: "provider",
label: "model",
value: "gpt-4o-mini",
options: {
openai: ["gpt-4o-mini"],
gemini: [
"gemini-2.0-flash",
"gemini-2.0-flash-lite",
"gemini-2.5-flash-preview-04-17",
],
lmstudio: ["qwen2.5-coder-3b-instruct", "qwen3-4b"],
ollama: [
"Qwen2.5-Coder-3B-Instruct-GGUF:Q4_K_M_edit",
"gemma3:4b",
],
},
},
{
id: "temperature",
type: "slider",
label: "temperature",
value: 0.5,
min: 0,
max: 1,
step: 0.01,
},
{
id: "top_p",
type: "slider",
label: "top_p",
value: 0.9,
min: 0,
max: 1,
step: 0.01,
},
{
id: "api_key",
type: "password",
label: "api_key",
value: "",
},
{
id: "api_base",
type: "text",
label: "api_base",
value: "",
},
{
id: "streaming",
type: "toggle",
label: "streaming",
value: false,
},
],
outputs: ["out"],
function: "interactAI",
file: "./app/nodes/ai.js",
},
],
},
{
name: "Automation",
nodes: [
{
title: "Selenium",
nodeType: "multifunction",
inputs: [],
outputs: ["result"],
function: "",
file: "./app/nodes/selenium.js",
fields: [
{
id: "functions",
type: "search",
label: "",
value: "",
options: [
{
function: "open_browser",
label: "Open Browser",
argument: {
url: "",
browser: ["", "chrome", "firefox", "edge"],
},
on_error: ["stop", "skip"],
},
{
function: "input_text",
label: "Input Text",
argument: { locator: "", value: "" },
on_error: ["stop", "skip"],
},
{
function: "click_element",
label: "Click Element",
argument: { locator: "" },
on_error: ["stop", "skip"],
},
{
function: "sleep",
label: "Sleep",
argument: { second: 1 },
on_error: ["stop", "skip"],
},
{
function: "get_value",
label: "Get Value",
argument: { locator: "", attribute: "" },
return: { variable: "ret" },
on_error: ["stop", "skip"],
},
{
function: "wait_element_visible",
label: "Wait Element Visible",
argument: { locator: "", timeout: 5 },
on_error: ["stop", "skip"],
},
],
},
{
id: "arguments",
type: "function_arguments",
label: "arguments",
value: []
}
],
},
],
},
{
name: "Input",
nodes: [
{
title: "Array",
nodeType: "array",
inputs: [],
outputs: ["out"],
initialFields: [{ value: "Input 1" }, { value: "Input 2" }],
},
{
title: "Boolean",
inputs: [],
fields: [
{
id: "toggle1",
type: "toggle",
label: "",
value: true,
},
],
outputs: ["out"],
},
{
title: "Dictionary",
nodeType: "dictionary",
inputs: [],
initialFields: [
{ key: "field1", value: "Input 1" },
{ key: "field2", value: "Input 2" },
],
outputs: ["out"],
},
{
title: "Dropdown",
inputs: [],
fields: [
{
id: "combo1",
type: "combo",
label: "",
value: "red",
options: ["red", "green", "blue"],
},
],
outputs: ["out"],
},
{
title: "DropdownFilter",
inputs: [],
fields: [
{
id: "category",
type: "combo",
label: "category",
value: "color",
options: ["color", "carbrand", "animal"],
},
{
id: "subcategory",
type: "combosub",
parent: "category",
label: "subcategory",
value: "red",
options: {
color: ["red", "green", "blue"],
carbrand: ["toyota", "honda", "suzuki"],
animal: ["cat", "dog", "capybara"],
},
},
],
outputs: ["out"],
},
{
title: "JSON",
outputs: ["out"],
fields: [
{
id: "jsonData",
type: "json",
label: "JSON Data",
value: "{}",
},
],
},
{
title: "Number",
inputs: [],
fields: [
{
id: "number1",
type: "number",
label: "",
value: 1,
min: -99999,
max: 99999,
step: 1,
},
],
outputs: ["out"],
},
{
title: "Password",
inputs: [],
fields: [
{
id: "pass1",
type: "password",
label: "",
value: "",
},
],
outputs: ["out"],
},
{
title: "Slider",
inputs: [],
fields: [
{
id: "slider1",
type: "slider",
label: "",
value: 0.5,
min: 0,
max: 1,
step: 0.01,
outputPort: "out",
},
],
outputs: ["out"],
},
{
title: "Text",
inputs: [],
fields: [
{
id: "text1",
type: "text",
label: "",
value: "",
},
],
outputs: ["out"],
},
{
title: "TextArea",
inputs: [],
fields: [
{
id: "textarea1",
type: "textarea",
label: "",
value: "",
},
],
outputs: ["out"],
},
{
title: "TextareaSelection",
inputs: [],
outputs: ["out"],
fields: [
{
id: "pattern",
type: "textareaselection",
label: "path",
value: "",
options: [
{ name: "status", value: "$.status" },
{ name: "statusText", value: "$.statusText" },
{ name: "data (full array)", value: "$.data" },
{ name: "first item", value: "$.data[0]" },
{ name: "first name", value: "$.data[0].name" },
{ name: "first email", value: "$.data[0].email" },
{ name: "last item", value: "$.data[-1]" },
{ name: "last name", value: "$.data[-1].name" },
{ name: "all names", value: "$.data[*].name" },
{ name: "all emails", value: "$.data[*].email" },
],
},
],
},
{
title: "TextboxSelection",
inputs: [],
fields: [
{
id: "pattern",
type: "textboxselection",
label: "pattern",
value: "",
options: [
{
name: "email",
value: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}",
},
{ name: "phone", value: "\\+?[1-9]\\d{1,14}" },
],
},
],
outputs: ["out"],
},
],
},
{
name: "JSON",
nodes: [
{
title: "Get Json Value",
inputs: ["json_data"],
outputs: ["out"],
function: "getJsonValue",
file: "./app/nodes/json.js",
fields: [
{
id: "json_path",
type: "textareaselection",
label: "path",
value: "",
options: [
{ name: "status", value: "$.status" },
{ name: "statusText", value: "$.statusText" },
{ name: "data (full array)", value: "$.data" },
{ name: "first item", value: "$.data[0]" },
{ name: "first name", value: "$.data[0].name" },
{ name: "first email", value: "$.data[0].email" },
{ name: "last item", value: "$.data[-1]" },
{ name: "last name", value: "$.data[-1].name" },
{ name: "all names", value: "$.data[*].name" },
{ name: "all emails", value: "$.data[*].email" },
],
},
],
},
{
title: "Update Json Multiple",
inputs: ["json_data"],
outputs: ["out"],
function: "updateJsonMultiple",
file: "./app/nodes/json.js",
fields: [
{
id: "data_replace",
type: "json",
label: "data_replace",
value: "{}",
},
],
},
],
},
{
name: "Math",
nodes: [
{
title: "Add",
inputs: ["A", "B"],
outputs: ["out"],
function: "logicADD",
file: "./app/nodes/math.js",
},
{
title: "Subtract",
inputs: ["A", "B"],
outputs: ["out"],
function: "logicSubtract",
file: "./app/nodes/math.js",
},
{
title: "Multiply",
inputs: ["A", "B"],
outputs: ["out"],
function: "logicMultiply",
file: "./app/nodes/math.js",
},
{
title: "Divide",
inputs: ["A", "B"],
outputs: ["out"],
function: "logicDivide",
file: "./app/nodes/math.js",
},
],
},
{
name: "Report",
nodes: [{ title: "Console", inputs: ["value"], outputs: [] },{ title: "HTML", inputs: ["value"], outputs: [] }],
},
{
name: "String",
nodes: [
{
title: "GetRegexp",
inputs: ["string"],
outputs: ["out"],
function: "getRegexp",
file: "./app/nodes/string.js",
fields: [
{
id: "pattern",
type: "textboxselection",
label: "pattern",
value: "",
options: [
{ name: "char", value: "[abc]" },
{ name: "char except", value: "[^abc]" },
{ name: "char range", value: "[a-z]" },
{ name: "any", value: "." },
{ name: "or", value: "a|b" },
{ name: "space", value: "\\s" },
{ name: "digit", value: "\\d" },
{ name: "any word", value: "\\w" },
{
name: "email",
value: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}",
},
{ name: "phone", value: "\\+?[1-9]\\d{1,10}" },
],
},
],
},
{
title: "Replace",
inputs: ["string"],
outputs: ["out"],
function: "replaceString",
file: "./app/nodes/string.js",
fields: [
{
id: "search_for",
type: "text",
label: "search_for",
value: "",
},
{
id: "replace_with",
type: "text",
label: "replace_with",
value: "",
},
],
},
{
title: "ReplaceRegexp",
inputs: ["string"],
outputs: ["out"],
function: "replaceRegexp",
file: "./app/nodes/string.js",
fields: [
{
id: "pattern",
type: "textboxselection",
label: "pattern",
value: "",
options: [
{ name: "char", value: "[abc]" },
{ name: "char except", value: "[^abc]" },
{ name: "char range", value: "[a-z]" },
{ name: "any", value: "." },
{ name: "or", value: "a|b" },
{ name: "space", value: "\\s" },
{ name: "digit", value: "\\d" },
{ name: "any word", value: "\\w" },
{
name: "email",
value: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}",
},
{ name: "phone", value: "\\+?[1-9]\\d{1,10}" },
],
},
{
id: "replace_with",
type: "text",
label: "replace_with",
value: "",
},
],
},
{
title: "Remove",
inputs: ["string"],
outputs: ["out"],
function: "removeString",
file: "./app/nodes/string.js",
fields: [
{
id: "removables",
type: "text",
label: "removables",
value: "",
},
],
},
{
title: "RemoveRegexp",
inputs: ["string"],
outputs: ["out"],
function: "removeRegexp",
file: "./app/nodes/string.js",
fields: [
{
id: "pattern",
type: "textboxselection",
label: "pattern",
value: "",
options: [
{ name: "char", value: "[abc]" },
{ name: "char except", value: "[^abc]" },
{ name: "char range", value: "[a-z]" },
{ name: "any", value: "." },
{ name: "or", value: "a|b" },
{ name: "space", value: "\\s" },
{ name: "digit", value: "\\d" },
{ name: "any word", value: "\\w" },
{
name: "email",
value: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}",
},
{ name: "phone", value: "\\+?[1-9]\\d{1,10}" },
],
},
],
},
{
title: "Split",
inputs: ["string"],
outputs: ["out"],
function: "splitString",
file: "./app/nodes/string.js",
fields: [
{
id: "separator",
type: "text",
label: "separator",
value: "",
},
],
},
{
title: "Substring",
inputs: ["string"],
outputs: ["out"],
function: "subString",
file: "./app/nodes/string.js",
fields: [
{
id: "start",
type: "number",
label: "start",
value: 0,
min: -99999,
max: 99999,
step: 1,
},
{
id: "end",
type: "number",
label: "end",
value: 0,
min: -99999,
max: 99999,
step: 1,
},
],
},
],
}
];
export default nodeCategories;
