Examples
Todo List with Undo
Section titled “Todo List with Undo”import { timeTravel } from "@biswaviraj/time-travel";
type Todo = { id: number; text: string; done: boolean };
const tt = timeTravel<Todo[]>([]);let nextId = 1;
function addTodo(text: string) { tt.add([...tt.get(), { id: nextId++, text, done: false }]);}
function toggleTodo(id: number) { tt.add(tt.get().map((t) => (t.id === id ? { ...t, done: !t.done } : t)));}
function removeTodo(id: number) { tt.add(tt.get().filter((t) => t.id !== id));}
addTodo("Buy groceries");addTodo("Walk the dog");toggleTodo(1);
tt.get();// [{ id: 1, text: "Buy groceries", done: true }, { id: 2, text: "Walk the dog", done: false }]
tt.undo(); // un-toggle: groceries back to done: falsett.undo(); // removes "Walk the dog"Form with Undo/Redo
Section titled “Form with Undo/Redo”import { timeTravel } from "@biswaviraj/time-travel";
type FormState = { name: string; email: string; bio: string;};
const form = timeTravel<FormState>( { name: "", email: "", bio: "" }, { limit: 30 },);
// Simulate user filling out a formform.add({ name: "Alice", email: "", bio: "" });form.add({ name: "Alice", email: "alice@example.com", bio: "" });form.add({ name: "Alice", email: "alice@example.com", bio: "Hello world" });
// User changes their mind about the bioform.undo();form.get().bio; // ""
// Actually, bring it backform.redo();form.get().bio; // "Hello world"Canvas Drawing with Undo
Section titled “Canvas Drawing with Undo”import { timeTravel } from "@biswaviraj/time-travel";
type Point = { x: number; y: number };type Stroke = Point[];
const canvas = timeTravel<Stroke[]>([], { limit: 50 });
function addStroke(stroke: Stroke) { canvas.add([...canvas.get(), stroke]);}
addStroke([ { x: 0, y: 0 }, { x: 10, y: 5 }, { x: 20, y: 0 },]);addStroke([ { x: 5, y: 5 }, { x: 15, y: 15 },]);
canvas.get().length; // 2 strokescanvas.undo();canvas.get().length; // 1 strokecanvas.redo();canvas.get().length; // 2 strokesSyncing State to localStorage
Section titled “Syncing State to localStorage”Use subscribe to persist state changes automatically.
import { timeTravel } from "@biswaviraj/time-travel";
const tt = timeTravel<string>("draft");
tt.subscribe((state) => { localStorage.setItem("editor-content", state);});
tt.add("draft - updated");// localStorage now has "draft - updated"
tt.undo();// localStorage now has "draft"Bulk Import with Batch Add
Section titled “Bulk Import with Batch Add”Use addMany when loading a sequence of states at once, like replaying a history log.
import { timeTravel } from "@biswaviraj/time-travel";
const tt = timeTravel<number>(0);
// Replay a saved history logconst savedHistory = [1, 2, 3, 4, 5];tt.addMany(savedHistory);
tt.get(); // 5tt.size; // { past: 5, future: 0 }
// You can still undo through the entire replayed historytt.go(-3); // returns 2React: Undo-able Counter
Section titled “React: Undo-able Counter”import { useTimeTravel } from "@biswaviraj/time-travel/react";
function Counter() { const { state, add, undo, redo, canUndo, canRedo } = useTimeTravel(0);
return ( <div> <p>Count: {state}</p> <button onClick={() => add(state + 1)}>+1</button> <button onClick={() => add(state - 1)}>-1</button> <button onClick={() => undo()} disabled={!canUndo}>Undo</button> <button onClick={() => redo()} disabled={!canRedo}>Redo</button> </div> );}React: Color Picker with History
Section titled “React: Color Picker with History”import { useTimeTravel } from "@biswaviraj/time-travel/react";
const colors = ["#ef4444", "#3b82f6", "#22c55e", "#eab308", "#8b5cf6"];
function ColorPicker() { const { state, add, undo, redo, canUndo, canRedo, size } = useTimeTravel( colors[0], );
return ( <div> <div style={{ width: 100, height: 100, backgroundColor: state }} /> <div> {colors.map((color) => ( <button key={color} style={{ backgroundColor: color, width: 30, height: 30 }} onClick={() => add(color)} /> ))} </div> <button onClick={() => undo()} disabled={!canUndo}>Undo</button> <button onClick={() => redo()} disabled={!canRedo}>Redo</button> <p>History: {size.past} undo / {size.future} redo</p> </div> );}