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

@molecule/app-mind-map-canvas-react

v1.0.1

Published

React mind-map canvas — tree-structured nodes with parent/child links, automatic radial/horizontal/vertical tree layout, fold/unfold subtrees, inline edit-on-double-click; thin domain wrapper over @molecule/app-feature-canvas-react.

Downloads

139

Readme

@molecule/app-mind-map-canvas-react

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

React mind-map canvas — thin domain wrapper over the shared canvas base. Tree-structured nodes (parent/child links), automatic radial / horizontal / vertical tree layout, fold/unfold subtrees, inline edit-on-double-click, +/- toggles to add and collapse children.

Pan / zoom is delegated to <CanvasSurface> from @molecule/app-feature-canvas-react. This package owns only the mind-map domain semantics — adding mechanics that live above the pan/zoom-and-paint base.

Exports:

  • <MindMapCanvas> — top-level widget; controlled or uncontrolled.
  • MindMapNode, MindMapLayout, MindMapLayoutResult types.
  • Pure layout helpers: computeRadialPositions, computeHorizontalTreePositions, layout knobs + defaults.
  • Pure tree mutators: findNode, updateNode, setNodeText, toggleCollapsed, addChild, removeNode.

Quick Start

import { useState } from 'react'

import { MindMapCanvas, type MindMapNode } from '@molecule/app-mind-map-canvas-react'

function Demo() {
  const [root, setRoot] = useState<MindMapNode>({
    id: 'r',
    text: 'Project',
    children: [
      { id: 'a', text: 'Plan', children: [] },
      { id: 'b', text: 'Build', children: [] },
    ],
  })
  return <MindMapCanvas root={root} onChange={setRoot} layout="radial" />
}

Type

feature

Installation

npm install @molecule/app-mind-map-canvas-react @molecule/app-feature-canvas-react @molecule/app-react @molecule/app-ui react
npm install -D @types/react

API

Interfaces

LayoutOptions

Per-layout knobs (all optional).

interface LayoutOptions {
  /** Node width in canvas units. */
  nodeWidth?: number
  /** Node height in canvas units. */
  nodeHeight?: number
  /** Distance between concentric rings (radial layout). */
  ringSpacing?: number
  /** Horizontal step between generations (horizontal/vertical layout). */
  stepX?: number
  /** Vertical step between sibling subtrees (horizontal layout). */
  stepY?: number
  /** Origin in canvas-space for the root node's center. Defaults to `(0, 0)`. */
  origin?: Point
}

MindMapCanvasProps

<MindMapCanvas> props.

interface MindMapCanvasProps {
  /**
   * Root of the mind-map tree. The canvas is fully-controlled when
   * `onChange` is supplied; otherwise the component manages its own
   * mirror via `useState`.
   */
  root: MindMapNode
  /**
   * Optional change callback. When provided, the canvas runs in
   * controlled mode — every fold/edit/add-child mutation calls
   * `onChange(nextRoot)` and the parent decides whether to commit.
   */
  onChange?: (next: MindMapNode) => void
  /** Layout strategy. Defaults to `'radial'`. */
  layout?: MindMapLayout
  /** Width of the surface in CSS pixels. Defaults to `800`. */
  width?: number
  /** Height of the surface in CSS pixels. Defaults to `600`. */
  height?: number
  /** Node width in canvas units. Defaults to {@link DEFAULT_NODE_WIDTH}. */
  nodeWidth?: number
  /** Node height in canvas units. Defaults to {@link DEFAULT_NODE_HEIGHT}. */
  nodeHeight?: number
  /** Fired when a node is clicked (single click, no drag). */
  onNodeClick?: (node: MindMapNode) => void
  /**
   * Fired when a node's text is committed via inline edit. Receives the
   * node id and the new text. Useful for analytics / autosave.
   */
  onNodeEdit?: (id: string, text: string) => void
  /** Extra classes merged onto the outer wrapper. */
  className?: string
}

MindMapLayoutResult

