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

@type-editor/viewdesc

v0.0.3

Published

Type Editor - ViewDesc Module

Readme

@type-editor/viewdesc

A refactored version of ProseMirror's view description system, providing the core rendering engine that maintains a parallel tree structure between the document model and the DOM representation.

Installation

npm install @type-editor/viewdesc

Overview

The ViewDesc (View Description) system is the internal rendering layer that powers the Type Editor view. It creates and maintains a tree of descriptor objects that:

  • Mirror the document structure: Each document node has a corresponding ViewDesc
  • Manage DOM nodes: Create, update, and destroy DOM elements efficiently
  • Apply decorations: Render visual enhancements without modifying the document
  • Map positions: Convert between document positions and DOM coordinates
  • Handle updates: Incrementally update the DOM when the document changes
  • Support custom rendering: Allow developers to override node rendering

ViewDesc operates as an abstraction layer between the editor's document state and the browser's DOM, enabling efficient updates and sophisticated rendering capabilities.

Core Concepts

The Parallel Tree Structure

Type Editor maintains two parallel trees:

Document Tree (Model)          ViewDesc Tree                  DOM Tree
─────────────────────          ─────────────                  ────────
    doc                            DocViewDesc                   <div>
     │                                  │                          │
     ├─ paragraph                   NodeViewDesc               <p>
     │   └─ "Hello"                 └─ TextViewDesc            └─ "Hello"
     │
     ├─ blockquote                  NodeViewDesc               <blockquote>
     │   └─ paragraph               └─ NodeViewDesc            └─ <p>
     │       └─ "World"                 └─ TextViewDesc            └─ "World"

Each ViewDesc maintains:

  • References to its DOM node(s)
  • Knowledge of its document position
  • Information about decorations
  • Links to parent and child ViewDescs

ViewDesc Types

The system includes several specialized ViewDesc types:

  • NodeViewDesc: Represents document nodes (paragraphs, headings, lists, etc.)
  • TextViewDesc: Represents text content within nodes
  • MarkViewDesc: Represents inline marks (bold, italic, links)
  • WidgetViewDesc: Represents decoration widgets (placeholders, UI elements)
  • CustomNodeViewDesc: Represents user-defined custom node views
  • CompositionViewDesc: Handles IME composition for complex text input
  • TrailingHackViewDesc: Browser-specific compatibility fixes

Key Components

ViewDesc (Base Class)

The foundation class providing core functionality:

import { ViewDesc } from '@type-editor/viewdesc';

// ViewDesc properties
viewDesc.dom              // The DOM node
viewDesc.contentDOM       // Where children are rendered
viewDesc.parent           // Parent ViewDesc
viewDesc.children         // Child ViewDescs
viewDesc.dirty            // Dirty state tracking
viewDesc.node             // Associated ProseMirror node

// Position mapping
const pos = viewDesc.posBeforeChild(childDesc);
const domPos = viewDesc.domFromPos(10, 1);
const docPos = viewDesc.localPosFromDOM(domNode, offset, bias);

// Lifecycle
viewDesc.destroy();
viewDesc.markDirty(from, to);

NodeViewDesc

Represents actual document nodes with full support for decorations:

import { NodeViewDesc } from '@type-editor/viewdesc';

// NodeViewDesc properties
nodeViewDesc.node         // The ProseMirror node
nodeViewDesc.outerDeco    // Decorations wrapping the node
nodeViewDesc.innerDeco    // Decorations inside the node
nodeViewDesc.nodeDOM      // The node's primary DOM element
nodeViewDesc.size         // Node size in the document
nodeViewDesc.border       // Border size (0 for leaves, 1 for blocks)

// Node matching for efficient updates
const matches = nodeViewDesc.matchesNode(node, outerDeco, innerDeco);

// Apply decorations
const decoratedDOM = NodeViewDesc.applyOuterDeco(dom, decorations, node);

TextViewDesc

Represents text nodes with special handling for text content:

import { TextViewDesc } from '@type-editor/viewdesc';

// TextViewDesc wraps text DOM nodes
const textDesc = new TextViewDesc(parent, node, outerDeco, innerDeco, dom);

