Skip to content

Version History

Vizel 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 { useVizelEditor, useVizelVersionHistory, VizelProvider, VizelEditor } from "@vizel/react";

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

  return (
    <VizelProvider editor={editor}>
      <VizelEditor />
      <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>
    </VizelProvider>
  );
}

Vue

vue
<script setup lang="ts">
import { useVizelEditor, useVizelVersionHistory, VizelProvider, VizelEditor } from "@vizel/vue";

const editor = useVizelEditor({});
const { snapshots, saveVersion, restoreVersion, deleteVersion } =
  useVizelVersionHistory(() => editor.value, {
    maxVersions: 20,
    key: "my-doc-versions",
  });
</script>

<template>
  <VizelProvider :editor="editor">
    <VizelEditor />
    <button @click="saveVersion('Manual save')">Save Version</button>
    <ul>
      <li v-for="s in snapshots" :key="s.id">
        {{ s.description ?? "Untitled" }} —
        {{ new Date(s.timestamp).toLocaleString() }}
        <button @click="restoreVersion(s.id)">Restore</button>
        <button @click="deleteVersion(s.id)">Delete</button>
      </li>
    </ul>
  </VizelProvider>
</template>

Svelte

svelte
<script lang="ts">
import { createVizelEditor, createVizelVersionHistory, VizelProvider, VizelEditor } from "@vizel/svelte";

const editor = createVizelEditor({});
const history = createVizelVersionHistory(() => editor.current, {
  maxVersions: 20,
  key: "my-doc-versions",
});
</script>

<VizelProvider editor={editor.current}>
  <VizelEditor />
  <button onclick={() => history.saveVersion("Manual save")}>
    Save Version
  </button>
  <ul>
    {#each history.snapshots as s}
      <li>
        {s.description ?? "Untitled"} —
        {new Date(s.timestamp).toLocaleString()}
        <button onclick={() => history.restoreVersion(s.id)}>Restore</button>
        <button onclick={() => history.deleteVersion(s.id)}>Delete</button>
      </li>
    {/each}
  </ul>
</VizelProvider>

Options

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

maxVersions

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

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

storage

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

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

// Custom backend (e.g., API)
useVizelVersionHistory(() => 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 VizelVersionSnapshot {
  /** 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
ReactuseVizelVersionHistory(getEditor, options)
VueuseVizelVersionHistory(getEditor, options)
SveltecreateVizelVersionHistory(getEditor, options)

Return Values

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

TIP

In Vue, snapshots, isLoading, and error are ComputedRef values — access them with .value in script or directly in templates.

Core Handlers

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

typescript
import {
  createVizelVersionHistoryHandlers,
  type VizelVersionHistoryState,
} from "@vizel/core";

const handlers = createVizelVersionHistoryHandlers(
  () => editor,
  { maxVersions: 20, key: "my-versions" },
  (state: Partial<VizelVersionHistoryState>) => {
    // 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.