Result of a layout computation: a flat map of nodeId → canvas-space top-left position, plus the parent/child pairs that should be drawn as edges (in tree order, parents first). Collapsed subtrees are omitted.

interface MindMapLayoutResult {
  /** Map of `nodeId` → canvas-space top-left position. */
  positions: Map<string, Point>
  /** Parent/child id pairs to draw as edges. */
  edges: Array<{ parentId: string; childId: string }>
  /** Flat list of nodes that should be rendered (i.e. not hidden by a collapsed ancestor). */
  visibleNodes: MindMapNode[]
}

MindMapNode

One mind-map node. Every node is the root of its own subtree (the top-level node passed as root is just the outermost example).

interface MindMapNode {
  /** Stable identifier — must be unique across the entire tree. */
  id: string
  /** Display text shown in the node's body. */
  text: string
  /** Direct child subtrees, rendered in array order. */
  children: MindMapNode[]
  /**
   * If `true`, the node renders without its descendants — the subtree
   * is effectively hidden until expanded. Defaults to `false`.
   */
  collapsed?: boolean
  /**
   * Optional accent color (CSS color string). Used as the inline
   * border-left accent on the node body; ClassMap drives the rest of
   * the chrome.
   */
  color?: string
}

Types

MindMapLayout

Layout strategies <MindMapCanvas> knows how to compute.

type MindMapLayout = 'radial' | 'horizontal' | 'vertical'

Functions

addChild(root, parentId, child)

Append a child to the node with the given id. The new child is pushed at the end of the children array. If the parent is currently collapsed, it is automatically expanded so the new child is visible.

function addChild(root: MindMapNode, parentId: string, child: MindMapNode): MindMapNode
  • root — Tree root.
  • parentId — Id of the parent that will receive the new child.
  • child — The child node to append.

Returns: A new tree with the child appended (and the parent expanded).

computeHorizontalTreePositions(root, options, axis)

Horizontal tidy-tree layout: root on the left, children fan out to the right, each subtree's children stacked vertically with enough room for every leaf descendant. The axis option swaps the role of the X and Y axes for a vertical (top-down) tree.

function computeHorizontalTreePositions(
  root: MindMapNode,
  options?: LayoutOptions,
  axis?: 'horizontal' | 'vertical',
): MindMapLayoutResult
  • root — Tree root.
  • options — Optional layout knobs.
  • axis'horizontal' (default) places generations along +X; 'vertical' places generations along +Y.

Returns: Layout result with positions, edges, and the visible-node list.

computeRadialPositions(root, options)

Radial layout: root at origin, children fan out around it at uniform angles, each generation living on its own concentric ring. For deeper generations the angular slice of each child is its parent's slice divided by the parent's child count.

function computeRadialPositions(root: MindMapNode, options?: LayoutOptions): MindMapLayoutResult
  • root — Tree root.
  • options — Optional layout knobs.

Returns: Layout result with positions, edges, and the visible-node list.

findNode(root, id)

Walk the tree and find the node with the given id, returning a pointer-style reference (not a clone). Used internally by the other helpers — exported because it's also handy at call sites.

function findNode(root: MindMapNode, id: string): MindMapNode | null
  • root — Tree root.
  • id — Id of the node to locate.

Returns: The node, or null if no node has that id.

MindMapCanvas(props)

Mind-map canvas — a thin domain wrapper over @molecule/app-feature-canvas-react. Composes <CanvasSurface> for pan/zoom, <CanvasNode> for each tree node, and <CanvasEdge kind="bezier"> for parent → child links. Domain-specific behavior lives here, not in the base:

  • Auto-layout — radial / horizontal / vertical positions are computed from the tree shape via the pure helpers in ./layout.js.
  • Fold / unfold — the +/- toggle on a non-leaf node flips collapsed, hiding (or revealing) the entire subtree.
  • Inline edit — double-click any node body to enter an inline <input>; commit on Enter / blur, cancel on Escape.
  • Add child — the + button on every node appends a new child ("New idea") and auto-expands the parent.

