ClipMind
Workspace
Contact UsIf you have any questions, feel free to reach out at neo@clipmind.tech.

@clipmind/mindmap

A React-based mind map component with multiple layout strategies, theming support, and rich node features.

Installation

BASH
npm install @clipmind/mindmap
# or
yarn add @clipmind/mindmap
# or
pnpm add @clipmind/mindmap

Peer Dependencies

Make sure you have the following peer dependencies installed:

BASH
npm install react react-dom mobx mobx-react styled-components slate slate-react slate-history

Quick Start

TYPESCRIPT
import { useEffect, useState } from 'react';
import { MindMapEditor, generateStore, loadFromMarkdown } from '@clipmind/mindmap';
import styled from 'styled-components';
import type { MindMapStore } from '@clipmind/mindmap';

const Container = styled.div`
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
`;

export function MindmapDemo() {
  const [store, setStore] = useState<MindMapStore | null>(null);

  useEffect(() => {
    // generateStore is async to ensure fonts are loaded before layout calculation
    generateStore().then(s =>  {
      loadFromMarkdown('# Hello World\n\n## Item 1\n### Item 1.1\n## Item 2', s);
      setStore(s);
    } );
  }, []);

  if (!store) {
    return (
      <Container>{'Loading...'}</Container>
    );
  }

  return (
      <Container>
        <MindMapEditor store={store} />
      </Container>
  );
}

Features

  • 6 Layout Types: MindMap, Logic, Organization, Timeline, Tree, and Fishbone
  • 50+ Color Themes: Light and dark themes with customization support
  • Rich Nodes: Text, images, markers, checkboxes, and boundaries
  • Export: SVG, PNG, JPG, and PDF export capabilities
  • Undo/Redo: Full history management
  • Markdown Import: Load mind maps from markdown text
  • Serialization: Save and restore mind map state

Store Initialization

Use generateStore to create a properly initialized MindMapStore. This function is async to ensure fonts are fully loaded before layout calculations, preventing text truncation issues.

TYPESCRIPT
import { generateStore } from '@clipmind/mindmap';

// Basic usage
const store = await generateStore();

// With custom font
const store = await generateStore({ fontFamily: 'Inter' });

GenerateStoreOptions

OptionTypeDefaultDescription
fontFamilystring'Lexend'

Google Font to use for node text

Supported Fonts

The following Google Fonts are supported:

Lexend, Roboto, Open Sans, Lato, Montserrat, Oswald, Source Sans Pro, Raleway, PT Sans, Merriweather, Inter, Roboto Mono, Fira Code, JetBrains Mono, Poppins, Quicksand, Playfair Display, Lora, Pacifico, Dancing Script


Data Import from Markdown

You can import mind map data from markdown text using the loadFromMarkdown function.

Fetching Markdown from ClipMind API

Use the ClipMind API to generate markdown from any text input.

Get your API Token: Visit API Docs to obtain your API token.

BASH
curl -X POST https://api.clipmind.tech/public/mindmaps/markdown \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
    "text": "My MindMap\n- Idea 1\n- Idea 2",
    "options": {
      "mode": "summarize",
      "language": "english",
      "length": "medium"
    }
  }'

Loading Markdown into Store

TYPESCRIPT
import { loadFromMarkdown, generateStore } from '@clipmind/mindmap';

// Create store (async to ensure fonts are loaded)
const store = await generateStore();

