Skip to content

Version History

Editu provides a version history system that lets you save, view, and restore document snapshots.

Overview

Version history enables:

  • Save snapshots — capture document state at any point
  • Restore versions — revert to a previous snapshot
  • Browse history — list all saved versions with timestamps
  • Storage flexibility — use localStorage or a custom backend
  • Version limits — automatic cleanup of old versions

Quick Start

React

tsx
import { useEdituEditor, useEdituVersionHistory, EdituProvider, EdituEditor } from "@editu/react";

function Editor() {
  const editor = useEdituEditor({});
  const { snapshots, saveVersion, restoreVersion, deleteVersion } =
    useEdituVersionHistory(() => editor, {
      maxVersions: 20,
      key: "my-doc-versions",
    });

  return (
    <EdituProvider editor={editor}>
      <EdituEditor />
      <button onClick={() => saveVersion("Manual save")}>
        Save Version
      </button>
      <ul>
        {snapshots.map((s) => (
          <li key={s.id}>
            {s.description ?? "Untitled"} —{" "}
            {new Date(s.timestamp).toLocaleString()}
            <button onClick={() => restoreVersion(s.id)}>Restore</button>
            <button onClick={() => deleteVersion(s.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </EdituProvider>
  );
}

Options

typescript
interface EdituVersionHistoryOptions {
  /** Enable version history (default: true) */
  enabled?: boolean;
  /** Maximum number of versions to keep (default: 50) */
  maxVersions?: number;
  /** Storage backend (default: 'localStorage') */
  storage?: EdituVersionStorage;
  /** Storage key for localStorage (default: 'editu-versions') */
  key?: string;
  /** Callback when a version is saved */
  onSave?: (snapshot: EdituVersionSnapshot) => void;
  /** Callback when an error occurs */
  onError?: (error: Error) => void;
  /** Callback when a version is restored */
  onRestore?: (snapshot: EdituVersionSnapshot) => void;
}

maxVersions

Limits the number of stored snapshots. When the limit is reached, Editu removes the oldest snapshot.

typescript
useEdituVersionHistory(() => editor, {
  maxVersions: 10, // Keep only the last 10 versions
});

storage

You can choose between built-in localStorage or a custom backend.

typescript
// localStorage (default)
useEdituVersionHistory(() => editor, {
  storage: "localStorage",
});

// Custom backend (e.g., API)
useEdituVersionHistory(() => editor, {
  storage: {
    save: async (snapshots) => {
      await fetch("/api/versions", {
        method: "PUT",
        body: JSON.stringify(snapshots),
      });
    },
    load: async () => {
      const res = await fetch("/api/versions");
      return res.json();
    },
  },
});

Version Snapshot

Each snapshot contains:

typescript
interface EdituVersionSnapshot {
  /** Unique identifier */
  id: string;
  /** Document content as JSON */
  content: JSONContent;
  /** Unix timestamp (milliseconds) */
  timestamp: number;
  /** Optional description */
  description?: string;
  /** Optional author name */
  author?: string;
}

API Reference

Hook / Composable / Rune

FrameworkFunction
ReactuseEdituVersionHistory(getEditor, options)

Return Values

PropertyTypeDescription
snapshotsEdituVersionSnapshot[]All stored snapshots (newest first)
isLoadingbooleanWhether history is loading
errorError | nullLast error that occurred
saveVersion(desc?, author?)Promise<EdituVersionSnapshot | null>Save current state
restoreVersion(id)Promise<boolean>Restore to a version
loadVersions()Promise<EdituVersionSnapshot[]>Reload from storage
deleteVersion(id)Promise<void>Delete a version
clearVersions()Promise<void>Delete all versions

Core Handlers

For advanced use cases, you can use the core handlers directly:

typescript
import {
  createEdituVersionHistoryHandlers,
  type EdituVersionHistoryState,
} from "@editu/core";

const handlers = createEdituVersionHistoryHandlers(
  () => editor,
  { maxVersions: 20, key: "my-versions" },
  (state: Partial<EdituVersionHistoryState>) => {
    // Handle state changes
  }
);

await handlers.saveVersion("Initial draft", "Alice");
const versions = await handlers.loadVersions();
await handlers.restoreVersion(versions[0].id);

Released under the MIT License.