CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tiptap--pm

Comprehensive wrapper around ProseMirror packages providing unified entry point for rich text editing functionality in Tiptap framework

Pending
Overview
Eval results
Files

schema-definitions.mddocs/

Schema Definitions

Pre-built schema definitions provide common node and mark types for rich text editing. The basic schema covers fundamental text formatting, while the list schema adds structured list support.

Capabilities

Basic Schema

The basic schema provides essential node and mark types for general text editing.

/**
 * Complete basic schema with nodes and marks
 */
const schema: Schema;

Basic Node Types

Core node types for document structure.

/**
 * Document root node - contains all other content
 */
const doc: NodeSpec;

/**
 * Paragraph node - basic text container
 */
const paragraph: NodeSpec;

/**
 * Block quote node - indented quoted content
 */
const blockquote: NodeSpec;

/**
 * Horizontal rule node - visual separator
 */
const horizontal_rule: NodeSpec;

/**
 * Heading node with level attribute (1-6)
 */
const heading: NodeSpec;

/**
 * Code block node - preformatted code
 */
const code_block: NodeSpec;

/**
 * Text node - leaf node containing actual text
 */
const text: NodeSpec;

/**
 * Image node - embedded images with src and optional alt/title
 */
const image: NodeSpec;

/**
 * Hard break node - forced line break
 */
const hard_break: NodeSpec;

Basic Mark Types

Inline formatting marks for text styling.

/**
 * Link mark - hyperlinks with href attribute
 */
const link: MarkSpec;

/**
 * Emphasis mark - italic text styling  
 */
const em: MarkSpec;

/**
 * Strong mark - bold text styling
 */
const strong: MarkSpec;

/**
 * Code mark - inline code formatting
 */
const code: MarkSpec;

Node and Mark Collections

Organized collections of specifications.

/**
 * All basic node specifications
 */
const nodes: {
  doc: NodeSpec;
  paragraph: NodeSpec;
  blockquote: NodeSpec;
  horizontal_rule: NodeSpec;
  heading: NodeSpec;
  code_block: NodeSpec;
  text: NodeSpec;
  image: NodeSpec;
  hard_break: NodeSpec;
};

/**
 * All basic mark specifications  
 */
const marks: {
  link: MarkSpec;
  em: MarkSpec;
  strong: MarkSpec;
  code: MarkSpec;
};

List Schema Extensions

The list schema provides structured list node types and commands.

/**
 * Ordered list node specification
 */
const orderedList: NodeSpec;

/**
 * Bullet list node specification  
 */
const bulletList: NodeSpec;

/**
 * List item node specification
 */
const listItem: NodeSpec;

List Integration

Functions to integrate list nodes into existing schemas.

/**
 * Add list nodes to an existing node collection
 */
function addListNodes(
  nodes: { [name: string]: NodeSpec },
  itemContent: string,
  listGroup?: string
): { [name: string]: NodeSpec };

List Commands

Commands for manipulating list structures.

/**
 * Wrap selection in a list of the given type
 */
function wrapInList(listType: NodeType, attrs?: Attrs): Command;

/**
 * Split the current list item
 */
function splitListItem(itemType: NodeType): Command;

/**
 * Split list item while preserving marks
 */
function splitListItemKeepMarks(itemType: NodeType): Command;

/**
 * Lift the current list item out of its list
 */
function liftListItem(itemType: NodeType): Command;

/**
 * Sink the current list item down into a nested list
 */
function sinkListItem(itemType: NodeType): Command;

Usage Examples:

import { schema as basicSchema, nodes, marks } from "@tiptap/pm/schema-basic";
import { 
  addListNodes, 
  wrapInList, 
  splitListItem, 
  liftListItem, 
  sinkListItem 
} from "@tiptap/pm/schema-list";
import { Schema } from "@tiptap/pm/model";

// Use basic schema directly
const simpleEditor = EditorState.create({
  schema: basicSchema,
  doc: basicSchema.nodeFromJSON({
    type: "doc",
    content: [{
      type: "paragraph",
      content: [{ type: "text", text: "Hello world!" }]
    }]
  })
});

// Extend basic schema with lists
const extendedNodes = addListNodes(nodes, "paragraph block*", "block");
const mySchema = new Schema({
  nodes: extendedNodes,
  marks: marks
});

// Create list commands
const toggleOrderedList = wrapInList(mySchema.nodes.orderedList);
const toggleBulletList = wrapInList(mySchema.nodes.bulletList);
const splitItem = splitListItem(mySchema.nodes.listItem);
const liftItem = liftListItem(mySchema.nodes.listItem);
const sinkItem = sinkListItem(mySchema.nodes.listItem);

// Use in keymap
const listKeymap = keymap({
  "Mod-Shift-7": toggleOrderedList,
  "Mod-Shift-8": toggleBulletList,
  "Enter": splitItem,
  "Mod-[": liftItem,
  "Mod-]": sinkItem,
  "Tab": sinkItem,
  "Shift-Tab": liftItem
});

// Custom schema with additional nodes
const customSchema = new Schema({
  nodes: {
    ...nodes,
    // Add custom nodes
    callout: {
      content: "block+",
      group: "block",
      defining: true,
      attrs: { type: { default: "info" } },
      parseDOM: [{ 
        tag: "div.callout", 
        getAttrs: (dom) => ({ type: dom.getAttribute("data-type") }) 
      }],
      toDOM: (node) => ["div", { 
        class: "callout", 
        "data-type": node.attrs.type 
      }, 0]
    },
    
    // Add list nodes
    ...addListNodes(nodes, "paragraph block*", "block")
  },
  
  marks: {
    ...marks,
    // Add custom marks
    highlight: {
      attrs: { color: { default: "yellow" } },
      parseDOM: [{ 
        tag: "mark", 
        getAttrs: (dom) => ({ color: dom.style.backgroundColor }) 
      }],
      toDOM: (mark) => ["mark", { 
        style: `background-color: ${mark.attrs.color}` 
      }, 0]
    }
  }
});

Advanced Schema Customization

Custom Node Definitions

Extend or modify existing node types for specific needs.

// Custom heading with ID support
const headingWithId = {
  ...heading,
  attrs: {
    level: { default: 1 },
    id: { default: null }
  },
  parseDOM: [
    ...heading.parseDOM.map(rule => ({
      ...rule,
      getAttrs: (dom) => ({
        level: +dom.tagName.slice(1),
        id: dom.id || null
      })
    }))
  ],
  toDOM: (node) => {
    const attrs = { id: node.attrs.id };
    return [`h${node.attrs.level}`, attrs, 0];
  }
};

// Code block with language support
const codeBlockWithLang = {
  ...code_block,
  attrs: { 
    language: { default: null },
    showLineNumbers: { default: false }
  },
  parseDOM: [{
    tag: "pre",
    preserveWhitespace: "full",
    getAttrs: (dom) => ({
      language: dom.getAttribute("data-language"),
      showLineNumbers: dom.hasAttribute("data-line-numbers")
    })
  }],
  toDOM: (node) => {
    const attrs = {};
    if (node.attrs.language) {
      attrs["data-language"] = node.attrs.language;
    }
    if (node.attrs.showLineNumbers) {
      attrs["data-line-numbers"] = "";
    }
    return ["pre", attrs, ["code", 0]];
  }
};

List Customization

Customize list behavior and styling.

// Custom list with additional attributes
const customOrderedList = {
  ...orderedList,
  attrs: {
    order: { default: 1 },
    style: { default: "decimal" }
  },
  parseDOM: [{
    tag: "ol",
    getAttrs: (dom) => ({
      order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
      style: dom.style.listStyleType || "decimal"
    })
  }],
  toDOM: (node) => {
    const attrs = {};
    if (node.attrs.order !== 1) {
      attrs.start = node.attrs.order;
    }
    if (node.attrs.style !== "decimal") {
      attrs.style = `list-style-type: ${node.attrs.style}`;
    }
    return ["ol", attrs, 0];
  }
};

// Task list item extension
const taskListItem = {
  content: "paragraph block*",
  defining: true,
  attrs: { 
    checked: { default: false },
    id: { default: null }
  },
  parseDOM: [{
    tag: "li[data-task-item]",
    getAttrs: (dom) => ({
      checked: dom.hasAttribute("data-checked"),
      id: dom.getAttribute("data-id")
    })
  }],
  toDOM: (node) => {
    const attrs = { "data-task-item": "" };
    if (node.attrs.checked) {
      attrs["data-checked"] = "";
    }
    if (node.attrs.id) {
      attrs["data-id"] = node.attrs.id;
    }
    return ["li", attrs, 0];
  }
};

Schema Validation

Ensure schema consistency and proper configuration.

// Validate schema configuration
function validateCustomSchema(schemaSpec: SchemaSpec): string[] {
  const errors: string[] = [];
  
  // Check required nodes
  const requiredNodes = ["doc", "paragraph", "text"];
  for (const node of requiredNodes) {
    if (!schemaSpec.nodes[node]) {
      errors.push(`Missing required node: ${node}`);
    }
  }
  
  // Validate content expressions
  for (const [name, spec] of Object.entries(schemaSpec.nodes)) {
    if (spec.content && !isValidContentExpression(spec.content)) {
      errors.push(`Invalid content expression for ${name}: ${spec.content}`);
    }
  }
  
  return errors;
}

// Create schema with validation
function createValidatedSchema(schemaSpec: SchemaSpec): Schema {
  const errors = validateCustomSchema(schemaSpec);
  if (errors.length > 0) {
    throw new Error(`Schema validation failed:\n${errors.join("\n")}`);
  }
  return new Schema(schemaSpec);
}

Types

/**
 * Schema specification for nodes and marks
 */
interface SchemaSpec {
  nodes: { [name: string]: NodeSpec };
  marks?: { [name: string]: MarkSpec };
  topNode?: string;
}

/**
 * List integration options
 */
interface ListOptions {
  itemContent?: string;
  listGroup?: string;
}

/**
 * Custom node attributes
 */
interface CustomNodeAttrs {
  [key: string]: AttributeSpec;
}

Install with Tessl CLI

npx tessl i tessl/npm-tiptap--pm

docs

collaboration.md

commands-and-editing.md

cursors-and-enhancements.md

history.md

index.md

input-and-keymaps.md

markdown.md

menus-and-ui.md

model-and-schema.md

schema-definitions.md

state-management.md

tables.md

transformations.md

view-and-rendering.md

tile.json