CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-quill

A modern, powerful rich text editor built for compatibility and extensibility

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

delta-operations.mddocs/

Delta Operations

Delta-based document representation and operational transform system for tracking and applying changes to rich text content. Delta is Quill's native format for describing document content and changes, providing a JSON-based structure that supports operational transformation for real-time collaboration.

Capabilities

Delta Constructor

Creates a new Delta instance for representing document content or changes.

/**
 * Creates a new Delta instance
 * @param ops - Array of operations or another Delta to copy
 */
constructor(ops?: Op[] | Delta);

interface Op {
  /** Insert text or embed object */
  insert?: string | object;
  /** Delete specified number of characters */
  delete?: number;
  /** Retain specified number of characters, optionally with attributes */
  retain?: number;
  /** Formatting attributes to apply */
  attributes?: AttributeMap;
}

interface AttributeMap {
  [key: string]: unknown;
}

Usage Examples:

import { Delta } from 'quill';

// Create empty Delta
const delta = new Delta();

// Create Delta from operations
const delta = new Delta([
  { insert: 'Hello ' },
  { insert: 'World', attributes: { bold: true } },
  { insert: '\n' }
]);

// Copy existing Delta
const copy = new Delta(existingDelta);

Insert Operations

Methods for inserting text or embed content with optional formatting.

/**
 * Insert text at current position
 * @param text - Text to insert
 * @param attributes - Optional formatting attributes
 * @returns This Delta instance for chaining
 */
insert(text: string, attributes?: AttributeMap): Delta;

/**
 * Insert embed object at current position
 * @param embed - Embed object (image, video, etc.)
 * @param attributes - Optional formatting attributes
 * @returns This Delta instance for chaining
 */
insert(embed: object, attributes?: AttributeMap): Delta;

Usage Examples:

// Insert plain text
const delta = new Delta()
  .insert('Hello World');

// Insert formatted text
const delta = new Delta()
  .insert('Bold Text', { bold: true })
  .insert('Red Text', { color: '#ff0000' });

// Insert embeds
const delta = new Delta()
  .insert({ image: 'https://example.com/image.jpg' })
  .insert({ video: 'https://youtube.com/watch?v=abc123' });

// Chain multiple inserts
const delta = new Delta()
  .insert('Normal text ')
  .insert('bold text ', { bold: true })
  .insert('italic text', { italic: true })
  .insert('\n');

Delete Operations

Methods for deleting characters from the document.

/**
 * Delete specified number of characters
 * @param length - Number of characters to delete
 * @returns This Delta instance for chaining
 */
delete(length: number): Delta;

Usage Examples:

// Delete 5 characters
const delta = new Delta()
  .delete(5);

// Delete and insert (replacement)
const delta = new Delta()
  .retain(10)    // Skip first 10 characters
  .delete(5)     // Delete next 5 characters
  .insert('new text'); // Insert replacement text

Retain Operations

Methods for retaining (keeping) characters, optionally applying formatting changes.

/**
 * Retain specified number of characters
 * @param length - Number of characters to retain
 * @param attributes - Optional attributes to apply/change
 * @returns This Delta instance for chaining
 */
retain(length: number, attributes?: AttributeMap): Delta;

Usage Examples:

// Retain characters without changes
const delta = new Delta()
  .retain(10);

// Retain and apply formatting
const delta = new Delta()
  .retain(5, { bold: true }); // Make first 5 characters bold

// Complex formatting change
const delta = new Delta()
  .retain(10)                    // Skip first 10 characters
  .retain(5, { italic: true })   // Make next 5 characters italic
  .retain(3, { bold: null });    // Remove bold from next 3 characters

Delta Composition

Methods for combining Deltas using operational transform principles.

/**
 * Compose this Delta with another Delta
 * @param other - Delta to compose with
 * @returns New Delta representing the composition
 */
compose(other: Delta): Delta;

