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

@clipmind/mindmap

v1.0.7

Published

A React-based mind map component with multiple layout strategies

Readme

@clipmind/mindmap

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

Installation

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:

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

Quick Start

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.

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

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

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

GenerateStoreOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | fontFamily | string | '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.

curl -X POST https://api.clipmind.com/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

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.com/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:

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

loadFromMarkdown(markdown, store);

Markdown Format

The parser supports the following markdown syntax:

# 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:

# 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:

# 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:

// 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

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

// 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

// 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

// 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

// 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:

// 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:

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

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

Boundaries

Add visual boundaries around node groups:

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

Custom Styles

Apply custom styles to individual nodes:

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

Undo / Redo

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

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

Image Export

SVG Export

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

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

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

PDF Export

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

Preview Generation

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

Layout Types

// 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 Type | Available Themes | |-------------|------------------| | mindmap | mindmap-underline, mindmap-modern, mindmap-organic, mindmap-creative | | logic | logic-underline, logic-underline-stack, logic-minimal, logic-minimal-circle, logic-modern | | org | org-corporate, org-modern | | timeline | timeline-default, timeline-axis, timeline-horizontal | | tree | tree-trunk, tree-structure | | fishbone | fishbone-classic, fishbone-modern |


Color Themes

Light Themes

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

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

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

// 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.

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.com/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>
  );
}