npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@netlisian/dynamic-functions

v0.0.0

Published

A **Blender-inspired visual programming interface** for creating dynamic data transformations. Build complex transformation pipelines using an intuitive node-based editor powered by React Flow.

Readme

Dynamic Function Package

A Blender-inspired visual programming interface for creating dynamic data transformations. Build complex transformation pipelines using an intuitive node-based editor powered by React Flow.

🎨 NEW: React Flow Visual Programming System

📚 Legacy Rete.js Documentation:

Features

Visual Programming (React Flow)

  • 🎨 Blender-Inspired Design: Professional dark theme with color-coded sockets
  • 🔌 Smart Connections: Type-safe socket connections with visual feedback
  • 📦 50+ Pre-built Operations: Arithmetic, logical, string, array, and object operations
  • 🎯 Drag & Drop: Intuitive node creation from sidebar
  • 💾 Serializable Graphs: Save and load complete graph state
  • ⚡ Runtime Execution: Convert visual graphs to executable functions
  • 🔍 Input Fields: Edit values directly in unconnected input sockets
  • 🎭 Three Node Types:
    • Source Nodes: Data input with configurable paths
    • Transform Nodes: Operation nodes for data transformation
    • Destination Nodes: Data output targets

Legacy Rete.js Support

  • Visual Node Editor: Built with Rete.js for intuitive visual programming
  • Three Node Types:
    • From Nodes: Input fields that provide values to the transform function
    • Operator Nodes: Processing nodes for transformations (math, logic, string operations)
    • To Nodes: Output fields that receive transformed values
  • Built-in Operators:
    • Math: Add, Subtract, Multiply, Divide, Modulo, Power
    • Logic: AND, OR, NOT, Equals, Not Equals, Greater/Less Than
    • String: Concat, Uppercase, Lowercase, Trim, Split, Join, Replace, Substring
  • Real-time Validation: Detects circular dependencies and validates connections
  • TypeScript Support: Fully typed API with Puck integration

Installation

pnpm add @netlisian/dynamic-functions

Quick Start (React Flow)

import { DynamicFunctionModal } from '@netlisian/dynamic-functions';
import '@xyflow/react/dist/style.css';

function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);
  const [mappings, setMappings] = useState([]);

  return (
    <>
      <button onClick={() => setIsOpen(true)}>
        Open Visual Editor
      </button>

      <DynamicFunctionModal
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        fromOptions={[
          { label: 'First Name', value: 'user.firstName' },
          { label: 'Last Name', value: 'user.lastName' },
        ]}
        toOptions={[
          { label: 'Full Name', value: 'profile.fullName' },
        ]}
        value={mappings}
        onChange={setMappings}
      />
    </>
  );
}

See the Quick Start Guide for a complete tutorial.

Usage (Legacy Rete.js)

Simple Editor (Getting Started)

For learning and testing, use the SimpleEditor which follows official Rete.js patterns:

import { SimpleEditorTest } from "@netlisian/dynamic-functions";
import "@netlisian/dynamic-functions/dist/styles.css";

function App() {
  return (
    <div>
      <h1>Simple Rete.js Editor</h1>
      <SimpleEditorTest />
    </div>
  );
}

Or create your own editor programmatically:

import { SimpleEditor, createNumberNode, createAddNode } from "@netlisian/dynamic-functions";
import { ClassicPreset } from "rete";

function MyCustomEditor() {
  const containerRef = useRef<HTMLDivElement>(null);
  const editorRef = useRef<SimpleEditor | null>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const initEditor = async () => {
      const editor = new SimpleEditor(containerRef.current!);
      
      // Add nodes
      const num1 = createNumberNode(5);
      const num2 = createNumberNode(10);
      const add = createAddNode();
      
      await editor.addNode(num1, { x: 50, y: 100 });
      await editor.addNode(num2, { x: 50, y: 250 });
      await editor.addNode(add, { x: 350, y: 170 });
      
      // Connect nodes
      await editor.addConnection(
        new ClassicPreset.Connection(num1, "value", add, "left")
      );
      
      await editor.zoomToFit();
      editorRef.current = editor;
    };

    initEditor();

    return () => {
      if (editorRef.current) {
        editorRef.current.destroy();
      }
    };
  }, []);

  return <div ref={containerRef} style={{ width: "100%", height: "600px" }} />;
}

Basic Example

import { DynamicFunctionModal } from "@netlisian/dynamic-functions/puck";
import "@netlisian/dynamic-functions/dist/styles.css";

function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);
  const [mappings, setMappings] = useState([]);

  const fromOptions = [
    { label: "First Name", value: "firstName", type: "text" },
    { label: "Last Name", value: "lastName", type: "text" },
    { label: "Age", value: "age", type: "number" },
  ];

  const toOptions = [
    { label: "Full Name", value: "fullName", type: "text" },
    { label: "Display Name", value: "displayName", type: "text" },
  ];

  return (
    <>
      <button onClick={() => setIsOpen(true)}>
        Open Function Editor
      </button>

      <DynamicFunctionModal
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        fromOptions={fromOptions}
        toOptions={toOptions}
        value={mappings}
        onChange={setMappings}
      />
    </>
  );
}

