CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-slate-history

An operation-based history implementation for Slate editors providing undo/redo functionality.

Pending
Overview
Eval results
Files

history.mddocs/

History Structure

The History object is the core data structure that manages undo and redo operation stacks. It contains batched operations and provides utilities for validating history objects.

Capabilities

History Interface

The main data structure for storing operation history in undo and redo stacks.

interface History {
  /** Array of operation batches for redo functionality */
  redos: Batch[];
  /** Array of operation batches for undo functionality */
  undos: Batch[];
}

Batch Structure

Internal structure representing a group of related operations that should be undone/redone together.

interface Batch {
  /** Array of Slate operations in this batch */
  operations: Operation[];
  /** Selection state before these operations were applied */
  selectionBefore: Range | null;
}

Batch Characteristics:

  • Operations are stored in the order they were applied
  • Selection state is captured before the first operation in the batch
  • Batches represent logical units for undo/redo (e.g., a word typed, a paste operation)

Type Guards

Utility for validating History objects.

/**
 * Check if a value is a valid History object
 * @param value - Value to check
 * @returns True if value is a properly structured History object
 */
function isHistory(value: any): value is History;

Usage Examples:

import { History } from "slate-history";

// Check if an object is a valid history
const historyData = { redos: [], undos: [] };
if (History.isHistory(historyData)) {
  console.log("Valid history object");
}

// Access history from a history-enabled editor
if (HistoryEditor.isHistoryEditor(editor)) {
  const history = editor.history;
  
  // Check undo availability
  const canUndo = history.undos.length > 0;
  console.log(`Can undo: ${canUndo}`);
  
  // Check redo availability
  const canRedo = history.redos.length > 0;
  console.log(`Can redo: ${canRedo}`);
  
  // Get operation counts
  console.log(`Undo batches: ${history.undos.length}`);
  console.log(`Redo batches: ${history.redos.length}`);
}

History Structure Details

Operation Stacks

Undos Stack:

  • Contains batches of operations that can be undone
  • New operations are added to the end of the array
  • Undo operations remove batches from the end (LIFO - Last In, First Out)
  • Limited to 100 batches to prevent memory issues

Redos Stack:

  • Contains batches of operations that can be redone
  • Populated when undo operations are performed
  • Cleared when new operations are applied to the editor
  • Also follows LIFO ordering

Stack Behavior

// When operations are applied:
// 1. New batch is added to undos stack
// 2. Redos stack is cleared

// When undo is called:
// 1. Last batch is removed from undos stack
// 2. Inverse operations are applied
// 3. Original batch is added to redos stack

// When redo is called:
// 1. Last batch is removed from redos stack  
// 2. Original operations are reapplied
// 3. Batch is added back to undos stack

Batch Management

Batch Creation:

  • New batches are created for each logical operation group
  • Selection state is captured before applying operations
  • Related operations (like consecutive text insertions) are merged into single batches

Batch Limits:

  • Undo stack is limited to 100 batches maximum
  • Oldest batches are removed when limit is exceeded
  • This prevents unbounded memory growth in long editing sessions

Validation Logic

The History.isHistory function performs comprehensive validation:

  1. Object Structure: Checks that the value is an object with redos and undos properties
  2. Array Types: Verifies both properties are arrays
  3. Batch Validation: For non-empty stacks, validates that batches contain valid operation arrays
  4. Operation Validation: Uses Slate's Operation.isOperationList to validate operation structure

Example Validation:

import { History } from "slate-history";

// Valid history objects
History.isHistory({ redos: [], undos: [] }); // true
History.isHistory({ 
  redos: [{ operations: [], selectionBefore: null }], 
  undos: [] 
}); // true

// Invalid history objects
History.isHistory(null); // false
History.isHistory({ redos: "not array" }); // false
History.isHistory({ redos: [], undos: [{ invalid: "batch" }] }); // false

Integration with Editor

The History object is automatically managed by the withHistory plugin:

import { withHistory, HistoryEditor } from "slate-history";
import { createEditor } from "slate";

const editor = withHistory(createEditor());

// History is automatically initialized
console.log(editor.history); // { redos: [], undos: [] }

// History is updated as operations are applied
editor.insertText("Hello");
console.log(editor.history.undos.length); // 1

// History stacks change with undo/redo
editor.undo();
console.log(editor.history.undos.length); // 0
console.log(editor.history.redos.length); // 1

Install with Tessl CLI

npx tessl i tessl/npm-slate-history

docs

history-editor.md

history.md

index.md

with-history.md

tile.json