/**
 * Transform this Delta against another Delta
 * @param other - Delta to transform against
 * @param priority - Whether this Delta has priority in conflicts
 * @returns New transformed Delta
 */
transform(other: Delta, priority?: boolean): Delta;

/**
 * Transform a cursor position against this Delta
 * @param index - Cursor position to transform
 * @param priority - Whether cursor has priority
 * @returns New cursor position
 */
transformPosition(index: number, priority?: boolean): number;

/**
 * Calculate difference between this Delta and another
 * @param other - Delta to compare against
 * @param cursor - Optional cursor position for optimization
 * @returns Delta representing the difference
 */
diff(other: Delta, cursor?: number): Delta;

Usage Examples:

// Compose two changes
const delta1 = new Delta().insert('Hello');
const delta2 = new Delta().retain(5).insert(' World');
const composed = delta1.compose(delta2);
// Result: Delta with "Hello World"

// Transform concurrent changes
const delta1 = new Delta().insert('A');
const delta2 = new Delta().insert('B');
const transformed = delta1.transform(delta2, true);
// Result: Delta accounting for concurrent insertion

// Transform cursor position
const delta = new Delta().insert('Hello ');
const newPosition = delta.transformPosition(0); // Position after "Hello "

// Calculate difference between documents
const oldDoc = new Delta().insert('Hello World');
const newDoc = new Delta().insert('Hello Beautiful World');
const diff = oldDoc.diff(newDoc);
// Result: Delta showing what changed

Delta Utility Methods

Methods for analyzing and manipulating Delta content.

/**
 * Get total length of Delta content
 * @returns Total number of characters
 */
length(): number;

/**
 * Extract slice of Delta
 * @param start - Starting index (default: 0)
 * @param end - Ending index (default: end of Delta)
 * @returns New Delta with sliced content
 */
slice(start?: number, end?: number): Delta;

/**
 * Partition Delta based on predicate
 * @param predicate - Function to test each operation
 * @returns Tuple of [matching ops, non-matching ops] as Deltas
 */
partition(predicate: (op: Op) => boolean): [Delta, Delta];

/**
 * Filter operations based on predicate
 * @param predicate - Function to test each operation
 * @returns Array of operations that match predicate
 */
filter(predicate: (op: Op, index: number) => boolean): Op[];

/**
 * Execute function for each operation
 * @param predicate - Function to execute for each operation
 */
forEach(predicate: (op: Op, index: number) => void): void;

/**
 * Map operations to new values
 * @param predicate - Function to transform each operation
 * @returns Array of transformed values
 */
map<T>(predicate: (op: Op, index: number) => T): T[];

/**
 * Reduce operations to single value
 * @param predicate - Function to combine operations
 * @param initialValue - Initial value for reduction
 * @returns Final reduced value
 */
reduce<T>(predicate: (acc: T, curr: Op, index: number) => T, initialValue: T): T;

Usage Examples:

const delta = new Delta()
  .insert('Hello ')
  .insert('World', { bold: true })
  .insert('\n');

// Get length
const length = delta.length(); // 12 characters

// Slice content
const slice = delta.slice(0, 5); // Delta with "Hello"
const end = delta.slice(6); // Delta with "World\n" (bold)

// Partition by attributes
const [formatted, plain] = delta.partition(op => op.attributes && Object.keys(op.attributes).length > 0);

// Filter insert operations
const inserts = delta.filter(op => op.insert !== undefined);

// Process each operation
delta.forEach((op, index) => {
  console.log(`Operation ${index}:`, op);
});

// Extract text content
const text = delta
  .map(op => typeof op.insert === 'string' ? op.insert : '')
  .join('');

// Count characters
const charCount = delta.reduce((count, op) => {
  return count + (typeof op.insert === 'string' ? op.insert.length : 1);
}, 0);

OpIterator

Iterator class for processing Delta operations sequentially.

/**
 * Iterator for processing Delta operations
 * @param ops - Array of operations to iterate over
 */