With Puck (SoftConfig)

The package integrates seamlessly with the SoftConfig system:

import { SoftConfigProvider } from "@netlisian/softconfig/puck";
import { DynamicFunctionModal } from "@netlisian/dynamic-functions/puck";

<SoftConfigProvider
  hardConfig={config}
  softComponents={softComponents}
  overrides={{
    map: (props) => {
      const [isModalOpen, setIsModalOpen] = useState(false);

      return (
        <div>
          <button onClick={() => setIsModalOpen(true)}>
            Configure Transform
          </button>

          <DynamicFunctionModal
            isOpen={isModalOpen}
            onClose={() => setIsModalOpen(false)}
            fromOptions={props.fromOptions}
            toOptions={props.toOptions}
            value={props.value || []}
            onChange={props.onChange}
          />
        </div>
      );
    },
  }}
>
  {/* Your Puck editor */}
</SoftConfigProvider>

API Reference

DynamicFunctionModal

The main component for the visual function editor.

Props

  • isOpen: boolean - Controls modal visibility
  • onClose: () => void - Callback when modal closes
  • fromOptions: Array<{ label: string; value: string; type: FieldType }> - Available input fields
  • toOptions: Array<{ label: string; value: string; type: FieldType }> - Available output fields
  • value?: MapConfig[] - Current transformation mappings
  • onChange: (value: MapConfig[]) => void - Callback when mappings change
  • currentIndex?: number - Index of current mapping being edited (default: 0)

MapConfig

Configuration for a single transformation:

type MapConfig = {
  from: string | string[];
  to: string | string[];
  transform?: TransformFunction;
};

type TransformFunction = (values: any[], props: any) => any;

FieldType

Supported Puck field types:

type FieldType =
  | "text"
  | "textarea"
  | "number"
  | "select"
  | "radio"
  | "external"
  | "custom"
  | "array";

How It Works

  1. Add Input Nodes: Click fields from the "Input Fields" sidebar to add "From" nodes
  2. Add Operator Nodes: Choose operators from Math, Logic, or String categories
  3. Add Output Nodes: Add "To" nodes from the "Output Fields" sidebar
  4. Connect Nodes: Drag from output ports to input ports to create connections
  5. Save Transform: Click "Save Transform" to generate the transformation function

The editor automatically:

  • Validates connections between nodes
  • Generates executable transformation functions
  • Handles multiple inputs/outputs
  • Detects circular dependencies
  • Orders execution using topological sort

Operator Categories

Math Operators

  • Add (+): Adds two numbers
  • Subtract (-): Subtracts second from first
  • Multiply (×): Multiplies two numbers
  • Divide (÷): Divides first by second
  • Modulo (%): Returns remainder
  • Power (^): Raises first to power of second

Logic Operators

  • AND: Logical AND of two booleans
  • OR: Logical OR of two booleans
  • NOT: Logical NOT of a boolean
  • Equals (==): Checks equality
  • Not Equals (!=): Checks inequality
  • Greater Than (>): Numeric comparison
  • Less Than (<): Numeric comparison
  • Greater or Equal (≥): Numeric comparison
  • Less or Equal (≤): Numeric comparison

String Operators

  • Concatenate: Joins two strings
  • Uppercase: Converts to uppercase
  • Lowercase: Converts to lowercase
  • Trim: Removes whitespace
  • Split: Splits string by separator
  • Join: Joins array with separator
  • Replace: Replaces text in string
  • Substring: Extracts substring

Architecture

dynamic-function/
├── src/
│   ├── types.ts              # TypeScript type definitions
│   ├── operators.ts          # Operator definitions and implementations
│   ├── nodes.ts              # Node class definitions
│   ├── editor.ts             # Core editor logic and function generation
│   ├── components/
│   │   ├── Modal.tsx         # Generic modal component
│   │   └── DynamicFunctionModal.tsx  # Main editor modal
│   ├── puck/
│   │   └── index.tsx         # Puck-specific exports
│   └── styles.css            # Component styles

Advanced Usage

Custom Operators

You can extend the operator set by modifying operators.ts:

export const operators: Record<OperatorType, OperatorDefinition> = {
  // ... existing operators
  customOp: {
    type: "customOp",
    label: "Custom Operation",
    inputs: 2,
    category: "math",
    execute: (a: number, b: number) => {
      // Your custom logic
      return a * 2 + b;
    },
  },
};

Programmatic Editor Access

import { createDynamicFunctionEditor } from "@netlisian/dynamic-functions";

const editor = await createDynamicFunctionEditor(containerElement);

// Add nodes programmatically
await editor.addNode(someNode, { x: 100, y: 100 });

// Generate config
const config = editor.generateMapConfig();

// Clean up
editor.destroy();

Browser Compatibility

  • Chrome/Edge: ✅ Full support
  • Firefox: ✅ Full support
  • Safari: ✅ Full support
  • IE11: ❌ Not supported

Dependencies

  • rete: Node editor framework
  • rete-area-plugin: Area management
  • rete-connection-plugin: Connection handling
  • rete-react-plugin: React rendering
  • lucide-react: Icons
  • @measured/puck: Puck integration (peer dependency)

License

MIT