sweet-diagram
v0.4.7
Published
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
Downloads
29
Maintainers
Readme
🍠 Sweet Diagram
현대적이고 직관적인 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

✨ 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-diagramStep 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 zustandWe 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 providerBox- Basic diagram box with text supportConnector- Connection lines between componentsDraggableBox- Draggable box componentArrow- Arrow shapes and indicatorsLine- Simple line connectionsTriangle- Triangle shapesValve- Valve indicatorsImageBox- 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