// Fetch markdown from ClipMind API
const response = await fetch('https://api.clipmind.tech/public/mindmaps/markdown', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${YOUR_API_TOKEN}`,
  },
  body: JSON.stringify({
    text: 'React 入门指南',
    options: {
      mode: 'summarize',
      language: 'chinese',
      length: 'medium',
    },
  }),
});

const { data } = await response.json();

// Load markdown into store
loadFromMarkdown(data, store);

Manual Markdown Input

You can also load markdown directly without using the API:

TYPESCRIPT
const markdown = `# React 入门指南
## 核心概念
- JSX 语法
- 组件化开发
  - 函数组件
  - 类组件
## Hooks
- useState
- useEffect
- useContext`;

loadFromMarkdown(markdown, store);

Markdown Format

The parser supports the following markdown syntax:

MARKDOWN
# Central Topic
## Branch 1
- Item 1.1
- Item 1.2
-- Sub-item 1.2.1
## Branch 2
- Item 2.1

Heading levels:

  • # → Root node (level 1)
  • ## → First-level branches (level 2)
  • ### → Second-level branches (level 3)

List items:

  • - → Child node
  • -- → Grandchild node
  • --- → Great-grandchild node
  • Indentation also affects level: - Item (2 spaces = deeper level)

Images in Markdown

Include images with optional dimensions:

MARKDOWN
# My Mind Map
## ![logo](https://example.com/logo.png){100x80} Brand
- ![icon](https://example.com/icon.png) Feature 1

Supported dimension formats:

  • {100x80} - width x height
  • {width=100 height=80} - explicit attributes
  • {width=100} - width only
  • {100} - width only (shorthand)

Metadata Preservation

Export with convertMindMapToMarkdownWithMetadata preserves node styles:

MARKDOWN
# Central Topic
## Branch 1

<!-- clipmind-metadata
{"version":"cm-md/1","nodes":[{"shape":"rounded"},{"markers":["star"]}]}
-->

Serialization / Deserialization

Save and restore mind map state for persistence:

TYPESCRIPT
// Save to localStorage
const data = await store.serialize();
localStorage.setItem('mindmap', JSON.stringify(data));

// Restore from localStorage
const saved = localStorage.getItem('mindmap');
if (saved) {
  store.deserialize(JSON.parse(saved));
}

IMindMapData Structure

TYPESCRIPT
interface IMindMapData {
  id: string;
  rootNode: IMindMapNode;
  theme: string;                    // Color theme ID
  layout: {
    type: ILayoutType;              // 'mindmap' | 'logic' | 'org' | 'timeline' | 'tree' | 'fishbone'
    theme: string;                  // Layout theme ID
  };
  resource?: IMindMapResource;      // Images and other resources
  createdAt?: string;
  updatedAt?: string;
}

Node Operations

Adding Nodes

TYPESCRIPT
// Add a child node
store.addChildNode({
  title: 'New Child',
  parentId: 'root',           // Parent node ID
  enableScrollToNode: true,   // Auto-scroll to new node
});

// Add a sibling node (same level as specified node)
store.addSiblingNode('node-id');

// Get the ID of the last added child
const newNodeId = store.getLastChildNodeId('parent-id');

Deleting Nodes

TYPESCRIPT
// Delete single node
store.deleteNodes(['node-id']);

// Delete multiple nodes
store.deleteNodes(['node-1', 'node-2', 'node-3']);

// Note: Root node ('root') cannot be deleted

Modifying Nodes

TYPESCRIPT
// Set node text
store.setNodeText('node-id', 'New Title');

// Set node text without saving to history
store.setNodeText('node-id', 'New Title', false);

// Update node image
store.updateNodeImage('node-id', {
  src: 'https://example.com/image.png',
  alt: 'Description',
  box: { x: 0, y: 0, w: 100, h: 80 }
});

Node Selection

TYPESCRIPT
// Select a node
store.setSelectedNodes(['node-id']);

// Get selected nodes
const selected = store.selectedNodes;

// Clear selection
store.setSelectedNodes([]);

Node Features

Markers

Add icon markers to nodes:

TYPESCRIPT
// Available markers: 'star', 'heart', 'flag', 'check', 'cross', 'question', etc.
store.addMarker('node-id', 'star');
store.removeMarker('node-id', 'star');

Checkboxes

Add todo checkboxes to nodes:

TYPESCRIPT
store.setNodeCheckbox('node-id', {
  checked: false,
  shape: 'square'  // 'square' | 'circle' | 'diamond'
});

// Toggle checkbox
store.toggleNodeCheckbox('node-id');

Boundaries

Add visual boundaries around node groups:

TYPESCRIPT
store.setNodeBoundary('node-id', {
  enabled: true,
  style: 'rounded',  // 'rounded' | 'square' | 'wave'
  color: '#ff6b35'
});

Custom Styles

Apply custom styles to individual nodes:

TYPESCRIPT
store.setNodeCustomStyle('node-id', {
  backgroundColor: '#ff6b35',
  textColor: '#ffffff',
  fontSize: 16,
  fontWeight: 'bold'
});

Undo / Redo

TYPESCRIPT
// Check if operations are available
const canUndo = store.canUndo();
const canRedo = store.canRedo();

// Perform undo/redo
store.undo();
store.redo();

Image Export

SVG Export

TYPESCRIPT
store.saveSvg({
  isCopy: false,           // Copy to clipboard instead of download
  exportCheckbox: true,    // Include checkbox visuals
  sealConfig: {            // Optional watermark
    style: 'corner',
    text: 'My Brand'
  }
});

PNG Export

TYPESCRIPT
store.savePng({
  scale: 2,                        // Export scale (1-4)
  transparentBackground: false,    // Transparent or themed background
  isCopy: false,                   // Copy to clipboard
  exportCheckbox: true,
  targetWidth: 1920,               // Optional fixed width
  targetHeight: 1080               // Optional fixed height
});

JPG Export

TYPESCRIPT
store.saveJpg({
  scale: 2,
  exportCheckbox: true,
  targetWidth: 1920,
  targetHeight: 1080
});

PDF Export

TYPESCRIPT
store.savePdf({
  scale: 2,
  transparentBackground: false,
  exportCheckbox: true
});

Preview Generation

TYPESCRIPT
// Get PNG as data URL (for thumbnails, previews)
const dataUrl = await store.savePngPreview({
  scale: 1,
  transparentBackground: false
});

Layout Types

TYPESCRIPT
// Set layout type and theme
store.setLayout('mindmap', 'mindmap-underline');
store.setLayout('logic', 'logic-minimal');
store.setLayout('org', 'org-corporate');
store.setLayout('timeline', 'timeline-default');
store.setLayout('tree', 'tree-trunk');
store.setLayout('fishbone', 'fishbone-classic');

Available Layout Themes

Layout TypeAvailable Themes
mindmapmindmap-underline, mindmap-modern, mindmap-organic, mindmap-creative
logiclogic-underline, logic-underline-stack, logic-minimal, logic-minimal-circle, logic-modern
orgorg-corporate, org-modern
timelinetimeline-default, timeline-axis, timeline-horizontal
treetree-trunk, tree-structure
fishbonefishbone-classic, fishbone-modern

Color Themes

Light Themes

TYPESCRIPT
import {
  irisTheme,
  neonTheme,
  amethystTheme,
  sunsetTheme,
  oceanTheme,
  forestTheme,
  cherryBlossomTheme,
  volcanoTheme,
  hermesOrangeTheme,
  tiffanyBlueTheme,
  rainbowTheme,
  premiumBlackGrayTheme,
  roseGoldTheme,
  deepSeaTheme,
  lavenderTheme,
  champagneTheme,
  midnightBlueTheme,
  emeraldTheme,
  chinaRedTheme,
  frenchFlagTheme,
  germanFlagTheme,
  americanFlagTheme,
  japaneseFlagTheme,
  roseTheme,
  slateTheme,
  goldTheme,
  cyanTheme,
  indigoTheme,
} from '@clipmind/mindmap';

Dark Themes

TYPESCRIPT
import {
  darkIrisTheme,
  darkNeonTheme,
  darkAmethystTheme,
  darkSunsetTheme,
  darkOceanTheme,
  darkForestTheme,
  darkCherryBlossomTheme,
  darkVolcanoTheme,
  darkHermesOrangeTheme,
  darkTiffanyBlueTheme,
  darkRainbowTheme,
  darkPremiumBlackGrayTheme,
  darkRoseGoldTheme,
  darkDeepSeaTheme,
  darkLavenderTheme,
  darkChampagneTheme,
  darkMidnightBlueTheme,
  darkEmeraldTheme,
  darkChinaRedTheme,
  darkFrenchFlagTheme,
  darkGermanFlagTheme,
  darkAmericanFlagTheme,
  darkJapaneseFlagTheme,
  darkRoseTheme,
  darkSlateTheme,
  darkGoldTheme,
  darkCyanTheme,
  darkIndigoTheme,
} from '@clipmind/mindmap';

Theme Utilities

TYPESCRIPT
import { AVAILABLE_THEMES, LIGHT_THEMES, DARK_THEMES } from '@clipmind/mindmap';

// Get all themes
console.log(AVAILABLE_THEMES.length); // 56 themes

// Apply a theme
store.colorTheme = darkNeonTheme;

// Reset node colors after theme change
store.resetNodeThemes();

Canvas Operations

TYPESCRIPT
// Fit mind map to screen
store.canvas.fitToScreen();

// Zoom controls
store.canvas.zoomIn();
store.canvas.zoomOut();
store.canvas.setScale(1.5);

// Get current view state
const view = store.canvas.getView();
// { x: number, y: number, scale: number }

Complete Example: ClipMind API Integration

Get your API Token: Visit API Docs to obtain your API token.

TYPESCRIPT
import { useState, useEffect } from 'react';
import {
  MindMapStore,
  MindMapEditor,
  generateStore,
  loadFromMarkdown,
} from '@clipmind/mindmap';

// Get your token from https://clipmind.tech/workspace
const API_TOKEN = 'your-api-token';

function MindMapDemo() {
  const [store, setStore] = useState<MindMapStore | null>(null);

  useEffect(() => {
    // generateStore is async to ensure fonts are loaded before layout calculation
    generateStore().then(setStore);
  }, []);

  const handleGenerateFromAPI = async () => {
    if (!store) return;

    const response = await fetch('https://api.clipmind.tech/public/mindmaps/markdown', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_TOKEN}`,
      },
      body: JSON.stringify({
        text: 'React 入门指南',
        options: {
          mode: 'brainstorm',
          language: 'chinese',
          length: 'medium',
        },
      }),
    });

    const { data } = await response.json();
    loadFromMarkdown(data, store);
  };

  const handleExport = () => {
    store?.savePng({ scale: 2 });
  };

  const handleSave = async () => {
    if (!store) return;
    const data = await store.serialize();
    localStorage.setItem('mindmap', JSON.stringify(data));
  };

  const handleLoad = () => {
    const saved = localStorage.getItem('mindmap');
    if (saved && store) {
      store.deserialize(JSON.parse(saved));
    }
  };

  if (!store) {
    return <div>Loading...</div>;
  }

  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <MindMapEditor store={store} />
      <div style={{ display: 'flex', justifyContent: 'center', position: 'absolute', top: 80, left: '50%', transform: 'translateX(-50%)', gap: 16 }}>
        <button onClick={handleGenerateFromAPI}>Generate from API</button>
        <button onClick={handleExport}>Export PNG</button>
        <button onClick={handleSave}>Save</button>
        <button onClick={handleLoad}>Load</button>
      </div>
    </div>
  );
}