class OpIterator {
  constructor(ops: Op[]);
  
  /**
   * Check if there are more operations
   * @returns True if more operations available
   */
  hasNext(): boolean;
  
  /**
   * Get next operation, optionally consuming specific length
   * @param length - Length to consume from current operation
   * @returns Next operation or portion of operation
   */
  next(length?: number): Op;
  
  /**
   * Peek at next operation without consuming it
   * @returns Next operation
   */
  peek(): Op;
  
  /**
   * Get length of next operation
   * @returns Length of next operation
   */
  peekLength(): number;
  
  /**
   * Get type of next operation
   * @returns Type of next operation
   */
  peekType(): 'insert' | 'delete' | 'retain';
  
  /**
   * Get remaining operations
   * @returns Array of remaining operations
   */
  rest(): Op[];
}

Usage Examples:

import { OpIterator } from 'quill';

const delta = new Delta()
  .insert('Hello')
  .retain(5)
  .delete(3);

const iter = new OpIterator(delta.ops);

while (iter.hasNext()) {
  const op = iter.next();
  console.log('Operation:', op);
  
  // Process based on type
  if (op.insert) {
    console.log('Insert:', op.insert);
  } else if (op.delete) {
    console.log('Delete:', op.delete);
  } else if (op.retain) {
    console.log('Retain:', op.retain);
  }
}

// Peek without consuming
const iter2 = new OpIterator(delta.ops);
console.log('Next type:', iter2.peekType());
console.log('Next length:', iter2.peekLength());
console.log('Next op:', iter2.peek());

// Get remaining operations
const remaining = iter2.rest();

Delta JSON Serialization

Delta objects are JSON-serializable for storage and transmission.

// Delta structure for JSON serialization
interface DeltaJSON {
  ops: Op[];
}

interface Op {
  insert?: string | object;
  delete?: number;
  retain?: number;
  attributes?: AttributeMap;
}

Usage Examples:

// Create Delta
const delta = new Delta()
  .insert('Hello ')
  .insert('World', { bold: true })
  .insert('\n');

// Serialize to JSON
const json = JSON.stringify(delta);
console.log('JSON:', json);
// Output: {"ops":[{"insert":"Hello "},{"insert":"World","attributes":{"bold":true}},{"insert":"\n"}]}

// Deserialize from JSON
const parsed = JSON.parse(json);
const restored = new Delta(parsed.ops);

// Delta can be used directly as JSON
const delta2 = new Delta(parsed);

Common Delta Patterns

Frequently used Delta operation patterns for content manipulation.

Usage Examples:

// Document creation
const document = new Delta()
  .insert('Heading', { header: 1 })
  .insert('\n')
  .insert('This is a paragraph with ')
  .insert('bold text', { bold: true })
  .insert(' and ')
  .insert('italic text', { italic: true })
  .insert('.\n');

// Text replacement
const replacement = new Delta()
  .retain(startIndex)
  .delete(lengthToDelete)
  .insert(newText, formatting);

// Format application
const formatting = new Delta()
  .retain(startIndex)
  .retain(length, { bold: true, color: '#ff0000' });

// Format removal
const formatRemoval = new Delta()
  .retain(startIndex)
  .retain(length, { bold: null, italic: null });

// List creation
const list = new Delta()
  .insert('Item 1', { list: 'bullet' })
  .insert('\n')
  .insert('Item 2', { list: 'bullet' })
  .insert('\n');

// Link insertion
const link = new Delta()
  .retain(textStart)
  .retain(textLength, { link: 'https://example.com' });

// Image insertion
const image = new Delta()
  .retain(insertPosition)
  .insert({ image: 'https://example.com/image.jpg' });

Install with Tessl CLI

npx tessl i tessl/npm-quill

docs

delta-operations.md

editor-core.md

formatting-system.md

index.md

module-system.md

registry-system.md

theme-system.md

tile.json