@jucie-state/history
v1.0.9
Published
History plugin for @jucie-state/core - undo/redo functionality
Maintainers
Readme
@jucie-state/history
History management plugin for @jucie-state/core that provides undo/redo functionality with markers, batching, and commit listeners.
Features
- ⏪ Undo/Redo: Full undo and redo support with automatic change tracking
- 🏷️ Markers: Add descriptive markers to create logical undo/redo boundaries
- 📦 Batching: Group multiple changes into a single undo/redo step
- 🔔 Commit Listeners: React to history commits
- 🎯 Smart Change Consolidation: Automatically merges changes to the same path
- 📏 Configurable History Size: Limit the number of stored changes
Installation
npm install @jucie-state/historyNote: Requires @jucie-state/core as a peer dependency.
Quick Start
import { createState } from '@jucie-state/core';
import { HistoryManager } from '@jucie-state/history';
// Create state and install history plugin
const state = createState({
data: { count: 0 }
});
state.install(HistoryManager);
// Make some changes
state.set(['data', 'count'], 1);
state.set(['data', 'count'], 2);
state.set(['data', 'count'], 3);
console.log(state.get(['data', 'count'])); // 3
// Undo the changes
state.history.undo();
console.log(state.get(['data', 'count'])); // 2
state.history.undo();
console.log(state.get(['data', 'count'])); // 1
// Redo
state.history.redo();
console.log(state.get(['data', 'count'])); // 2
// Check if undo/redo is available
console.log(state.history.canUndo()); // true
console.log(state.history.canRedo()); // trueAPI Reference
Actions
undo(callback?)
Undo the last committed change(s).
state.history.undo(() => {
console.log('Undo completed');
});Returns: boolean - true if undo was successful, false if no changes to undo
redo(callback?)
Redo the next change(s).
state.history.redo(() => {
console.log('Redo completed');
});Returns: boolean - true if redo was successful, false if no changes to redo
canUndo()
Check if undo is available.
if (state.history.canUndo()) {
state.history.undo();
}Returns: boolean
canRedo()
Check if redo is available.
if (state.history.canRedo()) {
state.history.redo();
}Returns: boolean
Batching
batch()
Start a batch to group multiple changes into a single undo/redo step.
const endBatch = state.history.batch();
state.set(['user', 'name'], 'Alice');
state.set(['user', 'age'], 30);
state.set(['user', 'email'], '[email protected]');
endBatch(); // All three changes are now a single undo/redo step
state.history.undo(); // Undoes all three changes at onceReturns: Function - Call the returned function to end the batch
commit()
Manually commit pending changes and end the current batch.
state.history.batch();
state.set(['data', 'value'], 1);
state.history.commit(); // Forces commitReturns: HistoryManager instance (for chaining)
Markers
addMarker(description)
Add a descriptive marker to create a logical undo/redo boundary.
state.set(['user', 'name'], 'Alice');
state.history.addMarker('Set user name');
state.set(['user', 'age'], 30);
state.history.addMarker('Set user age');
// Now each undo will stop at the marker
state.history.undo(); // Undoes age change
state.history.undo(); // Undoes name changeParameters:
description(string): Optional description for the marker
Commit Listeners
onCommit(callback)
Listen for history commits.
const unsubscribe = state.history.onCommit((changes) => {
console.log('Changes committed:', changes);
});
state.set(['data', 'value'], 1);
// Console: "Changes committed: [...]"
// Remove listener when done
unsubscribe();Parameters:
callback(Function): Called with an array of changes when committed
Returns: Function - Call to remove the listener
Info
size()
Get the current number of items in the history.
const historySize = state.history.size();
console.log(`History contains ${historySize} items`);Returns: number
Configuration
Configure the history plugin using the configure() method:
import { createState } from '@jucie-state/core';
import { HistoryManager } from '@jucie-state/history';
const state = createState({
data: { count: 0 }
});
// Install with custom configuration
state.install(HistoryManager.configure({
maxSize: 200 // Limit to 200 history items (default: 100)
}));Options
maxSize(number): Maximum number of history items to keep. Default:100
Advanced Usage
Complex Batching with Markers
// Start a complex operation
state.history.batch();
state.history.addMarker('Start user registration');
state.set(['user', 'name'], 'Alice');
state.set(['user', 'email'], '[email protected]');
state.set(['user', 'preferences'], { theme: 'dark' });
state.history.commit();
// All changes are now a single undo step with a descriptive markerPause and Resume Recording
// Temporarily pause history recording (internal API)
state.plugins.history.pause();
state.set(['temp', 'data'], 'not recorded');
state.plugins.history.resume();
state.set(['tracked', 'data'], 'recorded'); // This will be recordedReset History
// Clear all history (internal API)
state.plugins.history.reset();How It Works
- Change Tracking: The plugin automatically tracks all state changes
- Consolidation: Multiple changes to the same path are consolidated
- Deferred Commits: Changes are committed asynchronously for performance
- Markers: Markers create logical boundaries for undo/redo operations
- Inversion: Changes are inverted for undo operations
Common Patterns
Form Editing with Undo/Redo
// Track form edits
function handleFieldChange(field, value) {
const endBatch = state.history.batch();
state.set(['form', field], value);
state.history.addMarker(`Update ${field}`);
endBatch();
}
// Implement undo/redo buttons
function handleUndo() {
if (state.history.canUndo()) {
state.history.undo(() => {
updateUI();
});
}
}Multi-Step Operations
function performComplexOperation() {
const endBatch = state.history.batch();
// Step 1: Update user
state.set(['user', 'status'], 'processing');
// Step 2: Create records
state.set(['records'], [{ id: 1, status: 'new' }]);
// Step 3: Update timestamp
state.set(['lastUpdate'], Date.now());
endBatch();
state.history.addMarker('Complex operation completed');
}
// All steps undo/redo as one operationLicense
See the root LICENSE file for license information.
Related Packages
- @jucie-state/core - Core state management system
- @jucie-state/matcher - Path pattern matching
- @jucie-state/on-change - Change listeners
