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

ucm-editor

v0.1.5

Published

Notion-like editor for UCM documents with graph visualization and diff viewing

Readme

UCM Editor

A Notion-like editor for UCM (Unified Content Model) documents with graph visualization and diff viewing capabilities.

Features

  • Block-based Editing - Notion-like vertical editing experience with inline editors
  • Drag & Drop - Reorder blocks and sections by dragging
  • Metadata Tooltips - Hover over blocks to see metadata, tags, timestamps, and edges
  • Graph View - Visual DAG representation of document structure with multiple layout algorithms
  • Diff Viewer - Compare snapshots and view/accept/reject changes
  • Keyboard Shortcuts - Full keyboard navigation and common shortcuts
  • Undo/Redo - Complete history with snapshot-based undo/redo
  • Type Support - Text, Code, Table, Math, JSON, Media content types
  • Observability - Structured logging and event system

Installation

npm install ucm-editor
# or
yarn add ucm-editor
# or
pnpm add ucm-editor

Quick Start

import { Editor } from 'ucm-editor'
import { parseMarkdown } from 'ucp-content'

// Parse a markdown document
const doc = parseMarkdown(`# Hello World

Welcome to UCM Editor!

## Features

- Block-based editing
- Graph visualization
- Diff viewing
`)

function App() {
  return (
    <Editor
      document={doc}
      onChange={(doc) => console.log('Document changed:', doc)}
    />
  )
}

Architecture

Core Modules

  • EditorStore - Central state management with observable pattern
  • SelectionManager - Block and text selection handling
  • DiffEngine - Document comparison and diff computation
  • Logger - Structured logging with levels and context

Components

  • Editor - Main container with view switching and toolbar
  • BlockRenderer - Renders blocks based on type and role
  • BlockEditor - Inline editing with auto-growing textarea
  • MetadataTooltip - Displays block metadata on hover
  • GraphView - Canvas-based graph visualization
  • DiffViewer - Side-by-side or unified diff display

API Reference

Editor Props

interface EditorProps {
  // Initial document to load
  document?: Document

  // Editor configuration
  config?: Partial<EditorConfig>

  // External store instance
  store?: EditorStoreInstance

  // Callback when document changes
  onChange?: (document: Document) => void

  // Callback when document is saved
  onSave?: (document: Document) => Promise<void>

  // Additional styling
  className?: string
  style?: React.CSSProperties
}

Editor Configuration

interface EditorConfig {
  // Maximum blocks before virtualization
  virtualizationThreshold: number  // default: 1000

  // Auto-save debounce delay (ms)
  autoSaveDelay: number            // default: 1000

  // Maximum history entries
  maxHistoryEntries: number        // default: 100

  // Enable keyboard shortcuts
  enableKeyboardShortcuts: boolean // default: true

  // Enable drag and drop
  enableDragDrop: boolean          // default: true

  // Show block IDs in UI
  showBlockIds: boolean            // default: false

  // Default graph layout
  defaultGraphLayout: GraphLayout  // default: 'hierarchical'

  // Log level
  logLevel: LogLevel               // default: 'info'
}

Using the Store Directly

import { createEditorStore } from 'ucm-editor'
import { parseMarkdown } from 'ucp-content'

const store = createEditorStore()

// Load a document
const doc = parseMarkdown('# Hello')
store.loadDocument(doc)

// Subscribe to state changes
const unsubscribe = store.subscribe((state, prevState) => {
  console.log('State changed:', state)
})

// Perform operations
store.select('blk_123')
store.startEditing('blk_123')
store.updatePendingContent('New content')
store.stopEditing(true) // save changes

// Undo/Redo
store.undo()
store.redo()

// Clean up
unsubscribe()

React Hooks

import {
  useEditorStore,
  useEditorState,
  useDocument,
  useSelection,
  useHistory,
  useBlockActions,
  useKeyboardShortcuts,
} from 'ucm-editor'

function MyComponent() {
  const store = useEditorStore()
  const document = useDocument(store)
  const { selection, isBlockSelected } = useSelection(store)
  const { canUndo, canRedo, undo, redo } = useHistory(store)
  const { addBlock, editBlock, deleteBlock } = useBlockActions(store)

  useKeyboardShortcuts(store)

  // ...
}

Error Handling

import { EditorError, Errors } from 'ucm-editor'

try {
  store.editBlock('invalid_id', 'content')
} catch (error) {
  if (error instanceof EditorError) {
    console.log('Error code:', error.code)
    console.log('Category:', error.category)
    console.log('Suggestion:', error.suggestion)
    console.log('User message:', error.toUserMessage())
  }
}

// Or use Result types
import { ok, err, unwrap } from 'ucm-editor'

function safeOperation(): Result<string, EditorError> {
  if (success) {
    return ok('result')
  }
  return err(Errors.blockNotFound('blk_123'))
}

const result = safeOperation()
if (result.ok) {
  console.log(result.value)
} else {
  console.error(result.error.message)
}

Events

import { useEditorEvent } from 'ucm-editor'

function MyComponent({ store }) {
  useEditorEvent(store, 'block:added', (event) => {
    console.log('Block added:', event.data.blockId)
  })

  useEditorEvent(store, 'document:saved', (event) => {
    console.log('Document saved:', event.data.documentId)
  })
}

Keyboard Shortcuts

| Shortcut | Action | |----------|--------| | Cmd/Ctrl + Z | Undo | | Cmd/Ctrl + Shift + Z | Redo | | Cmd/Ctrl + Y | Redo | | Cmd/Ctrl + S | Save | | Cmd/Ctrl + A | Select all | | Escape | Cancel edit / Clear selection | | Enter | Start editing selected block | | Delete/Backspace | Delete selected blocks | | ↑/↓ | Navigate blocks | | Shift + ↑/↓ | Extend selection |

Graph Layouts

  • Hierarchical - Tree layout with parent-child relationships
  • Force - Force-directed layout with physics simulation
  • Radial - Concentric circles with root at center

Views

  • Document - Block-based editing view
  • Graph - Interactive graph visualization
  • Diff - Snapshot comparison view
  • Split - Side-by-side document and graph

Development

# Install dependencies
npm install

# Run tests
npm test

# Build
npm run build

# Type check
npm run typecheck

License

MIT