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

@ankorar/nodex

v0.1.0

Published

Composable React package for building and extending a keyboard-driven mind map experience.

Readme

@ankorar/nodex

Composable React package for building and extending a keyboard-driven mind map experience.

This package exposes state, hooks, and UI primitives so each consumer app can build its own screen composition without being locked to a single page component.

What This Package Provides

  • Stateful mind map engine (Zustand-based)
  • Ready-to-compose visual components (board, nodes, minimap, popovers)
  • Keyboard and interaction handlers
  • Debounce hooks for history/state flow
  • Type exports for consumer-side extensions

Installation

Workspace (monorepo)

pnpm add @ankorar/nodex --workspace

Future npm install

pnpm add @ankorar/nodex

Quick Usage (Composition)

import "@ankorar/nodex/styles.css";
import {
  Background,
  Board,
  MindMapHeader,
  MineMap,
  Nodex,
  ZenCard,
  useMindMapDebounce,
} from "@ankorar/nodex";

export function MindMapPage() {
  useMindMapDebounce(() => undefined, { delayMs: 3000 });

  return (
    <section className="h-[calc(100dvh-11rem)] min-h-[38rem]">
      <Nodex readOnly={false}>
        <MindMapHeader title="Mind Map" />
        <Board>
          <Background />
          <MineMap />
          <ZenCard />
        </Board>
      </Nodex>
    </section>
  );
}

Read-only Mode

Use Nodex with readOnly when the map should be visual-only:

<Nodex readOnly>
  <MindMapHeader title="Mind Map (View)" />
  <Board>
    <Background />
    <MineMap />
    <ZenCard />
  </Board>
</Nodex>

In readOnly mode, the package blocks content mutations (keyboard shortcuts, inline edits, add/remove node actions, and style popover updates).

High-quality image export

You can export the whole map as a high-resolution PNG so that text stays readable when zooming, even on very large maps.

  • From the header: set showExportImageButton on MindMapHeader to show an “Export image” button that downloads a PNG (scale factor 3× by default).
  • Programmatic: use exportMindMapAsHighQualityImage(nodes, options?) with optional scale (1–4) and filename. Exported image dimensions are derived from node bounds plus padding, then multiplied by scale.
import { MindMapHeader, exportMindMapAsHighQualityImage, useMindMapState } from "@ankorar/nodex";

// In your page:
<MindMapHeader title="My Map" showExportImageButton />

// Or call manually:
const nodes = useMindMapState.getState().getFlatNodes();
await exportMindMapAsHighQualityImage(nodes, { scale: 3, filename: "my-map" });

Initial State

@ankorar/nodex now starts with an empty node list (nodes: []).

If your app loads maps from an API, hydrate the state explicitly:

import { useEffect } from "react";
import { useMindMapState, type MindMapNode } from "@ankorar/nodex";

export function MindMapHydrator({ nodes }: { nodes: MindMapNode[] }) {
  useEffect(() => {
    useMindMapState.setState({
      nodes,
      selectedNodeId: null,
      editingNodeId: null,
    });
  }, [nodes]);

  return null;
}

Custom nodes (persisted)

You can add custom node types that are stored and restored with the map.

  • Set type: "custom" and customType: string (e.g. "note") on a node. Use customPayload?: unknown for app-specific data (e.g. { noteId: "..." }).
  • These fields are part of MindMapNode and are persisted when your app saves the node tree (e.g. as content in your map API). When you load the map, pass the same tree into state so custom nodes keep their customType and customPayload.
  • Register a React component per customType via the customNodeRenderers prop on Nodex: customNodeRenderers={{ note: NoteNodeComponent }}. The component receives CustomNodeProps (node, style slots). Custom nodes are not auto-resized by layout (they keep the dimensions you set).
<Nodex customNodeRenderers={{ note: NoteNode }}>
  <Board>…</Board>
</Nodex>

Styling

@ankorar/nodex ships its own precompiled stylesheet, so consumer apps do not need to compile Tailwind classes from this package.

Import it once at app entry:

import "@ankorar/nodex/styles.css";

Public API

Components

  • Nodex (optional: customNodeRenderers, nodeEditorCustomButtons, newNodesTextColor)
  • Board
  • Background
  • Nodes
  • Segments
  • CentalNode
  • DefaultNode
  • ImageNode
  • NodeStylePopover
  • KeyboardHelpDialog
  • MineMap
  • ZenCard
  • MindMapHeader (optional: showExportImageButton for PNG export)

Utilities

  • getMindMapPreviewDataUrl(nodes) – data URL for minimap-style preview thumbnails
  • exportMindMapAsHighQualityImage(nodes, options?) – render map to high-resolution PNG and trigger download
  • HIGH_QUALITY_EXPORT_SCALE – default scale factor (3) for export

Hooks

  • useMindMapDebounce
  • useMindMapHistoryDebounce
  • useMindMapNode (for custom node components: selection, addChild, destroy, getSide)
  • useMindMapNodeMouseHandlers
  • useCustomNodeRenderers

State

  • useMindMapState
  • useMindMapHistory
  • createMindMapSnapshot

Types

  • MindMapNode (includes optional customType, customPayload for custom nodes)
  • MindMapNodeStyle
  • MindMapNodeType ("default" | "central" | "image" | "custom")
  • MindMapNodeTextAlign
  • MindMapNodeFontSize
  • CustomNodeProps, CustomNodeRenderers (for custom node components)

Package Structure

src/
  components/
    mindMap/
    ui/
  config/
  handlers/
  helpers/
  hooks/
    mindMap/
  lib/
  state/
  index.ts

Development

From the monorepo root:

pnpm --filter @ankorar/nodex dev

Available scripts in this package:

  • dev: watches types and regenerates styles.css
  • build: type validation + stylesheet build
  • lint: Type validation (tsc --noEmit)

Consumer Responsibilities

Because this package is composition-first, the consumer app is responsible for:

  • Defining the route/page shell
  • Providing app-level layout and authentication wrappers
  • Loading global styles/tokens expected by the selected UI setup

Versioning and Publishing

Before publishing a new version:

  1. Validate exports in src/index.ts.
  2. Run package checks:
    • pnpm --filter @ankorar/nodex build
    • pnpm --filter @ankorar/nodex lint
  3. Update docs for any API/behavior change.
  4. Bump package version in packages/nodex/package.json.

Documentation Policy

All package documentation must be written in English.

For mandatory documentation rules (including AI/chat workflows), see:

  • docs/AI_DOCUMENTATION_POLICY.md