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

@agendocerto/flow-sdk

v0.4.0

Published

A clean, type-safe abstraction layer for React Flow with centralized state management, complete event system, and command-based API

Readme

Flow SDK

A clean, type-safe abstraction layer for React Flow with centralized state management, complete event system, and command-based API.

TypeScript React Flow License

Why Flow SDK?

React Flow is powerful but low-level. Building production applications requires:

  • Manual state synchronization between React Flow and your app
  • Scattered event handlers across multiple callbacks
  • Custom TypeScript types for every operation
  • Boilerplate code for common operations

Flow SDK solves these problems with a clean architectural layer that provides:

  • ✅ Centralized state management (Zustand + Immer)
  • ✅ Complete event system (pub/sub pattern)
  • ✅ Command API (imperative operations)
  • ✅ Full TypeScript strict typing
  • ✅ SOLID principles applied

What Problems It Solves

| Problem | React Flow | Flow SDK Solution | |---------|------------|-------------------| | State Management | Manual sync required | Zustand store with automatic sync | | Event Handling | Scattered callbacks | Centralized EventBus (pub/sub) | | Type Safety | Manual type guards | Strict TypeScript with full inference | | Operations | Boilerplate for each op | Command API for all operations | | Batch Updates | Complex custom logic | Transaction system with rollback | | Testing | Mock React Flow internals | Clean interfaces, easy mocking |

Quick Start

Installation

# Install dependencies
npm install

# Build the library
npm run build

Using the Compiled Library

After building, you can import the library in your React application:

import { FlowAdapter, useFlowCommands, useFlowEvents } from '@agendocerto/flow-sdk';

🎨 Importing Styles (REQUIRED)

Flow SDK provides multiple CSS options to avoid duplication:

// ✅ Option 1: Project WITHOUT Tailwind/shadcn (easiest)
import '@agendocerto/flow-sdk/full.css';

// ✅ Option 2: Project WITH Tailwind/shadcn (recommended, smallest bundle)
import '@agendocerto/flow-sdk/base.css';
// + configure Tailwind (see docs)

// ✅ Option 3: Project WITH Tailwind, WITHOUT shadcn
import '@agendocerto/flow-sdk/base.css';
import '@agendocerto/flow-sdk/variables.css';
// + configure Tailwind (see docs)

📚 Important:

  • Don't use full.css if you already have Tailwind (avoids ~54kb duplication!)
  • See Complete Styling Guide for detailed scenarios
  • Configure tailwind.config.js when using base.css (see docs)

Note: See the Quick Start Guide for complete setup instructions including peer dependencies and configuration.

Basic Usage

import { FlowAdapter, useFlowCommands, useFlowEvents } from '@agendocerto/flow-sdk';

function App() {
  const commands = useFlowCommands();
  
  // Listen to events
  useFlowEvents('node:click', (event) => {
    console.log('Node clicked:', event.node.id);
  });

  // Execute commands
  const addNode = () => {
    commands.addNode({
      type: 'default',
      position: { x: 100, y: 100 },
      data: { label: 'New Node' }
    });
  };

  return (
    <FlowAdapter fitView showBackground showControls>
      <button onClick={addNode}>Add Node</button>
    </FlowAdapter>
  );
}

Core Concepts

1. State (Single Source of Truth)

All graph data centralized in one place: nodes, edges, selection, viewport.

import { useFlowState } from '@agendocerto/flow-sdk';

const nodes = useFlowState(state => state.nodes);
const nodeCount = useFlowState(state => state.nodes.length);

2. Commands (Imperative API)

Predictable operations with clear semantics.

const commands = useFlowCommands();

// Add
commands.addNode({...});
commands.addEdge({...});

// Update
commands.updateNode(id, {...});
commands.moveNode(id, {x, y});

// Remove
commands.removeNode(id);
commands.removeEdges([id1, id2]);

3. Events (Reactive Updates)

Subscribe to any change with a clean pub/sub system.

useFlowEvents('node:dragStop', (event) => {
  savePosition(event.node.id, event.node.position);
});

useFlowEvents('connect', (connection) => {
  console.log('Connected:', connection);
});

Key Features

  • 🔒 Type Safe - Full TypeScript strict mode with complete inference
  • ⚡ Performance - Optimized selectors, shallow equality, zero unnecessary re-renders
  • 🎯 SOLID - Clean architecture, easy to extend and maintain
  • 📡 Event-Driven - Complete pub/sub system for all React Flow events
  • 🎮 Commands - Imperative API for all graph operations
  • 💾 Transactions - Batch operations with commit/rollback support
  • 🔌 Dynamic Handles - Multiple inputs/outputs per node with automatic distribution
  • 📐 Auto Layout - ELK.js integration for automatic graph layout
  • 🎨 shadcn-ui - Modern, accessible UI components included by default

Documentation

Getting Started

API Reference

Guides

Advanced

Reference

Development & Examples

Running the Example Gallery

Run the interactive example gallery for local development:

npm run dev

This starts a development server showcasing all Flow SDK features in the Unified Control Panel example.

Available Scripts

npm run dev              # Start development server
npm run build            # Build library (ESM + CJS + types)
npm run build:lib        # Build library bundles only
npm run build:types      # Generate TypeScript declarations
npm run type-check       # Type check entire project
npm run type-check:lib   # Type check library only
npm run lint             # Run ESLint
npm run clean            # Remove build artifacts

