Advanced Features

Beyond basic typing: implementing search, real-time collaboration, and debugging tools.

Overview

Professional editors require features that go beyond content manipulation. This section covers complex capabilities often needed for production apps.

Search & Replace

Do not use window.find(). It affects selection and is limited. Instead, implement model-based search.

  • Search: Traverse the model text nodes, matching regex. Collect paths/ranges.
  • Highlight: Apply a temporary "decoration" or "mark" to the matched ranges.
  • Replace: Dispatch a transaction replacing the range content.
function searchModel(doc, query) {
  const matches = [];
  doc.descendants((node, pos) => {
    if (node.isText) {
      // Regex match on node.text
      // push { from: pos + match.index, to: ... }
    }
  });
  return matches;
}

Real-time Collaboration

Modern collaboration uses CRDTs (Conflict-free Replicated Data Types) like Yjs or Automerge.

Integration Strategy

Bind your editor model to a Yjs Y.XmlFragment. Listen for Yjs updates to patch the editor, and broadcast editor transactions to Yjs.

// 1. Editor -> Yjs
editor.on('transaction', (tr) => {
  yDoc.transact(() => {
    applyStepsToYjs(tr.steps, yXmlFragment);
  });
});

// 2. Yjs -> Editor
yXmlFragment.observe((event) => {
  const tr = convertYjsEventsToSteps(event);
  editor.dispatch(tr);
});

History Visualizer

For debugging undo/redo stacks, create a visualizer that renders the transaction history.

  • State: Capture a snapshot of the document at each step.
  • Diff: Highlight what changed in that transaction.
  • Selection: Show where the user cursor was.