// Efficiently updates text content
textDesc.node = newTextNode;

MarkViewDesc

Represents inline marks that wrap text or other content:

import { MarkViewDesc } from '@type-editor/viewdesc';

// MarkViewDesc wraps content with mark styling
const markDesc = new MarkViewDesc(parent, mark, dom, contentDOM);

// Marks are layered - a bold italic link would have three MarkViewDescs

CustomNodeViewDesc

Used when developers provide custom node views:

import { CustomNodeViewDesc } from '@type-editor/viewdesc';

// Created automatically when using custom node views
const customDesc = new CustomNodeViewDesc(
    parent, 
    node, 
    outerDeco, 
    innerDeco, 
    dom, 
    contentDOM, 
    nodeDOM,
    nodeView,  // The custom node view object
    view,
    getPos
);

Working with ViewDescs

Creating the View Tree

ViewDescs are typically created internally by the editor view:

import { docViewDesc } from '@type-editor/viewdesc';

// Creates the root ViewDesc tree
const docView = docViewDesc(
    state.doc,        // Document
    outerDeco,        // Outer decorations
    innerDeco,        // Inner decorations
    containerDOM,     // Container element
    editorView        // View instance
);

Updating ViewDescs

The ViewDescUpdater handles incremental updates:

import { ViewDescUpdater } from '@type-editor/viewdesc';

// Attempts to update the existing tree
const updated = ViewDescUpdater.update(
    viewDesc,
    editorView,
    newNode,
    outerDeco,
    innerDeco
);

if (!updated) {
    // Full redraw needed
    viewDesc.destroy();
    viewDesc = createNewViewDesc();
}

Position Mapping

Convert between document positions and DOM coordinates:

// Document position → DOM coordinates
const { node, offset } = viewDesc.domFromPos(15, 1);
// Returns the DOM node and offset at document position 15

// DOM coordinates → Document position  
const pos = viewDesc.posFromDOM(domNode, domOffset, bias);
// Returns the document position for the given DOM location

// Position before a child
const pos = viewDesc.posBeforeChild(childViewDesc);

Utility Functions

The ViewDescUtil provides helper functions:

import { ViewDescUtil } from '@type-editor/viewdesc';

// Find ViewDesc by DOM node
const desc = ViewDescUtil.findByDOM(domNode);

// Find parent block ViewDesc
const blockDesc = ViewDescUtil.findParentBlock(viewDesc);

// Check if ViewDesc needs update
const needsUpdate = ViewDescUtil.needsUpdate(viewDesc, node, deco);

Advanced Usage

Custom Node Views

Custom node views automatically get wrapped in CustomNodeViewDesc:

import { EditorView } from '@type-editor/view';

const view = new EditorView({
    nodeViews: {
        // Custom rendering for images
        image(node, view, getPos) {
            const dom = document.createElement('figure');
            const img = document.createElement('img');
            img.src = node.attrs.src;
            dom.appendChild(img);
            
            // CustomNodeViewDesc wraps this automatically
            return { dom };
        },
        
        // Custom rendering with content
        callout(node, view, getPos) {
            const dom = document.createElement('div');
            dom.className = 'callout';
            const contentDOM = document.createElement('div');
            contentDOM.className = 'callout-content';
            dom.appendChild(contentDOM);
            
            return { dom, contentDOM };
        }
    }
});

Decoration Rendering

ViewDescs apply decorations during rendering:

// Inline decorations add attributes to text
const inlineDeco = Decoration.inline(5, 15, {
    class: 'highlight',
    style: 'background: yellow'
});
// MarkViewDesc or TextViewDesc applies these attributes

// Node decorations wrap entire nodes
const nodeDeco = Decoration.node(20, 45, {
    class: 'selected-node'
});
// NodeViewDesc wraps the node with decoration elements

// Widget decorations insert DOM elements
const widgetDeco = Decoration.widget(10, () => {
    const el = document.createElement('span');
    el.textContent = '📍';
    return el;
});
// WidgetViewDesc manages the widget DOM

Dirty State Tracking

ViewDescs track what needs updating:

import { ViewDirtyState } from '@type-editor/viewdesc';

