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

input-and-keymaps.mddocs/

Input and Keymaps

Input rules provide automatic text transformations based on typing patterns, while keymaps bind keyboard commands to editor actions. Together they create responsive editing experiences.

Capabilities

Input Rules

Input rules automatically transform text as users type, providing shortcuts and typography improvements.

/**
 * An input rule transforms text based on pattern matching
 */
class InputRule {
  /**
   * Create a new input rule
   */
  constructor(
    match: RegExp,
    handler: string | ((state: EditorState, match: string[], start: number, end: number) => Transaction | null),
    options?: { undoable?: boolean }
  );
}

Input Rule Plugin

Create and manage input rule plugins.

/**
 * Create an input rules plugin
 */
function inputRules(config: { rules: InputRule[] }): Plugin;

/**
 * Undo the last input rule transformation
 */
function undoInputRule(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;

Input Rule Helpers

Convenient functions for common input rule patterns.

/**
 * Create an input rule that wraps matched text in a node
 */
function wrappingInputRule(
  regexp: RegExp,
  nodeType: NodeType,
  getAttrs?: Attrs | ((match: string[]) => Attrs | null),
  joinPredicate?: (match: string[], node: Node) => boolean
): InputRule;

/**
 * Create an input rule that changes text block type
 */
function textblockTypeInputRule(
  regexp: RegExp,
  nodeType: NodeType,
  getAttrs?: Attrs | ((match: string[]) => Attrs | null)
): InputRule;

Typography Rules

Pre-defined input rules for common typography transformations.

/**
 * Convert -- to em dash
 */
const emDash: InputRule;

/**
 * Convert ... to ellipsis character
 */
const ellipsis: InputRule;

/**
 * Convert opening quotes
 */
const openDoubleQuote: InputRule;

/**
 * Convert closing quotes
 */
const closeDoubleQuote: InputRule;

/**
 * Convert opening single quotes
 */
const openSingleQuote: InputRule;

/**
 * Convert closing single quotes
 */
const closeSingleQuote: InputRule;

/**
 * Combined smart quote rules
 */
const smartQuotes: InputRule[];

Keymap System

Keymaps bind keyboard shortcuts to editor commands.

/**
 * Create a keymap plugin from key bindings
 */
function keymap(bindings: { [key: string]: Command | false }): Plugin;

/**
 * Create a keydown event handler from bindings
 */
function keydownHandler(bindings: { [key: string]: Command | false }): (view: EditorView, event: KeyboardEvent) => boolean;

Key Notation

Key combinations use standard notation for cross-platform compatibility.

/**
 * Key binding specification
 */
interface KeyBinding {
  [key: string]: Command | false;
}

/**
 * Key notation examples:
 * - "Mod-b" (Ctrl on PC/Linux, Cmd on Mac)
 * - "Alt-Enter"
 * - "Shift-Ctrl-z"
 * - "Backspace"
 * - "Delete"
 * - "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"
 * - "Home", "End"
 * - "PageUp", "PageDown"
 */

Usage Examples:

import { 
  InputRule, 
  inputRules, 
  wrappingInputRule, 
  textblockTypeInputRule,
  smartQuotes,
  emDash,
  ellipsis
} from "@tiptap/pm/inputrules";
import { keymap } from "@tiptap/pm/keymap";
import { toggleMark, setBlockType } from "@tiptap/pm/commands";

// Custom input rules
const rules = [
  // Convert ** to bold
  new InputRule(
    /\*\*([^*]+)\*\*$/,
    (state, match, start, end) => {
      const tr = state.tr.delete(start, end);
      const mark = state.schema.marks.strong.create();
      return tr.insert(start, state.schema.text(match[1], [mark]));
    }
  ),
  
  // Wrap selection in blockquote with >
  wrappingInputRule(
    /^\s*>\s$/,
    state.schema.nodes.blockquote
  ),
  
  // Convert # to heading
  textblockTypeInputRule(
    /^#\s/,
    state.schema.nodes.heading,
    { level: 1 }
  ),
  
  // Typography rules
  ...smartQuotes,
  emDash,
  ellipsis
];

// Create input rules plugin
const inputRulesPlugin = inputRules({ rules });

// Custom keymap
const myKeymap = keymap({
  // Formatting
  "Mod-b": toggleMark(schema.marks.strong),
  "Mod-i": toggleMark(schema.marks.em),
  "Mod-`": toggleMark(schema.marks.code),
  
  // Block types
  "Shift-Ctrl-1": setBlockType(schema.nodes.heading, { level: 1 }),
  "Shift-Ctrl-2": setBlockType(schema.nodes.heading, { level: 2 }),
  "Shift-Ctrl-0": setBlockType(schema.nodes.paragraph),
  
  // Custom commands
  "Mod-Enter": (state, dispatch) => {
    if (dispatch) {
      dispatch(state.tr.insertText("\n"));
    }
    return true;
  },
  
  // Disable default behavior
  "Ctrl-d": false
});

// Combine with editor
const state = EditorState.create({
  schema: mySchema,
  plugins: [
    inputRulesPlugin,
    myKeymap
  ]
});

Advanced Input Rules

Conditional Rules

Create rules that apply conditionally based on context.

// Only apply in specific node types
const codeBlockRule = new InputRule(
  /```(\w+)?\s$/,
  (state, match, start, end) => {
    // Only apply at document level
    if (state.selection.$from.depth > 1) return null;
    
    const attrs = match[1] ? { language: match[1] } : {};
    return state.tr
      .delete(start, end)
      .setBlockType(start, start, schema.nodes.code_block, attrs);
  }
);

// Rules with custom undo behavior
const undoableRule = new InputRule(
  /-->/g,
  "→",
  { undoable: true }
);

Complex Transformations

Input rules can perform sophisticated document transformations.

// Auto-link URLs
const autoLinkRule = new InputRule(
  /(https?:\/\/[^\s]+)$/,
  (state, match, start, end) => {
    const url = match[1];
    const mark = schema.marks.link.create({ href: url });
    return state.tr
      .addMark(start, end, mark)
      .insertText(" ", end);
  }
);

// Smart list continuation
const listContinueRule = new InputRule(
  /^(\d+)\.\s$/,
  (state, match, start, end) => {
    const number = parseInt(match[1]);
    return state.tr
      .delete(start, end)
      .wrapIn(schema.nodes.ordered_list, { order: number })
      .wrapIn(schema.nodes.list_item);
  }
);

Keymap Composition

Layered Keymaps

Combine multiple keymaps with priority ordering.

import { baseKeymap } from "@tiptap/pm/commands";

const editorKeymaps = [
  // Highest priority - custom overrides
  keymap({
    "Enter": customEnterCommand,
    "Tab": customTabCommand
  }),
  
  // Medium priority - feature-specific
  keymap({
    "Mod-k": insertLinkCommand,
    "Mod-Shift-k": removeLinkCommand
  }),
  
  // Lowest priority - base commands
  keymap(baseKeymap)
];

const state = EditorState.create({
  schema: mySchema,
  plugins: editorKeymaps
});

Platform-Specific Bindings

Handle platform differences in key bindings.

const platformKeymap = keymap({
  // Cross-platform modifier
  "Mod-z": undo,
  "Mod-Shift-z": redo,
  
  // Platform-specific alternatives  
  ...(navigator.platform.includes("Mac") ? {
    "Cmd-y": redo  // Mac alternative
  } : {
    "Ctrl-y": redo  // Windows/Linux alternative
  })
});

Types

/**
 * Input rule configuration
 */
interface InputRuleConfig {
  rules: InputRule[];
}

/**
 * Key binding map
 */
interface Keymap {
  [key: string]: Command | false;
}

/**
 * Input rule handler function
 */
type InputRuleHandler = (
  state: EditorState,
  match: string[],
  start: number,
  end: number
) => Transaction | null;

/**
 * Input rule options
 */
interface InputRuleOptions {
  undoable?: boolean;
}

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