Last active
November 3, 2024 06:09
-
-
Save speedwheel/61f69433379472404a76050553b9495c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Define types for the state getter, state setter, and snapshots | |
type StateGetter<T> = () => T; | |
type StateSetter<T> = (newState: T) => void; | |
export function createStateWithUndoRedo<T>( | |
stateGetter: StateGetter<T>, | |
stateSetter: StateSetter<T>, | |
maxHistorySize: number = 50 | |
) { | |
// History stacks for undo and redo | |
const undoStack: T[] = []; | |
let redoStack: T[] = []; | |
// Function to capture the current state as a snapshot | |
function captureState() { | |
// Push a snapshot of the current state onto the undo stack | |
undoStack.push($state.snapshot(stateGetter()) as T); // Type assertion to ensure compatibility | |
// Clear redo stack since we are making a new action | |
redoStack = []; | |
// Maintain the maximum history size | |
if (undoStack.length > maxHistorySize) { | |
undoStack.shift(); // Remove the oldest entry to keep within limit | |
} | |
} | |
// Function to perform an action and capture state | |
function performAction(action: () => void) { | |
captureState(); | |
action(); // Execute the action that modifies the state | |
} | |
// Undo function | |
function undo() { | |
if (undoStack.length > 0) { | |
// Push the current state onto the redo stack | |
redoStack.push($state.snapshot(stateGetter()) as T); // Type assertion to ensure compatibility | |
// Pop the last state from the undo stack and revert to it | |
const previousState = undoStack.pop(); | |
if (previousState) { | |
stateSetter(previousState); | |
} | |
} | |
} | |
// Redo function | |
function redo() { | |
if (redoStack.length > 0) { | |
// Push the current state onto the undo stack | |
undoStack.push($state.snapshot(stateGetter()) as T); // Type assertion to ensure compatibility | |
// Pop the last state from the redo stack and apply it | |
const nextState = redoStack.pop(); | |
if (nextState) { | |
stateSetter(nextState); | |
} | |
} | |
} | |
return { | |
performAction, | |
undo, | |
redo, | |
canUndo: () => undoStack.length > 0, | |
canRedo: () => redoStack.length > 0 | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment