Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

sweet-diagram

KoreaMoney30MIT0.4.7TypeScript support: included

A modern and intuitive diagram editor component for React applications with advanced auto-connect features, Sankey diagrams, Stack functionality, vertical text support, animation effects, and comprehensive component library

react, diagram, editor, visualization, sweet-diagram, javascript, auto-connect, animation, vertical-text, drag-drop, component-library, interactive-diagram, typescript, modern-ui, sankey-diagram, stack-layout, flow-diagram, junction-points, undo-redo, history-management, json-import-export

readme

🍠 Sweet Diagram

npm version Downloads License: MIT React

현대적이고 직관적인 React 다이어그램 에디터 컴포넌트 with advanced auto-connect features, Sankey diagrams, Stack functionality, vertical text support, animation effects, and comprehensive component library.

🌐 Live Demo: https://sweetpotato-diagram.vercel.app

Sweet Diagram Preview

✨ Key Features

  • 🎯 Complete Diagram Solution - Box, Connector, Arrow, Triangle, Valve, Line, ImageBox components
  • 🌊 Sankey Diagrams - Interactive flow diagrams with proportional connections and JSON import/export
  • 📚 Stack Layout System - Automatic stacking with priority-based positioning
  • 🔄 Auto-Connect - Intelligent connection system with multiple algorithms
  • 🔗 Junction Points - Advanced connection points for complex diagram layouts
  • ↩️ Undo/Redo System - Complete history management with keyboard shortcuts (Ctrl+Z/Ctrl+Y)
  • 📝 Vertical Text Support - Both horizontal and vertical text orientations
  • 🎨 Modern Styling - Built with TailwindCSS for beautiful designs
  • 🖱️ Interactive & Draggable - Full mouse and touch support
  • High Performance - Optimized for large diagrams
  • 🎭 Animation Support - Smooth transitions and effects
  • 📱 Responsive Design - Works on all screen sizes
  • 🔧 TypeScript Ready - Full type definitions included
  • 🎪 Zero Config - Works out of the box

🚀 Quick Installation & Usage

Step 1: Install Package

# NPM으로 설치
npm install sweet-diagram

# 또는 Yarn으로 설치
yarn add sweet-diagram

# 또는 PNPM으로 설치
pnpm add sweet-diagram

Step 2: Install Required Dependencies

Sweet Diagram uses peer dependencies for better flexibility:

# React (required)
npm install react react-dom

# TailwindCSS (highly recommended for styling)
npm install tailwindcss

# Additional peer dependencies (if using advanced features)
npm install @react-three/drei @react-three/fiber three lucide-react zustand

We moved heavy dependencies to peer dependencies to give you:

  • Flexibility - Use your preferred versions
  • Smaller bundle - Avoid duplicate dependencies
  • Better performance - Shared dependencies across your app

Step 3: Import CSS & Components

import React from "react";
import { DiagramProvider, Box, Connector, Sankey, Triangle, Valve } from "sweet-diagram";
import "sweet-diagram/dist/sweet-diagram.css";

function MyApp() {
  return (
    <div className="w-full h-full">
      <DiagramProvider width={800} height={600}>
        <Box
          id="box1"
          x={100}
          y={100}
          width={120}
          height={80}
          text="시작점"
          className="bg-blue-500 text-white rounded-lg"
        />

        <Box
          id="box2"
          x={300}
          y={200}
          width={120}
          height={80}
          text="끝점"
          className="bg-green-500 text-white rounded-lg"
        />

        <Connector
          fromBox={{ id: "box1", position: "right" }}
          toBox={{ id: "box2", position: "left" }}
          connectionType="straight"
          showArrow={true}
        />
      </DiagramProvider>
    </div>
  );
}

export default MyApp;

🌊 Sankey Diagram Usage

import React from "react";
import { Sankey } from "sweet-diagram";
import "sweet-diagram/dist/sweet-diagram.css";

function SankeyExample() {
  const data = {
    nodes: [
      { id: "A", name: "소스 A", layer: 0 },
      { id: "B", name: "소스 B", layer: 0 },
      { id: "C", name: "중간 처리", layer: 1 },
      { id: "D", name: "최종 결과", layer: 2 },
    ],
    links: [
      { id: "link1", source: "A", target: "C", value: 30 },
      { id: "link2", source: "B", target: "C", value: 20 },
      { id: "link3", source: "C", target: "D", value: 50 },
    ],
  };

  return (
    <div className="w-full h-96">
      <Sankey data={data} width={600} height={400} className="mx-auto border rounded-lg" />
    </div>
  );
}

Sankey with JSON Import/Export

import React, { useState } from "react";
import { Sankey } from "sweet-diagram";

function SankeyWithImport() {
  const [sankeyData, setSankeyData] = useState(null);

  const handleImportJSON = (file) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      try {
        const data = JSON.parse(e.target.result);
        setSankeyData(data);
      } catch (error) {
        console.error("Invalid JSON file:", error);
      }
    };
    reader.readAsText(file);
  };

  const handleExportJSON = () => {
    if (sankeyData) {
      const blob = new Blob([JSON.stringify(sankeyData, null, 2)], {
        type: "application/json",
      });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "sankey-data.json";
      a.click();
      URL.revokeObjectURL(url);
    }
  };

  return (
    <div>
      <input type="file" accept=".json" onChange={(e) => handleImportJSON(e.target.files[0])} />
      <button onClick={handleExportJSON}>Export JSON</button>
      {sankeyData && <Sankey data={sankeyData} width={600} height={400} />}
    </div>
  );
}

🔗 Junction Points Usage

import React from "react";
import { DiagramProvider, Box, Connector, Junction } from "sweet-diagram";

function JunctionExample() {
  return (
    <DiagramProvider width={800} height={600}>
      <Box id="input1" x={50} y={100} width={100} height={60} text="Input 1" />
      <Box id="input2" x={50} y={200} width={100} height={60} text="Input 2" />
      <Box id="output" x={600} y={150} width={100} height={60} text="Output" />

      {/* Junction Point for merging connections */}
      <Junction id="junction1" x={400} y={150} size={8} className="fill-red-500 stroke-red-700" />

      {/* Connections to junction */}
      <Connector fromBox={{ id: "input1" }} toBox={{ id: "junction1" }} connectionType="orthogonal" />
      <Connector fromBox={{ id: "input2" }} toBox={{ id: "junction1" }} connectionType="orthogonal" />

      {/* Connection from junction to output */}
      <Connector fromBox={{ id: "junction1" }} toBox={{ id: "output" }} connectionType="straight" />
    </DiagramProvider>
  );
}

↩️ Undo/Redo System Usage

import React from "react";
import { DiagramProvider, DraggableBox, UndoRedoButtons, useDiagram } from "sweet-diagram";

function UndoRedoExample() {
  const DebugInfo = () => {
    const { getDiagramStats } = useDiagram();
    const stats = getDiagramStats();

    return (
      <div className="absolute top-4 left-4 bg-white p-3 rounded shadow">
        <div>Undo 가능: {stats.canUndo ? "✅" : "❌"}</div>
        <div>Redo 가능: {stats.canRedo ? "✅" : "❌"}</div>
        <div>히스토리: {stats.historyIndex + 1}개</div>
      </div>
    );
  };

  return (
    <DiagramProvider width={800} height={600}>
      {/* Draggable boxes that support undo/redo */}
      <DraggableBox
        id="box1"
        initialX={100}
        initialY={100}
        width={120}
        height={80}
        title="드래그해보세요"
        color="blue"
      />

      <DraggableBox id="box2" initialX={300} initialY={200} width={120} height={80} title="박스 2" color="green" />

      {/* Undo/Redo Buttons with various styles */}
      <UndoRedoButtons position="top-right" variant="gradient" showLabels={true} enableKeyboardShortcuts={true} />

      {/* Custom styled undo/redo buttons */}
      <UndoRedoButtons
        position="bottom-right"
        customStyle={{
          undo: "bg-red-500 hover:bg-red-600 text-white shadow-lg rounded-full",
          redo: "bg-green-500 hover:bg-green-600 text-white shadow-lg rounded-full",
        }}
        customLabels={{ undo: "되돌리기", redo: "앞으로" }}
      />

      <DebugInfo />
    </DiagramProvider>
  );
}