Pan / zoom is owned by <CanvasSurface>; this wrapper never re-implements those mechanics.

Style is driven by getClassMap(). Inline styles are reserved for canvas-space geometry and the optional accent border.

function MindMapCanvas(props: MindMapCanvasProps): JSX.Element
  • props — Component props.

Returns: The mind-map canvas element.

removeNode(root, id)

Remove the node with the given id (and its entire subtree) from the tree. The root itself cannot be removed — passing the root id is a no-op that returns the original tree.

function removeNode(root: MindMapNode, id: string): MindMapNode
  • root — Tree root.
  • id — Id of the node to remove.

Returns: A new tree with the node removed, or the original tree if id matches the root.

setNodeText(root, id, text)

Set a node's text.

function setNodeText(root: MindMapNode, id: string, text: string): MindMapNode
  • root — Tree root.
  • id — Id of the node to edit.
  • text — New text content.

Returns: A new tree with the node's text updated.

toggleCollapsed(root, id)

Toggle a node's collapsed flag.

function toggleCollapsed(root: MindMapNode, id: string): MindMapNode
  • root — Tree root.
  • id — Id of the node to toggle.

Returns: A new tree with the node's collapsed flag flipped.

updateNode(root, id, updater)

Apply a transformation to the node with the given id, returning a new tree where every ancestor of the touched node has been re-cloned so React-style reference equality remains correct on unchanged subtrees.

function updateNode(
  root: MindMapNode,
  id: string,
  updater: (node: MindMapNode) => MindMapNode,
): MindMapNode
  • root — Tree root.
  • id — Id of the node to update.
  • updater — Function that returns the replacement node.

Returns: A new tree, or the original if id was not found.

walkVisible(root, visit)

Walk the tree and call visit(node, parent | null, depth) for every node not hidden by a collapsed ancestor. Visits in pre-order.

function walkVisible(
  root: MindMapNode,
  visit: (node: MindMapNode, parent: MindMapNode | null, depth: number) => void,
): void
  • root — Tree root.
  • visit — Callback invoked once per visible node.

Constants

DEFAULT_HORIZONTAL_STEP_X

Default horizontal tree per-generation step in canvas units.

const DEFAULT_HORIZONTAL_STEP_X: 220

DEFAULT_HORIZONTAL_STEP_Y

Default horizontal tree per-leaf step in canvas units.

const DEFAULT_HORIZONTAL_STEP_Y: 72

DEFAULT_NODE_HEIGHT

Default canvas-space height of one node.

const DEFAULT_NODE_HEIGHT: 48

DEFAULT_NODE_WIDTH

Default canvas-space size of one node, used to space siblings.

const DEFAULT_NODE_WIDTH: 160

DEFAULT_RADIAL_RING

Default radial ring spacing in canvas units.

const DEFAULT_RADIAL_RING: 180

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-feature-canvas-react ^1.0.1
  • @molecule/app-react ^1.0.1
  • @molecule/app-ui ^1.0.1
  • react ^18.0.0 || ^19.0.0

Runtime Dependencies

  • @molecule/app-feature-canvas-react
  • @molecule/app-react
  • @molecule/app-ui
  • react

Requires a wired ClassMap bond (setClassMap(...) at startup) and a React I18nProvider ancestor — getClassMap() and useTranslation() both throw before wiring. Pair with the companion locale bond @molecule/app-locales-mind-map-canvas for translated aria labels and the "New idea" default child text (English fallbacks otherwise).

The surface is FIXED-SIZE: width / height are pixel props (default 800x600) — the canvas does not track its parent's size. To fill a panel, measure the parent (e.g. a resize observer) and pass the measured pixels down; CSS alone will clip, not resize.

Supplying onChange makes the tree fully controlled (every fold / edit / add-child calls it with the next root); omitting it lets the canvas manage an internal copy seeded from root.

Translations

Translation strings are provided by @molecule/app-locales-mind-map-canvas.