resig.js
Version:
Universal reactive signal library with complete platform features: signals, animations, CRDTs, scheduling, DOM integration. Works identically across React, SolidJS, Svelte, Vue, and Qwik.
377 lines • 30.7 kB
JavaScript
/**
* Undo/Redo System
* Uses Memento<State> with coalgebraic time-travel patterns
*/
import { signal, computed } from '../core/signal';
// Coalgebraic time-travel manager
export class UndoRedoManager {
constructor(initialState, config = {}) {
this.config = config;
this.lastCommand = null;
this.mergeTimer = null;
this.history = signal([this.createMemento(initialState, 'initial')]);
this.future = signal([]);
this.currentIndex = signal(0);
this.currentState = signal(initialState);
this.commands = signal([]);
this.setupAutoMerge();
this.loadPersistedHistory();
}
// Create memento snapshot (coalgebraic unfold)
createMemento(state, id, metadata) {
return {
state: this.deepClone(state),
timestamp: Date.now(),
id,
metadata,
};
}
// Deep clone state for immutability
deepClone(obj) {
if (obj === null || typeof obj !== 'object')
return obj;
if (obj instanceof Date)
return new Date(obj.getTime());
if (obj instanceof Array)
return obj.map((item) => this.deepClone(item));
if (typeof obj === 'object') {
const cloned = {};
Object.keys(obj).forEach((key) => {
cloned[key] = this.deepClone(obj[key]);
});
return cloned;
}
return obj;
}
// Setup automatic command merging
setupAutoMerge() {
if (!this.config.autoMerge)
return;
const mergeTimeout = this.config.mergeTimeout || 1000;
this.commands.subscribe((commands) => {
if (commands.length === 0)
return;
// const _lastCommand = commands[commands.length - 1]; // Unused for now
if (this.mergeTimer) {
clearTimeout(this.mergeTimer);
}
this.mergeTimer = window.setTimeout(() => {
this.lastCommand = null;
}, mergeTimeout);
});
}
// Load persisted history
loadPersistedHistory() {
if (!this.config.persistKey)
return;
try {
const saved = localStorage.getItem(this.config.persistKey);
if (saved) {
const data = JSON.parse(saved);
this.history._set(data.history || []);
this.currentIndex._set(data.currentIndex || 0);
const currentMemento = this.history.value()[this.currentIndex.value()];
if (currentMemento) {
this.currentState._set(currentMemento.state);
}
}
}
catch (error) {
console.warn('Failed to load persisted undo/redo history:', error);
}
}
// Persist history
persistHistory() {
if (!this.config.persistKey)
return;
try {
const data = {
history: this.history.value(),
currentIndex: this.currentIndex.value(),
};
localStorage.setItem(this.config.persistKey, JSON.stringify(data));
}
catch (error) {
console.warn('Failed to persist undo/redo history:', error);
}
}
// Compress history by removing intermediate states
compressHistory() {
if (!this.config.compressHistory)
return;
const maxSize = this.config.maxHistorySize || 50;
const history = this.history.value();
if (history.length <= maxSize)
return;
// Keep first, last, and evenly distributed intermediate states
const compressed = [];
const step = Math.floor(history.length / maxSize);
for (let i = 0; i < history.length; i += step) {
compressed.push(history[i]);
}
// Always keep the last state
if (compressed[compressed.length - 1] !== history[history.length - 1]) {
compressed.push(history[history.length - 1]);
}
this.history._set(compressed);
this.currentIndex._set(Math.min(this.currentIndex.value(), compressed.length - 1));
}
// Execute command with coalgebraic time-travel
execute(command) {
const currentState = this.currentState.value();
// Try to merge with last command if auto-merge is enabled
if (this.config.autoMerge && this.lastCommand) {
if (command.canMerge?.(this.lastCommand)) {
const mergedCommand = command.merge(this.lastCommand);
this.executeInternal(mergedCommand, currentState);
return;
}
}
this.executeInternal(command, currentState);
this.lastCommand = command;
}
// Internal command execution
executeInternal(command, currentState) {
try {
const newState = command.execute(currentState);
const memento = this.createMemento(newState, command.id, {
commandName: command.name,
commandId: command.id,
});
// Clear future history (branching timeline)
this.future._set([]);
// Add to history
const history = this.history.value();
const newHistory = [
...history.slice(0, this.currentIndex.value() + 1),
memento,
];
// Limit history size
const maxSize = this.config.maxHistorySize || 50;
if (newHistory.length > maxSize) {
newHistory.splice(0, newHistory.length - maxSize);
}
this.history._set(newHistory);
this.currentIndex._set(newHistory.length - 1);
this.currentState._set(newState);
// Add command to command history
this.commands._set([...this.commands.value(), command]);
// Compress history if needed
this.compressHistory();
// Persist changes
this.persistHistory();
}
catch (error) {
console.error('Failed to execute command:', error);
}
}
// Undo operation (coalgebraic time-travel backward)
undo() {
const currentIdx = this.currentIndex.value();
const history = this.history.value();
if (currentIdx <= 0)
return false;
const previousMemento = history[currentIdx - 1];
const currentMemento = history[currentIdx];
// Move current state to future
this.future._set([currentMemento, ...this.future.value()]);
// Update current state
this.currentIndex._set(currentIdx - 1);
this.currentState._set(previousMemento.state);
this.persistHistory();
return true;
}
// Redo operation (coalgebraic time-travel forward)
redo() {
const future = this.future.value();
if (future.length === 0)
return false;
const nextMemento = future[0];
const remainingFuture = future.slice(1);
// Move state from future to history
this.future._set(remainingFuture);
this.currentIndex._set(this.currentIndex.value() + 1);
this.currentState._set(nextMemento.state);
this.persistHistory();
return true;
}
// Jump to specific point in history (coalgebraic time-travel to index)
jumpTo(index) {
const history = this.history.value();
if (index < 0 || index >= history.length)
return false;
const currentIdx = this.currentIndex.value();
const targetMemento = history[index];
if (index < currentIdx) {
// Moving backward - add states to future
const statesToFuture = history.slice(index + 1, currentIdx + 1).reverse();
this.future._set([...statesToFuture, ...this.future.value()]);
}
else if (index > currentIdx) {
// Moving forward - remove states from future
const statesToRemove = index - currentIdx;
this.future._set(this.future.value().slice(statesToRemove));
}
this.currentIndex._set(index);
this.currentState._set(targetMemento.state);
this.persistHistory();
return true;
}
// Create snapshot manually
createSnapshot(id) {
const currentState = this.currentState.value();
const memento = this.createMemento(currentState, id || `snapshot-${Date.now()}`, { type: 'manual-snapshot' });
const history = this.history.value();
const newHistory = [
...history.slice(0, this.currentIndex.value() + 1),
memento,
];
this.history._set(newHistory);
this.currentIndex._set(newHistory.length - 1);
this.future._set([]);
this.persistHistory();
}
// Get time-travel state
getTimeTravel() {
return computed(() => ({
currentIndex: this.currentIndex.value(),
history: this.history.value(),
future: this.future.value(),
canUndo: this.currentIndex.value() > 0,
canRedo: this.future.value().length > 0,
totalStates: this.history.value().length + this.future.value().length,
}));
}
// Get current state signal
getCurrentState() {
return this.currentState;
}
// Get history signal
getHistory() {
return this.history;
}
// Get commands signal
getCommands() {
return this.commands;
}
// Clear all history
clearHistory() {
const currentState = this.currentState.value();
const initialMemento = this.createMemento(currentState, 'reset');
this.history._set([initialMemento]);
this.future._set([]);
this.currentIndex._set(0);
this.commands._set([]);
this.persistHistory();
}
// Get state at specific index
getStateAt(index) {
const history = this.history.value();
return history[index]?.state || null;
}
// Check if can undo/redo
canUndo() {
return this.currentIndex.value() > 0;
}
canRedo() {
return this.future.value().length > 0;
}
// Cleanup
destroy() {
if (this.mergeTimer) {
clearTimeout(this.mergeTimer);
}
}
}
// Factory function for creating undo/redo manager
export const createUndoRedoManager = (initialState, config) => {
return new UndoRedoManager(initialState, config);
};
// Command builders
export const createCommand = (id, name, execute, undo, options) => ({
id,
name,
timestamp: Date.now(),
execute,
undo,
canMerge: options?.canMerge,
merge: options?.merge,
});
// Mergeable command for text editing
export const createTextCommand = (id, type, position, text, previousText) => ({
id,
name: `text-${type}`,
timestamp: Date.now(),
execute: (state) => {
switch (type) {
case 'insert':
return state.slice(0, position) + text + state.slice(position);
case 'delete':
return state.slice(0, position) + state.slice(position + text.length);
case 'replace':
return (state.slice(0, position) +
text +
state.slice(position + (previousText?.length || 0)));
default:
return state;
}
},
undo: (state) => {
switch (type) {
case 'insert':
return state.slice(0, position) + state.slice(position + text.length);
case 'delete':
return state.slice(0, position) + text + state.slice(position);
case 'replace':
return (state.slice(0, position) +
(previousText || '') +
state.slice(position + text.length));
default:
return state;
}
},
canMerge: (other) => {
return (other.name.startsWith('text-') &&
Math.abs(other.timestamp - Date.now()) < 1000);
},
merge: (other) => {
// Simplified merge logic - in production, implement proper text merging
return createTextCommand(`${id}-${other.id}`, type, position, text, previousText);
},
});
// Array manipulation commands
export const createArrayCommand = (type, ...args) => ({
id: `array-${type}-${Date.now()}`,
name: `array-${type}`,
timestamp: Date.now(),
execute: (state) => {
const newState = [...state];
newState[type](...args);
return newState;
},
undo: (state) => {
const newState = [...state];
// Implement reverse operations
switch (type) {
case 'push':
newState.pop();
break;
case 'pop':
newState.push(args[0]);
break;
case 'shift':
newState.unshift(args[0]);
break;
case 'unshift':
newState.shift();
break;
case 'splice':
// Reverse splice operation
const [start, deleteCount, ...items] = args;
newState.splice(start, items.length, ...new Array(deleteCount));
break;
}
return newState;
},
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW5kby1yZWRvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2V4dGVuc2lvbnMvdW5kby1yZWRvLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILE9BQU8sRUFBVSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUF5QzFELGtDQUFrQztBQUNsQyxNQUFNLE9BQU8sZUFBZTtJQVMxQixZQUNFLFlBQWUsRUFDUCxTQUF5QixFQUFFO1FBQTNCLFdBQU0sR0FBTixNQUFNLENBQXFCO1FBTDdCLGdCQUFXLEdBQXNCLElBQUksQ0FBQztRQUN0QyxlQUFVLEdBQWtCLElBQUksQ0FBQztRQU12QyxJQUFJLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNyRSxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN6QixJQUFJLENBQUMsWUFBWSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM5QixJQUFJLENBQUMsWUFBWSxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUUzQixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVELCtDQUErQztJQUN2QyxhQUFhLENBQ25CLEtBQVEsRUFDUixFQUFVLEVBQ1YsUUFBOEI7UUFFOUIsT0FBTztZQUNMLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztZQUM1QixTQUFTLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtZQUNyQixFQUFFO1lBQ0YsUUFBUTtTQUNULENBQUM7SUFDSixDQUFD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