npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

richtext-all

v1.0.0

Published

Universal, zero-dependency collaborative rich text & live editor engine for all JavaScript frameworks and platforms (React, Next.js, Vue 3, Angular, Svelte, Vanilla). Supports real-time collaboration with live cursors, presence avatars, revision audit his

Readme

✍️ RichText-All

The Universal, Zero-Dependency Collaborative Rich Text & Document Editor Engine
One unified API across React, Next.js, Vue 3, Angular, Svelte, and Vanilla HTML5.

npm version Bundle Size Zero Dependencies Multi-Platform License: MIT Live Demo


🌐 Live Interactive Demo

Try RichText-All directly in your browser:
👉 Open Live Demo Playground
(Experience print-accurate A4 pagination, 3D card clustering, bilateral margin arrangement, version checkpoints with visual diffs, and 1-click DOCX import/export)


🚀 Why RichText-All?

| Feature | RichText-All 🌟 | TipTap | Quill | Slate | TinyMCE / CKEditor | | :--- | :---: | :---: | :---: | :---: | :---: | | Multi-Framework | React, Vue, Angular, Svelte, Vanilla | React & Vue only | Vanilla primarily | React only | Multi-framework | | Page Pagination | Print-accurate A4, Letter, Legal, Web | ❌ No | ❌ No | ❌ No | Paid Plugin | | Annotation Card Clustering | 3D Deck Stacking + Hover Fan-Out | ❌ No | ❌ No | ❌ No | ❌ No | | Bilateral Margins | Left, Right, or Auto Both Sides | ❌ No | ❌ No | ❌ No | ❌ No | | Track Changes & Suggestions | Built-in Additions & Deletions | Paid Cloud | ❌ No | ❌ No | Enterprise Paid | | Version History & Visual Diff | Word-by-word Side-by-side & Unified | Paid Cloud | ❌ No | ❌ No | Enterprise Paid | | Live Split Editor | Bidirectional Markdown <-> WYSIWYG | ❌ No | ❌ No | ❌ No | ❌ No | | Native Word DOCX Import | Built-in Zero-Dependency Parser | Plugins required | ❌ No | ❌ No | Paid Plugins | | Zero Runtime Dependencies | 0 Dependencies (~24 KB) | 20+ packages | 5+ packages | 10+ packages | Heavy (>150 KB) |


📦 Installation

npm install richtext-all

Or via CDN:

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/richtext-all.css">
<script type="module" src="https://unpkg.com/[email protected]/dist/index.esm.js"></script>

💡 Flagship Features

1. 📄 Print-Accurate Physical Page Layouts, In-Between Insertion & Page Reordering

  • Switch between A4 (210×297mm), US Letter (8.5×11in), US Legal (8.5×14in), and Web (Infinite 100%).
  • Insert Pages In-Between: Insert a new page anywhere between existing pages with one click via header buttons (+ Add Page) or editor.insertPageAt(index). All pages automatically renumber cleanly.
  • Interactive Page Reordering: Move pages up/down with 1-click header buttons (↑ Up, ↓ Down), drag-and-drop page sheets with the ⠿ handle, or programmatically reorder via editor.movePage(from, to) and editor.reorderPages([3, 1, 2]).
  • Real-Time Continuous Typing Auto-Pagination: As text, images, or tables exceed page height budgets, overflow elements automatically advance to the next page sheet without splitting words awkwardly or breaking paragraph integrity.
  • Page numbering pills (Page 1, Page 2, ...) and insert/delete page breaks with one click.

