Undo & Redo
WitTable implements undo/redo through a CommandManager that maintains a history stack. Every mutating operation (cell edit, resize, merge) is wrapped in a Command object with execute() and undo() methods. Press Ctrl+Z to undo and Ctrl+Y or Ctrl+Shift+Z to redo.
View source code
import { useState, useRef, useCallback } from 'react';import { WitTable } from '@witqq/spreadsheet-react';import type { WitTableRef, CellChangeEvent } from '@witqq/spreadsheet-react';import { DemoWrapper } from './DemoWrapper';import { generateEmployees, employeeColumns } from './generate-data';import { useSiteTheme } from './useSiteTheme';
const data = generateEmployees(50);
export function UndoRedoDemo() { const { witTheme } = useSiteTheme(); const tableRef = useRef<WitTableRef>(null); const [editCount, setEditCount] = useState(0);
const handleUndo = useCallback(() => tableRef.current?.undo(), []); const handleRedo = useCallback(() => tableRef.current?.redo(), []); const handleCellChange = useCallback((_event: CellChangeEvent) => { setEditCount(prev => prev + 1); }, []);
return ( <DemoWrapper title="Live Demo" description="Double-click to edit cells. Use the buttons or Ctrl+Z / Ctrl+Y to undo and redo." height={440}> <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <div style={{ padding: '0.5rem 0.75rem', borderBottom: '1px solid #e2e8f0', flexShrink: 0, display: 'flex', gap: '0.5rem', alignItems: 'center' }}> <button onClick={handleUndo} style={{ padding: '4px 12px', cursor: 'pointer' }}>↩ Undo</button> <button onClick={handleRedo} style={{ padding: '4px 12px', cursor: 'pointer' }}>↪ Redo</button> <span style={{ fontSize: '0.8rem', color: '#64748b' }}>Edits: {editCount}</span> </div> <div style={{ flex: 1 }}> <WitTable theme={witTheme} ref={tableRef} columns={employeeColumns} data={data} showRowNumbers editable onCellChange={handleCellChange} style={{ width: '100%', height: '100%' }} /> </div> </div> </DemoWrapper> );}The history stack holds up to 100 commands by default. When the limit is reached, the oldest command is discarded.
Built-in Commands
Section titled “Built-in Commands”| Command | Description |
|---|---|
CellEditCommand | Single cell value change |
BatchCellEditCommand | Multiple cell changes (paste, cut, autofill) |
ResizeColumnCommand | Column width change |
ResizeRowCommand | Row height change |
MergeCellsCommand | Merge a cell region |
UnmergeCellsCommand | Unmerge a cell region |
InsertRowCommand | Insert a row at a given index |
DeleteRowCommand | Delete a row at a given index |
Undo/Redo Buttons
Section titled “Undo/Redo Buttons”Expose undo and redo through toolbar buttons via ref:
import { useRef, useState } from 'react';import { WitTable, WitTableRef } from '@witqq/spreadsheet-react';
function App() { const ref = useRef<WitTableRef>(null); const [canUndo, setCanUndo] = useState(false); const [canRedo, setCanRedo] = useState(false);
return ( <> <button disabled={!canUndo} onClick={() => ref.current?.getInstance().getCommandManager().undo()} > Undo </button> <button disabled={!canRedo} onClick={() => ref.current?.getInstance().getCommandManager().redo()} > Redo </button> <WitTable ref={ref} columns={columns} data={data} editable={true} onCommandExecuted={() => { setCanUndo(ref.current?.getInstance().getCommandManager().canUndo() ?? false); setCanRedo(ref.current?.getInstance().getCommandManager().canRedo() ?? false); }} /> </> );}API Reference
Section titled “API Reference”CommandManager
Section titled “CommandManager”| Method | Signature | Description |
|---|---|---|
execute | (command: Command) => void | Execute and push to history |
undo | () => void | Undo last command |
redo | () => void | Redo last undone command |
canUndo | () => boolean | Whether undo is available |
canRedo | () => boolean | Whether redo is available |
clear | () => void | Clear entire history |
Command Interface
Section titled “Command Interface”interface Command { execute(): void; undo(): void; description: string;}