Skip to content

Auto-Save ​

Auto-save persists editor content automatically.

Basic Usage ​

tsx
import { useEdituEditor, useEdituAutoSave, EdituEditor, EdituSaveIndicator } from '@editu/react';

function Editor() {
  const editor = useEdituEditor();
  
  const { status, lastSaved } = useEdituAutoSave(() => editor, {
    debounceMs: 2000,
    storage: 'localStorage',
    key: 'my-editor-content',
  });

  return (
    <div>
      <EdituEditor editor={editor} />
      <EdituSaveIndicator status={status} lastSaved={lastSaved} />
    </div>
  );
}

Options ​

AutoSaveOptions ​

PropertyTypeDefaultDescription
enabledbooleantrueEnable auto-save
debounceMsnumber1000Debounce delay in milliseconds
storageStorageBackend"localStorage"Storage backend
keystring"editu-content"Storage key
onSave(content) => void-Fires after a successful save
onError(error) => void-Fires on a save error
onRestore(content) => void-Fires when the system restores content

Storage Backends ​

localStorage (Default) ​

This backend persists content in the browser's localStorage:

typescript
const { status } = useEdituAutoSave(() => editor, {
  storage: 'localStorage',
  key: 'my-editor-content',
});

sessionStorage ​

This backend persists content only for the current session:

typescript
const { status } = useEdituAutoSave(() => editor, {
  storage: 'sessionStorage',
  key: 'my-editor-content',
});

Custom Backend ​

You can implement your own storage backend for server-side persistence:

typescript
const { status } = useEdituAutoSave(() => editor, {
  storage: {
    save: async (content) => {
      await fetch('/api/save', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(content),
      });
    },
    load: async () => {
      const response = await fetch('/api/content');
      if (!response.ok) return null;
      return response.json();
    },
  },
});

Return Values ​

Status ​

ValueDescription
"saved"Content has been saved and is up to date
"saving"A save operation is in progress
"unsaved"Unsaved changes exist
"error"The last save attempt failed

Properties ​

PropertyTypeDescription
statusSaveStatusCurrent save status
hasUnsavedChangesbooleanWhether there are unsaved changes
lastSavedDate | nullTimestamp of last successful save
errorError | nullLast error if status is "error"

Methods ​

MethodDescription
save()Triggers a save manually
restore()Restores content manually

Manual Save/Restore ​

typescript
const { save, restore } = useEdituAutoSave(() => editor, { storage: 'localStorage' });

// Trigger manual save
await save();

// Restore from storage
const content = await restore();
if (content) {
  editor.commands.setContent(content);
}

Save Indicator ​

The EdituSaveIndicator component displays the current save status:

tsx
import { EdituSaveIndicator } from '@editu/react';

<EdituSaveIndicator 
  status={status} 
  lastSaved={lastSaved}
  className="my-indicator"
/>

Custom Indicator ​

tsx
function CustomIndicator({ status, lastSaved }) {
  const formatTime = (date: Date) => {
    return new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
      .format(Math.round((date.getTime() - Date.now()) / 60000), 'minute');
  };

  return (
    <div className="save-indicator">
      {status === 'saving' && <span>Saving...</span>}
      {status === 'saved' && lastSaved && (
        <span>Saved {formatTime(lastSaved)}</span>
      )}
      {status === 'unsaved' && <span>Unsaved changes</span>}
      {status === 'error' && <span className="error">Save failed</span>}
    </div>
  );
}

Debouncing ​

The debounceMs option controls how long to wait after the last change before saving:

typescript
// Save 500ms after last change (more responsive)
useEdituAutoSave(() => editor, { debounceMs: 500 });

// Save 5 seconds after last change (less frequent)
useEdituAutoSave(() => editor, { debounceMs: 5000 });

Error Handling ​

You can handle save errors with the onError callback:

typescript
const { status, error } = useEdituAutoSave(() => editor, {
  storage: {
    save: async (content) => {
      const response = await fetch('/api/save', {
        method: 'POST',
        body: JSON.stringify(content),
      });
      if (!response.ok) {
        throw new Error('Failed to save');
      }
    },
  },
  onError: (error) => {
    console.error('Auto-save failed:', error);
    // Show notification to user
    toast.error('Failed to save. Please try again.');
  },
});

Restoring Content on Load ​

You can restore saved content when the editor initializes:

tsx
import { useEffect } from 'react';
import { useEdituEditor, useEdituAutoSave, EdituEditor } from '@editu/react';

function Editor() {
  const editor = useEdituEditor();
  
  const { restore } = useEdituAutoSave(() => editor, {
    storage: 'localStorage',
    key: 'my-editor-content',
    onRestore: (content) => {
      if (content) {
        console.log('Restored saved content');
      }
    },
  });

  useEffect(() => {
    if (editor) {
      restore().then((content) => {
        if (content) {
          editor.commands.setContent(content);
        }
      });
    }
  }, [editor]);

  return <EdituEditor editor={editor} />;
}

Disabling Auto-Save ​

You can temporarily disable auto-save:

typescript
const { status } = useEdituAutoSave(() => editor, {
  enabled: false, // Disable auto-save
});

Or conditionally based on state:

typescript
const [autoSaveEnabled, setAutoSaveEnabled] = useState(true);

const { status } = useEdituAutoSave(() => editor, {
  enabled: autoSaveEnabled,
});

Next Steps ​

Released under the MIT License.