2. 📚 Position-Based Card Clustering & 3D Deck Stacking

  • Vertical Proximity Clustering: When multiple annotations (comments, suggestions, deletions) are created on the same line or within $50\text{px}$, they group into a single compact line cluster anchored to the text.
  • Collapsed 3D Deck Stack: Displays the top card with a pill badge (📚 N items on this line) and stacks subsequent cards with layered 3D depth and subtle vertical offsets.
  • Hover Fan-Out / Spread: Hovering the card cluster smoothly expands all cards vertically with dynamically accumulated heights and non-overlapping $12\text{px}$ spacing.
  • Top-Layer Elevation: Hovering over marked phrases in the document body immediately pops that exact card to the top layer (z-index: 300, elevated 3D shadow, and author's color border).

3. ⇋ Bilateral Margin Space Arrangement (left, right, both)

  • 'right': All cards occupy the right margin space.
  • 'left': All cards occupy the left margin space.
  • 'both' (Automatic Bilateral): Activates both left and right margin spaces:
    • Single annotations on a line occupy their closest margin space.
    • Two annotations on the same line automatically occupy opposite sides (one on Left, one on Right), giving each card full visibility without clustering!
    • When line space on both margins is filled (3+ items), subsequent annotations form balanced card stacks on both sides.

4. ⚖️ Version History Checkpoints & Word-by-Word Visual Diff

  • Save manual checkpoints and automated snapshots with word count and author stamps.
  • Interactive Visual Diff Visualizer Modal:
    • Compare any past checkpoint against another or the Live Active Document.
    • Side-by-Side Split View with synchronized scrolling.
    • Unified View showing deletions in red strike-through (-Red) and additions in green underline (+Green).
    • One-click rollback to restore any previous document revision.

5. 💬 Threaded Comments & Collaborative Discussion

  • Multi-User Replies: Any collaborator can post threaded replies directly inside gutter cards or via API.
  • Resolve & Delete: Mark comments as resolved with one click (stored with resolvedBy and resolvedAt audit metadata) or delete obsolete discussion threads.
  • Filterable Discussion: Query active or resolved threads at any time with editor.getComments({ resolved: false }).

6. ✏️ Track Changes Suggestions & Reviewer Acceptance Workflow

  • Suggesting Mode: Direct edits are transformed into clean visual suggestions (green additions, red strikethrough deletions).
  • Reviewer Tracking: When suggestions are accepted or rejected, the system logs the reviewer's ID, name, color, and timestamp (reviewedBy, reviewedAt).
  • Granular Filtering: Filter pending, accepted, or rejected suggestions via editor.getSuggestions({ status: 'pending' }).

7. 📂 High-Performance Word (.docx) Import (1000+ Pages with Images & Links)

  • Zero-Freeze Continuous Mode: Automatically detects large documents (>30 pages) and switches to an ultra-efficient continuous sheet with visual print-break dividers. Easily loads 1000+ page documents at smooth 60 FPS without DOM memory bloat.
  • Embedded Images & Links: Built-in zero-dependency ZIP & XML engine extracts all embedded media (word/media/*) into base64 images and resolves all hyperlinks (word/_rels/document.xml.rels).
  • Export clean .docx, .md, .html, .json, and plain .txt files.

8. 👥 Collaborator Identity & User Switcher

  • Assign each team member a distinct name and author color.
  • Dropdown user switcher with custom color picker dialog (+ User).
  • Metadata persists across all comments, replies, suggestions, and cursor badges.

9. 🎛️ Fully Configurable Toolbar: Defaults & Granular Show/Hide

  • Customizable Default Values: Set defaults for every toolbar control on initialization or at runtime (style, fontSize, lineHeight, color, highlight, layout, margin, mode, tableRows, tableCols).
  • Complete Toolbar Visibility: Toggle the entire ribbon with editor.hideToolbar() / editor.showToolbar() or initialize with toolbar: false or toolbar: { visible: false }.
  • Granular Item Visibility: Show or hide specific buttons, dropdowns, or feature groups with hiddenItems: ['upload', 'table'], show: { mode: false }, or whitelist with items: ['style', 'bold', 'italic'].
  • Dynamic Runtime Controls: Freely call editor.hideToolbarItem(key), editor.showToolbarItem(key), editor.toggleToolbarItem(key), or editor.setToolbarDefaults(defaults).
  • Automatic Group & Divider Management: Dividers and empty groups cleanly auto-collapse when child items are hidden.

10. ⚡ Zero-Config Real-Time Multiplayer Collaboration

  • Zero-Server Multi-Tab Sync (BroadcastChannel): Open 2, 3, or 5 tabs or windows in your browser—all edits, typing tooltips, and live colored cursors sync instantly with zero configuration and zero backend needed.
  • Cross-Browser & Network Sync (WebSocket): Seamlessly sync across different browsers (Chrome, Firefox, Edge, Safari) and different computers on your network by passing collab: { serverUrl: 'ws://localhost:1234' }.
  • Built-in Zero-Dependency Relay Server: Launch the included WebSocket server in one command with npm run collab (pure Node.js standard library, 0 external npm dependencies).

🛠️ Framework Integration

1. React / Next.js (App Router & Pages Router)

import React, { useRef } from 'react';
import { RichEditor } from 'richtext-all/react';
import 'richtext-all/css';

export default function DocumentEditor() {
  const editorRef = useRef(null);

  return (
    <div style={{ height: '90vh', maxWidth: '1200px', margin: '0 auto' }}>
      <RichEditor
        ref={editorRef}
        pageLayout="a4"              // 'a4' | 'letter' | 'legal' | 'infinite'
        gutterPosition="both"        // 'right' | 'left' | 'both'
        user={{
          id: 'usr-1',
          name: 'Sarah (Design Lead)',
          color: '#ec4899'
        }}
        onSave={(data) => {
          console.log('Document HTML:', data.html);
          console.log('Markdown:', data.markdown);
        }}
      />
    </div>
  );
}

2. Vue 3 / Nuxt 3

<template>
  <div class="editor-container">
    <RichEditor
      v-model="content"
      page-layout="a4"
      gutter-position="both"
      :user="{ id: 'usr-2', name: 'Alex (Tech Lead)', color: '#059669' }"
      @change="onContentChange"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { RichEditor } from 'richtext-all/vue';
import 'richtext-all/css';

const content = ref('<h1>Project Overview</h1><p>Collaborate in real time!</p>');
const onContentChange = (stats) => {
  console.log('Word count:', stats.words);
};
</script>

3. Angular (12+)

import { Component } from '@angular/core';
import { RichEditorComponent } from 'richtext-all/angular';

@Component({
  selector: 'app-document-view',
  standalone: true,
  imports: [RichEditorComponent],
  template: `
    <rich-editor
      [pageLayout]="'a4'"
      [gutterPosition]="'both'"
      (onSave)="handleSave($event)">
    </rich-editor>
  `
})
export class DocumentViewComponent {
  handleSave(doc: any) {
    console.log('Saved document HTML:', doc.html);
  }
}

4. Vanilla JavaScript / HTML5

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="node_modules/richtext-all/dist/richtext-all.css">
</head>
<body>
  <div id="editor-mount"></div>

  <script type="module">
    import { RichEditor } from 'richtext-all';

    const editor = new RichEditor('#editor-mount', {
      pageLayout: 'a4',
      gutterPosition: 'both',
      user: { name: 'Veeresh', color: '#6366f1' }
    });

    // Programmatic Margin Space API
    editor.setGutterPosition('left');  // Switch to left margin
    editor.setGutterPosition('right'); // Switch to right margin
    editor.setGutterPosition('both');  // Automatic bilateral margin distribution

    // Checkpoints & Diff
    editor.saveVersion('First Milestone Draft');
  </script>
</body>
</html>

📖 API Reference

Configuration Options

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | pageLayout | 'a4' \| 'letter' \| 'legal' \| 'infinite' | 'a4' | Document page format with auto-pagination. | | gutterPosition | 'right' \| 'left' \| 'both' | 'right' | Annotation margin space placement mode. | | toolbar | boolean \| object | true | Full toolbar configuration: { visible, defaults, show, hiddenItems, items }. | | toolbarDefaults | object | {} | Shortcut for default values (style, fontSize, lineHeight, etc.). | | user | { id, name, color } | Author | Active user credentials and highlight color. | | users | Array<{ id, name, color }> | Default list | Pre-populated team collaborators. | | collab | boolean \| object | true | Real-time collaboration: { roomId, serverUrl, user } (BroadcastChannel across tabs + WebSocket over network). | | placeholder | string | 'Write something...' | Watermark text displayed on empty pages. | | readOnly | boolean | false | Locks document editing. | | autoFocus | boolean | false | Focuses the first page on load. |

Toolbar Customization & Default Values

import { RichEditor } from 'richtext-all';

const editor = new RichEditor('#editor', {
  pageLayout: 'a4',
  toolbar: {
    visible: true,               // Set false to start with toolbar completely hidden
    defaults: {
      style: 'p',                // 'p' | 'h1'-'h6' | 'blockquote' | 'codeBlock'
      fontSize: '16',            // '12' | '14' | '16' | '18' | '20' | '24' | '32'
      lineHeight: '1.6',         // '1.0' | '1.2' | '1.4' | '1.5' | '1.6' | '2.0'
      color: '#0f172a',          // Default text color hex
      highlight: '#facc15',      // Default highlight swatch color hex
      layout: 'a4',              // 'a4' | 'letter' | 'legal' | 'infinite'
      margin: 'right',           // 'right' | 'left' | 'both'
      mode: 'editing',           // 'editing' | 'viewing' | 'suggesting' | 'comments'
      tableRows: 3,              // Default rows in table insertion modal
      tableCols: 3               // Default columns in table insertion modal
    },
    // Hide specific buttons or feature groups on load:
    hiddenItems: ['upload', 'table', 'mode'],
    // Or selectively show/hide via map:
    show: {
      upload: false,
      table: false
    }
  }
});

⚡ Real-Time Collaboration Setup

1. Zero-Config Multi-Tab Sync (No server needed)

Open multiple browser tabs or windows—they automatically sync via BroadcastChannel:

const editor = new RichEditor('#editor', {
  collab: {
    roomId: 'project-proposal-room',
    user: { id: 'usr-1', name: 'Alice', color: '#6366f1' }
  }
});

2. Cross-Browser & Multi-Device Sync (WebSocket)

To sync between different browsers (Chrome ↔ Firefox ↔ Edge) or different devices on your network:

  1. Start the included zero-dependency WebSocket relay server:
npm run collab
# Server listening on ws://localhost:1234
  1. Point your editor to the server:
const editor = new RichEditor('#editor', {
  collab: {
    serverUrl: 'ws://localhost:1234',
    roomId: 'team-design-room',
    user: { id: 'usr-2', name: 'Bob', color: '#ec4899' }
  }
});

Supported Toolbar Item Keys & Aliases

| Item Key | Group / Control | Aliases | | :--- | :--- | :--- | | upload | Open DOCX document button | browse | | history | Undo & Redo group | undoRedo | | undo / redo | Individual undo/redo buttons | — | | style | Paragraph, H1-H6, Quote dropdown | heading, headings | | typography | Font size & Line spacing group | fonts | | fontSize | Font size select dropdown | font | | lineHeight | Line spacing select dropdown | lineSpacing, spacing | | formatting | B, I, U, S, Tx buttons group | — | | bold / italic / underline | Individual format buttons | — | | strikeThrough | Strikethrough button | strikethrough | | removeFormat | Clear formatting (Tx) button | clearFormatting, clearFormat, tx | | colors | Text & highlight color group | — | | color | Text color picker | textColor, pen | | highlight | Highlight background swatch | bgColor, highlightColor, swatch | | align | Alignment buttons group | alignment | | list | Bulleted & Numbered list group | lists | | insert | Link, Image, Table group | — | | link / image / table | Individual insert controls | — | | page | Add Page & Layout group | — | | addPage / layout | Add Page button / Layout select | newPage, pageLayout | | review | Comment, Margin, Save Version group | — | | comment | Add Comment button | addComment, comments | | margin | Margin space dropdown (Right/Left/Both) | gutter, gutterPos, gutterPosition | | saveVersion | Save Version checkpoint button | versionHistory, saveVer, checkpoint | | mode | Document Mode dropdown | documentMode | | users | Active user switcher & +User button | user, collaborators |

Core Methods

| Method | Returns | Description | | :--- | :--- | :--- | | editor.showToolbar() | RichEditor | Shows the docked ribbon toolbar. | | editor.hideToolbar() | RichEditor | Hides the docked ribbon toolbar. | | editor.toggleToolbar(force?) | RichEditor | Toggles toolbar ribbon visibility. | | editor.isToolbarVisible() | boolean | Returns true if toolbar is currently displayed. | | editor.showToolbarItem(key) | RichEditor | Displays a specific toolbar item or group. | | editor.hideToolbarItem(key) | RichEditor | Hides a specific toolbar item or group. | | editor.toggleToolbarItem(key, force?) | RichEditor | Toggles visibility of a specific toolbar item. | | editor.isToolbarItemVisible(key) | boolean | Returns whether the item is currently visible. | | editor.setToolbarItemVisibility(key, visible) | RichEditor | Sets visibility of a single item or group. | | editor.setToolbarItemsVisibility(map) | RichEditor | Batch sets visibility e.g. { upload: false, table: false }. | | editor.setToolbarDefaults(defaults) | object | Sets and applies default values (fontSize, margin, etc.). | | editor.getToolbarDefaults() | object | Returns current toolbar default values. | | editor.setGutterPosition(pos) | string | Sets margin space ('left', 'right', or 'both'). | | editor.getGutterPosition() | string | Returns current margin space. | | editor.toggleGutterPosition() | string | Cycles margin: right ➔ left ➔ both ➔ right. | | editor.setLayout(type) | void | Changes page layout ('a4', 'letter', 'legal', 'infinite'). | | editor.addNewPage() | HTMLElement | Appends a new physical page sheet to the end. | | editor.insertPageAt(pageNumber, html?) | HTMLElement | Inserts a new page sheet at the specified 1-based page position. | | editor.insertPageAfter(pageNumber, html?) | HTMLElement | Inserts a new page sheet immediately after pageNumber. | | editor.insertPageBefore(pageNumber, html?) | HTMLElement | Inserts a new page sheet immediately before pageNumber. | | editor.removePage(pageNumber) | boolean | Removes a page sheet by its 1-based number. | | editor.movePage(fromNumber, toNumber) | boolean | Moves a page from one position to another and updates DOM. | | editor.movePageUp(pageNumber) | boolean | Swaps page with the preceding page sheet. | | editor.movePageDown(pageNumber) | boolean | Swaps page with the following page sheet. | | editor.reorderPages(newOrderArray) | boolean | Reorders all pages according to an array of page numbers (e.g. [3, 1, 2]). | | editor.getPageCount() | number | Returns total number of physical pages. | | editor.getPage(pageNumber) | HTMLElement \| null | Returns the page sheet DOM element. | | editor.getPageHTML(pageNumber) | string | Returns HTML content of a specific page. | | editor.setPageHTML(pageNumber, html) | boolean | Sets HTML content of a specific page sheet. | | editor.getData() / editor.getDocumentContext() | object | Exports complete developer context bundle (content, comments, suggestions, versions, metadata, settings). | | editor.setData(bundle) / editor.setDocumentContext(bundle) | boolean | Restores entire document context from exported JSON bundle. | | editor.saveVersion(title, description?) | object | Creates a named version checkpoint with comments and layout state. | | editor.getVersions() | Array<object> | Returns array of all saved version checkpoints. | | editor.setVersions(versionsList) | Array<object> | Imports/sets a custom array of versions. | | editor.getVersion(id) | object \| null | Retrieves a specific checkpoint by ID (or 'live'). | | editor.deleteVersion(id) | object \| false | Removes a version checkpoint by ID. | | editor.restoreVersion(id, opts?) | object \| null | Restores document HTML, comments, and settings to that version. | | editor.compareVersions(idA, idB?) | object | Computes word-by-word diff with stats, leftHtml, rightHtml, unifiedHtml. | | editor.getComparisonList() | Array<object> | Returns chronological timeline of versions with incremental diff stats. | | editor.showVersionComparison(idA?, idB?) | void | Opens interactive visual side-by-side / unified diff visualizer modal. | | editor.showVersionHistory() | void | Opens interactive version checkpoints modal. | | editor.addComment(text) | object | Adds a comment anchored to the active text selection. | | editor.replyComment(commentId, text, user?) | object \| null | Adds a threaded reply to an existing comment. | | editor.deleteCommentReply(commentId, replyId) | object \| false | Removes an individual reply from a comment thread. | | editor.resolveComment(commentId, resolvedBy?) | object \| null | Resolves a comment, removes document highlight, and logs reviewer audit. | | editor.deleteComment(commentId) | object \| false | Permanently deletes a comment and unwraps highlighted text. | | editor.clearAllAnnotations() | object | Permanently clears all comments & suggestions, unwraps DOM marks, and returns full audit data { deletedComments, deletedSuggestions, totalComments, totalSuggestions, timestamp }. | | editor.clearCommentsAndSuggestions() | object | Alias for editor.clearAllAnnotations(). | | editor.getComments(filter?) | Array<object> | Gets comments with optional filter: { resolved: true \| false }. | | editor.setComments(list) | Array<object> | Batch sets all comments in the document. | | editor.acceptSuggestion(id, reviewer?) | object \| null | Accepts a suggestion, applies DOM changes, and records reviewer metadata. | | editor.rejectSuggestion(id, reviewer?) | object \| null | Rejects a suggestion, unwraps/restores text, and records reviewer metadata. | | editor.getSuggestions(filter?) | Array<object> | Gets suggestions with optional filter: { status: 'pending' \| 'accepted' \| 'rejected' }. | | editor.setSuggestions(list) | Array<object> | Batch sets all tracked suggestions. | | editor.exportContextJSON(filename?) | void | Downloads complete developer document context as .json. | | editor.addUser(name, color) | object | Registers and selects a new collaborator. | | editor.setUser(userOrId) | object | Switches active author identity. | | editor.importDocument(file, options?) | Promise<string \| null> | Imports .docx, .doc, .md, .html, .txt, or .json. Prompts confirmation dialog if comments/suggestions exist before clearing them. | | editor.browseAndOpen(options?) | Promise<string \| null> | Prompts file picker with overwrite confirmation protection. | | editor.getHTML() | string | Returns clean document HTML. | | editor.getMarkdown() | string | Converts document to Markdown. | | editor.getJSON() | object | Returns structured JSON AST. | | editor.getStats() | object | Returns word count, character count, and reading time. |


📦 Developer-Friendly Document Context & Workflow API

// 1. Export Complete Document Context Bundle (Ready for Database / REST API)
const bundle = editor.getData();
console.log(bundle);
/*
{
  schemaVersion: '1.0.0',
  metadata: { title: 'Q4 Product Spec', author: 'Veeresh Poojari', stats: { words: 420, chars: 2800 } },
  settings: { pageLayout: 'a4', gutterPosition: 'both', mode: 'editing' },
  content: { html: '...', markdown: '...', text: '...', json: { ... } },
  comments: [
    {
      id: 'c-101',
      text: 'Please clarify this milestone',
      author: 'Veeresh',
      resolved: false,
      replies: [
        { id: 'rep-1', text: 'Updated with technical details', author: 'Alex', timestamp: '14:20' }
      ]
    }
  ],
  suggestions: [
    {
      id: 's-202',
      type: 'add',
      text: 'real-time multi-tab',
      author: 'Alex',
      status: 'accepted',
      reviewedBy: { id: 'usr-lead', name: 'Tech Lead', color: '#16a34a' },
      reviewedAt: '2026-10-08T12:00:00.000Z'
    }
  ],
  versions: [ ... ],
  comparisonList: [ ... ],
  users: [ ... ]
}
*/

// 2. Restore or Load Into Any Editor Instance
editor.setData(bundle);

// 3. Threaded Comments & Discussion API
const comment = editor.addComment('Review paragraph 3');
editor.replyComment(comment.id, 'Looks good to me!', { name: 'Sarah', color: '#ec4899' });
editor.resolveComment(comment.id, 'Veeresh (Lead)'); // Resolves and unhighlights text
const activeComments = editor.getComments({ resolved: false }); // Query unresolved only

// 4. Track Changes Suggestions & Reviewer Acceptance API
editor.setMode('suggesting'); // Swaps to suggesting mode
// When reviewer approves or rejects:
editor.acceptSuggestion('s-202', { id: 'usr-admin', name: 'Lead Reviewer', color: '#10b981' });
editor.rejectSuggestion('s-203', { id: 'usr-admin', name: 'Lead Reviewer', color: '#ef4444' });
const pendingSuggestions = editor.getSuggestions({ status: 'pending' });

// 5. Save Named Version Checkpoints & Visual Diffs
const v1 = editor.saveVersion('v1.0 Baseline', 'Initial draft before peer review');
const v2 = editor.saveVersion('v1.1 Review Edits', 'Addressed comments from tech lead');
const comparison = editor.compareVersions(v1.id, v2.id); // Or compare against 'live'
console.log(comparison.stats);       // { additions: 14, deletions: 3, unchanged: 180, totalChanges: 17 }
console.log(comparison.leftHtml);    // Baseline with deletions highlighted in red
console.log(comparison.rightHtml);   // Target with additions highlighted in green
console.log(comparison.unifiedHtml); // Combined inline diff

// 6. Opening Documents with Overwrite Confirmation & Database Sync
// When opening a DOCX with active comments/suggestions, a styled modal warns the user
// that all existing annotations will be permanently deleted.
// If accepted, it deletes them and loads the new document; if cancelled, the current document is preserved.

// Custom confirmation hook or bypass:
await editor.importDocument(file, {
  confirmOnOverwrite: true, // Set false to skip dialog if desired
  onConfirmOverwrite: async ({ file, commentsCount, suggestionsCount }) => {
    // Custom UI dialog (e.g. SweetAlert, AntD, Shadcn)
    return window.confirm(`Permanently remove ${commentsCount} comments and ${suggestionsCount} suggestions?`);
  }
});

// Programmatic bulk delete & database synchronization:
const audit = editor.clearAllAnnotations();
console.log('Audit Report:', audit);
/*
{
  deletedComments: [ { id: 'c-1', text: '...', ... } ],
  deletedSuggestions: [ { id: 's-1', ... } ],
  totalComments: 1,
  totalSuggestions: 1,
  timestamp: "2026-10-08T14:30:00.000Z"
}
*/
// Sync deletions with your backend database:
if (audit.totalComments > 0) {
  await myDatabase.comments.deleteMany({ id: { $in: audit.deletedComments.map(c => c.id) } });
}
if (audit.totalSuggestions > 0) {
  await myDatabase.suggestions.deleteMany({ id: { $in: audit.deletedSuggestions.map(s => s.id) } });
}

// Or listen to the documentImported event:
editor.on('documentImported', async ({ file, html, deletedAnnotations }) => {
  if (deletedAnnotations && (deletedAnnotations.totalComments > 0 || deletedAnnotations.totalSuggestions > 0)) {
    await syncDeletedAnnotationsToBackend(deletedAnnotations);
  }
});

// 7. Page Insertion & Reordering API
// Insert a new page between Page 1 and Page 2:
editor.insertPageAt(2, '<h2>Chapter 2: Architecture Deep Dive</h2><p>Overview...</p>');

// Or insert relative to existing pages:
editor.insertPageAfter(2);  // Inserts right after Page 2 (becomes Page 3)
editor.insertPageBefore(1); // Inserts brand new cover page (becomes Page 1)

// Reorder pages:
editor.movePage(3, 1);     // Moves Page 3 to the very front (Page 1)
editor.movePageUp(2);      // Swaps Page 2 with Page 1
editor.movePageDown(2);    // Swaps Page 2 with Page 3

// Batch reorder all pages to a new sequence:
editor.reorderPages([3, 1, 2]); // Page 3 becomes Page 1, Page 1 becomes Page 2, Page 2 becomes Page 3
console.log('Total pages:', editor.getPageCount());

🧪 Testing

Run the zero-dependency test suite covering security, pagination, card clustering, bilateral arrangement, and visual diffs:

npm test

📄 License

MIT © Veeresh Poojari.