// Dirty states
ViewDirtyState.NOT_DIRTY      // No update needed
ViewDirtyState.CHILD_DIRTY    // Children need update
ViewDirtyState.CONTENT_DIRTY  // Content needs update  
ViewDirtyState.NODE_DIRTY     // Entire node needs update

// Mark a range as dirty
viewDesc.markDirty(from, to);

// Check if ViewDesc is dirty
if (viewDesc.dirty !== ViewDirtyState.NOT_DIRTY) {
    // Needs update
}

Position and Offset Calculations

Working with positions in the ViewDesc tree:

// Get position before a specific child
const posBefore = parent.posBeforeChild(child);

// Get position after a child
const posAfter = posBefore + child.size;

// Find child at a position
const child = viewDesc.childAfter(pos);

// Local position from DOM
const localPos = viewDesc.localPosFromDOM(domNode, offset, bias);

Performance Considerations

  1. Incremental updates: ViewDesc enables efficient partial DOM updates instead of full rerenders
  2. Dirty tracking: Only updates parts marked as dirty
  3. Node matching: Reuses existing ViewDesc nodes when possible
  4. DOM node reuse: Keeps DOM nodes stable across updates when content hasn't changed
  5. Position caching: Maintains position information for fast lookups
  6. Minimal DOM operations: Batches and minimizes DOM changes

Internal Architecture

The ViewDesc system consists of several interconnected components:

  • ViewDesc: Base class with core functionality
  • ViewDescFactory: Creates appropriate ViewDesc instances
  • ViewDescUpdater: Handles incremental updates
  • ViewDescUtil: Utility functions for working with ViewDescs
  • ViewTreeUpdater: Manages tree-level updates
  • OuterDecoLevel: Manages decoration wrapper levels

These components work together to provide efficient, incremental DOM rendering while maintaining the connection between the document model and the visual representation.

API Reference

ViewDesc

Base class methods and properties:

Properties:

  • dom: Node - The DOM node
  • contentDOM: HTMLElement | null - Container for child content
  • parent: ViewDesc | undefined - Parent ViewDesc
  • children: ViewDesc[] - Child ViewDescs
  • dirty: ViewDirtyState - Dirty state
  • node: Node | null - Associated ProseMirror node

Methods:

  • destroy(): void - Clean up resources
  • markDirty(from: number, to: number): void - Mark range as dirty
  • domFromPos(pos: number, side: number): DOMPosition - Map position to DOM
  • localPosFromDOM(node: Node, offset: number, bias: number): number - Map DOM to position
  • posBeforeChild(child: ViewDesc): number - Get position before child

NodeViewDesc

Extends ViewDesc with node-specific functionality:

Additional Properties:

  • outerDeco: Decoration[] | null - Outer decorations
  • innerDeco: DecorationSource | null - Inner decorations
  • nodeDOM: Node - The node's DOM element
  • size: number - Node size
  • border: number - Border size
  • domAtom: boolean - Whether node is a DOM atom

Static Methods:

  • applyOuterDeco(dom: Node, deco: Decoration[], node: Node): Node - Apply decorations to DOM

ViewDescUpdater

Static methods for updating ViewDescs:

  • update(viewDesc: ViewDesc, view: EditorView, node: Node, outerDeco, innerDeco): boolean - Update ViewDesc
  • updateChildren(viewDesc: ViewDesc, view: EditorView, pos: number): void - Update children

ViewDescUtil

Utility functions:

  • findByDOM(dom: Node): ViewDesc | undefined - Find ViewDesc by DOM node
  • Various helper functions for ViewDesc manipulation

Compatibility

This module is a refactored version of ProseMirror's internal view description system. While the core concepts remain the same, the API is restructured and improved with TypeScript types. For full ProseMirror compatibility, use the compatibility layer packages.

Related Modules

  • @type-editor/view: The editor view that uses ViewDesc for rendering
  • @type-editor/decoration: Decoration system that ViewDesc renders
  • @type-editor/model: Document model that ViewDesc represents
  • @type-editor/dom-util: DOM utility functions used by ViewDesc
  • @type-editor/transform: Position mapping used during updates

License

MIT