🎯 Full Example

import React from "react";
import {
  DiagramProvider,
  Box,
  Connector,
  DraggableBox,
  Triangle,
  Valve,
  Arrow,
  Line,
  ImageBox,
  Sankey,
  useDiagram,
} from "sweet-diagram";

function MyDiagram() {
  return (
    <div className="w-full h-full absolute">
      <DiagramProvider width={800} height={600}>
        <Box
          id="box1"
          x={100}
          y={100}
          width={120}
          height={80}
          text="Start Point"
          className="bg-blue-500 text-white border-blue-600 border-2 rounded-lg"
          onClick={(event, data) => console.log("Box clicked:", data)}
        />

        <Box
          id="box2"
          x={300}
          y={200}
          width={120}
          height={80}
          text="End Point"
          className="bg-green-500 text-white border-green-600 border-2 rounded-lg"
        />

        {/* Vertical Text Box */}
        <Box
          id="vertical-box"
          x={500}
          y={100}
          width={60}
          height={120}
          text="Vertical Text"
          textDirection="vertical"
          verticalDirection="lr"
          className="bg-purple-500 text-white border-purple-600 border-2 rounded-lg"
        />

        <Connector
          fromBox={{ id: "box1", position: "right" }}
          toBox={{ id: "box2", position: "left" }}
          connectionType="straight"
          arrowDirection="forward"
          strokeWidth={3}
          className="text-black"
          animated={true}
        />

        <DraggableBox
          id="draggable1"
          initialX={500}
          initialY={100}
          width={100}
          height={60}
          title="Draggable"
          color="purple"
          onDrag={(position) => console.log("New position:", position)}
        />

        <Triangle x={200} y={300} size={30} color="#ff6b6b" onClick={() => console.log("Triangle clicked")} />

        <Valve x={400} y={150} size={25} isOpen={true} onClick={() => console.log("Valve clicked")} />
      </DiagramProvider>
    </div>
  );
}

export default MyDiagram;

🔧 Available Components

Core Components

  • DiagramProvider - Main context provider
  • Box - Basic diagram box with text support
  • Connector - Connection lines between components
  • DraggableBox - Draggable box component
  • Arrow - Arrow shapes and indicators
  • Line - Simple line connections
  • Triangle - Triangle shapes
  • Valve - Valve indicators
  • ImageBox - Image containers

🆕 New in v0.4.6

  • Sankey - Flow diagrams with proportional node heights
  • Stack Layout - Automatic box stacking with priority system

Hooks

  • useDiagram - Access diagram context and state

📦 Package.json Configuration

Make sure your package.json includes:

{
  "dependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "sweet-diagram": "^0.4.6"
  },
  "peerDependencies": {
    "tailwindcss": "^3.0.0"
  }
}

🎨 TailwindCSS Integration

Sweet Diagram is designed to work perfectly with TailwindCSS. Add this to your tailwind.config.js:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}", "./node_modules/sweet-diagram/**/*.{js,jsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

📚 Documentation

Visit our comprehensive documentation for:

  • 📖 Complete API reference
  • 🎯 Interactive examples
  • 🎨 Styling guides
  • ⚡ Performance tips
  • 🛠️ Advanced usage patterns

🧪 TypeScript Support

Full TypeScript definitions are included:

import { BoxProps, ConnectorProps, SankeyData, DiagramContextType } from "sweet-diagram";

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

MIT License - see LICENSE file for details.

🌟 Show Your Support

Give us a ⭐️ if this project helped you!


Made with ❤️ by the Sweet Diagram Team