Example Features

The Unified Control Panel demonstrates:

  • 🎮 Complete Feature Showcase - All SDK capabilities in one interface
  • 📦 Node Management - Add, remove, duplicate, and modify nodes
  • 🔗 Edge Management - Create and manage connections
  • 🔌 Dynamic Handles - Add/remove handles at runtime
  • Selection System - Box selection and batch operations
  • 📐 Auto Layout - Multiple layout algorithms (layered, force, radial)
  • 🎨 Custom Node Types - WhatsApp-style components, cards, and more
  • Transactions - Batch operations with rollback support

See example/UnifiedExample.tsx for the complete implementation.

API Quick Reference

Commands

// Nodes
addNode(node: Omit<Node, 'id'> & { id?: string }): string
removeNode(nodeId: string): void
updateNode(nodeId: string, updates: Partial<Node>): void
moveNode(nodeId: string, position: Position): void
duplicateNode(nodeId: string, offset?: Position): string

// Edges
addEdge(edge: Omit<Edge, 'id'> & { id?: string }): string
removeEdge(edgeId: string): void
updateEdge(edgeId: string, updates: Partial<Edge>): void
reconnectEdge(edgeId, newSource, newTarget, ...): void

// Handles
addInputHandle(nodeId, handleId?, label?, position?, color?): string
addOutputHandle(nodeId, handleId?, label?, position?, color?): string
removeHandle(nodeId: string, handleId: string): void

// Selection
setSelection(nodeIds: string[], edgeIds: string[]): void
addToSelection(nodeIds: string[], edgeIds: string[]): void
clearSelection(): void

// Viewport
fitView(padding?: number): void
centerNode(nodeId: string, zoom?: number): void
zoomTo(zoom: number): void
zoomIn(step?: number): void
zoomOut(step?: number): void

// Transactions
startTransaction(options?: TransactionOptions): void
commit(): CommandResult
rollback(): void

// Layout
applyAutoLayout(algorithm?, direction?, spacing?): Promise<void>

// Utility
clear(): void
reset(nodes?: Node[], edges?: Edge[]): void

→ Full API Reference

Events

// Node events
useFlowEvents('node:click', handler)
useFlowEvents('node:doubleClick', handler)
useFlowEvents('node:dragStart', handler)
useFlowEvents('node:dragStop', handler)

// Edge events
useFlowEvents('edge:click', handler)
useFlowEvents('edge:mouseEnter', handler)
useFlowEvents('edge:mouseLeave', handler)

// Connection events
useFlowEvents('connect', handler)
useFlowEvents('connect:start', handler)
useFlowEvents('connect:end', handler)

// Selection events
useFlowEvents('selection:change', handler)
useFlowEvents('selection:dragStart', handler)
useFlowEvents('selection:dragStop', handler)

// Viewport events
useFlowEvents('move:start', handler)
useFlowEvents('move:end', handler)

// Lifecycle events
useFlowEvents('init', handler)
useFlowEvents('delete', handler)

→ Full Events Reference

React Hooks

// Commands
const commands = useFlowCommands()

// State (optimized selectors)
const nodes = useFlowState(s => s.nodes)
const nodes = useFlowNodes()  // Shortcut
const edges = useFlowEdges()  // Shortcut
const selection = useFlowSelection()  // Shortcut
const viewport = useFlowViewport()  // Shortcut
const stats = useFlowStats()  // Computed stats

// Events
useFlowEvents(eventName, handler, deps?)
useFlowEventsMultiple(handlers, deps?)

→ Full Hooks Reference

Architecture Highlights

Clean Separation of Concerns

┌─────────────────────────────────────┐
│         React Components            │
│    (UI Layer - FlowAdapter)         │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│          React Hooks                │
│  (useFlowCommands, useFlowEvents)   │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│       Core Interfaces               │
│  (IGraphState, IGraphCommands)      │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│       Zustand Store                 │
│  (State + Commands + Events)        │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│       React Flow                    │
│    (Rendering Layer)                │
└─────────────────────────────────────┘

SOLID Principles

  • Single Responsibility: Each module has one clear purpose
  • Open/Closed: Extensible through events and interfaces
  • Liskov Substitution: Interfaces are fully interchangeable
  • Interface Segregation: Focused interfaces (IGraphState, IGraphCommands, IEditorEvents)
  • Dependency Inversion: Depends on abstractions, not concrete implementations

Performance

Flow SDK is optimized for zero lag and minimal re-renders:

  • Events on Completion Only - No events during continuous actions (drag, pan, zoom)
  • Shallow Equality - Default selector comparison prevents unnecessary re-renders
  • Optimized Hooks - Memoized selectors (useFlowNodes, useFlowEdges)
  • Batched Updates - RAF-based batching for position updates
  • Smart Subscriptions - Subscribe only to needed state slices

Result: 150x better performance compared to naive event handling.

Contributing

This is an internal project. For questions or suggestions, contact the development team.

Changelog

See CHANGELOG.md for version history and breaking changes.

License

Internal use only.


Built with ❤️ using React Flow, Zustand, TypeScript, and shadcn-ui