npm package: @gongfu/flowgram
Description: A powerful flow diagram SDK for building visual workflow editors
Author: Kongfu Team
Latest version: 0.2.0

# @kongfu/flowgram

A powerful and flexible flow diagram SDK for building visual workflow editors. Built on top of React Flow with additional features for workflow management.

[![npm version](https://img.shields.io/npm/v/@kongfu/flowgram.svg)](https://www.npmjs.com/package/@kongfu/flowgram)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- 🎨 **Rich Node Types** - Start, End, Task, Decision, Parallel, Subprocess nodes
- 🔧 **Drag & Drop** - Intuitive node creation and connection
- 📐 **Auto Layout** - Automatic graph layout with dagre
- ✅ **Validation** - Built-in flow validation with error/warning display
- 🎯 **Context Menus** - Right-click menus for nodes, edges, and canvas
- 💾 **Import/Export** - Support for JSON, SVG, PNG formats
- 🌍 **i18n Support** - English and Chinese localization
- 🎭 **Customizable** - Custom nodes, edges, themes, and behaviors
- ⚡ **Performance** - Optimized for large graphs with virtualization

## Installation

```bash
npm install @kongfu/flowgram
# or
yarn add @kongfu/flowgram
# or
pnpm add @kongfu/flowgram
```

## Quick Start

```tsx
import { Flowgram } from '@kongfu/flowgram';
import '@kongfu/flowgram/styles.css';

function App() {
  const handleSave = async (flow) => {
    console.log('Saving flow:', flow);
    // Save to your backend
  };

  return (
    <div style={{ height: '600px' }}>
      <Flowgram
        onSave={handleSave}
        locale="en"
      />
    </div>
  );
}
```

## Advanced Usage

### With Initial Flow

```tsx
const initialFlow = {
  nodes: [
    {
      id: '1',
      type: 'start',
      position: { x: 100, y: 100 },
      data: { label: 'Start' },
    },
    {
      id: '2',
      type: 'task',
      position: { x: 300, y: 100 },
      data: { 
        label: 'Process Data',
        status: 'in-progress',
        progress: 60,
        assignee: 'John Doe'
      },
    },
    {
      id: '3',
      type: 'end',
      position: { x: 500, y: 100 },
      data: { label: 'End' },
    },
  ],
  edges: [
    { id: 'e1-2', source: '1', target: '2' },
    { id: 'e2-3', source: '2', target: '3' },
  ],
};

<Flowgram
  initialFlow={initialFlow}
  showMinimap={true}
  showControls={true}
  onSave={handleSave}
/>
```

### Custom Node Types

```tsx
import { BaseNode } from '@kongfu/flowgram';

const CustomNode = (props) => {
  return (
    <BaseNode
      {...props}
      style={{ backgroundColor: '#e0f2fe' }}
    >
      <div>Custom Content</div>
    </BaseNode>
  );
};

<Flowgram
  nodeTypes={{
    custom: CustomNode,
  }}
/>
```

### Context Menus

```tsx
const contextMenu = {
  node: [
    {
      id: 'edit',
      label: 'Edit Node',
      icon: <EditIcon />,
      action: (node) => {
        console.log('Edit node:', node);
      },
    },
    {
      id: 'delete',
      label: 'Delete Node',
      icon: <DeleteIcon />,
      action: (node) => {
        // Delete node
      },
    },
  ],
  pane: [
    {
      id: 'add-task',
      label: 'Add Task',
      action: () => {
        // Add new task node
      },
    },
  ],
};

<Flowgram
  contextMenu={contextMenu}
/>
```

### Validation Rules

```tsx
const validation = {
  rules: [
    {
      id: 'no-orphans',
      name: 'No Orphan Nodes',
      validate: (flow) => {
        const errors = [];
        flow.nodes.forEach(node => {
          const hasConnection = flow.edges.some(
            edge => edge.source === node.id || edge.target === node.id
          );
          if (!hasConnection) {
            errors.push({
              nodeId: node.id,
              message: `Node "${node.data.label}" is not connected`,
              type: 'error',
            });
          }
        });
        return { valid: errors.length === 0, errors };
      },
    },
  ],
  validateOnChange: true,
  showErrors: true,
};

<Flowgram
  validation={validation}
/>
```

### Using the Store

```tsx
import { useFlowgramStore } from '@kongfu/flowgram';

function FlowControls() {
  const { 
    nodes,
    edges,
    addNode,
    deleteNode,
    autoLayout,
    validate,
    exportFlow,
  } = useFlowgramStore();

  const handleAddTask = () => {
    addNode({
      id: `task-${Date.now()}`,
      type: 'task',
      position: { x: 200, y: 200 },
      data: { label: 'New Task' },
    });
  };

  const handleAutoLayout = () => {
    autoLayout({ direction: 'TB' });
  };

  const handleExport = () => {
    exportFlow({ format: 'json' });
  };

  return (
    <div>
      <button onClick={handleAddTask}>Add Task</button>
      <button onClick={handleAutoLayout}>Auto Layout</button>
      <button onClick={handleExport}>Export</button>
    </div>
  );
}
```

## API Reference

### Flowgram Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `initialFlow` | `FlowData` | - | Initial flow data |
| `mode` | `'light' \| 'dark'` | `'light'` | Color mode |
| `readOnly` | `boolean` | `false` | Disable editing |
| `showGrid` | `boolean` | `true` | Show background grid |
| `showMinimap` | `boolean` | `true` | Show minimap |
| `showControls` | `boolean` | `true` | Show zoom controls |
| `snapToGrid` | `boolean` | `true` | Snap nodes to grid |
| `gridSize` | `number` | `20` | Grid size in pixels |
| `nodeTypes` | `Record<string, Component>` | - | Custom node types |
| `edgeTypes` | `Record<string, Component>` | - | Custom edge types |
| `theme` | `FlowgramTheme` | - | Custom theme |
| `locale` | `'en' \| 'zh-CN'` | `'en'` | UI language |
| `toolbar` | `ToolbarConfig` | - | Toolbar configuration |
| `contextMenu` | `ContextMenuConfig` | - | Context menu configuration |
| `validation` | `ValidationConfig` | - | Validation configuration |
| `onSave` | `(flow: FlowData) => void` | - | Save callback |
| `onNodeClick` | `(event, node) => void` | - | Node click handler |
| `onEdgeClick` | `(event, edge) => void` | - | Edge click handler |
| `onConnect` | `(connection) => void` | - | Connection handler |
| `onDelete` | `(elements) => void` | - | Delete handler |

### Node Types

#### Task Node
```typescript
{
  type: 'task',
  data: {
    label: string;
    status?: 'pending' | 'in-progress' | 'completed' | 'failed';
    progress?: number; // 0-100
    assignee?: string;
  }
}
```

#### Decision Node
```typescript
{
  type: 'decision',
  data: {
    label: string;
    conditions?: Array<{
      id: string;
      label: string;
      expression?: string;
    }>;
  }
}
```

#### Parallel Node
```typescript
{
  type: 'parallel',
  data: {
    label: string;
    branches?: number;
    joinType?: 'all' | 'any' | 'custom';
  }
}
```

## Theming

```tsx
const theme = {
  primaryColor: '#3b82f6',
  backgroundColor: '#ffffff',
  gridColor: '#e5e5e5',
  nodeBackgroundColor: '#f9fafb',
  nodeTextColor: '#111827',
  nodeBorderColor: '#e5e7eb',
  edgeColor: '#9ca3af',
  selectedColor: '#3b82f6',
  errorColor: '#ef4444',
  successColor: '#10b981',
};

<Flowgram theme={theme} />
```

## Layout Options

```tsx
const layoutOptions = {
  direction: 'TB', // TB, BT, LR, RL
  spacing: {
    nodeWidth: 180,
    nodeHeight: 80,
    horizontalSpacing: 100,
    verticalSpacing: 100,
  },
  algorithm: 'dagre', // dagre, elk, custom
};

// Use with store
const { autoLayout } = useFlowgramStore();
autoLayout(layoutOptions);
```

## Export Formats

```typescript
// JSON export
exportFlow({ format: 'json', filename: 'my-flow.json' });

// SVG export (coming soon)
exportFlow({ format: 'svg', filename: 'my-flow.svg' });

// PNG export (coming soon)
exportFlow({ 
  format: 'png', 
  filename: 'my-flow.png',
  quality: 0.9,
  background: '#ffffff',
});
```

## Browser Support

- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)

## Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

## License

MIT © Kongfu Team