Skip to main content
Edits, pastes, fills, clears, inserts, deletes and imports are all mutations. A mutation is a labelled record of what changed, so it can be applied, sent to the source, inverted and undone. In tally-react the undo message reads from the label, such as Undid Paste 2 cells.

The Mutation object

createMutation({ label, changes?, inserted?, deleted? }) fills in id and at. applyMutation(rows, mutation, schema, direction?) applies one forward or backward, and invertMutation swaps every change and turns inserts into deletes and back.

Editing through the grid

edits.ts
setCells parses every value with the column type, so '$5k' becomes 5000 in a currency column. An empty value becomes null. Values that do not parse and values that do not change are skipped, and a call that changes nothing commits nothing. tally-react uses the verbs Paste, Fill and Clear. grid.newRow() creates a blank row with a fresh UUID key. Pass newRow to the grid when the key is a function or needs another shape.

Optimistic updates

A commit applies to the grid’s rows at once, then goes to the source’s mutate. When the source answers accepted: false or throws, the mutation is reverted and removed from history, and the result carries the errors. A source without mutate keeps edits in the grid only.

Undo and redo

grid.undo() reverts the last mutation in the grid and sends its inverse to the source. grid.redo() applies it again and sends it. When the source rejects either one, the grid steps back. The row store at grid.rows keeps the history: A new commit after an undo drops the mutations that were undone.

Live patches

Changes from outside the grid arrive as patches rather than mutations. A patch upserts and deletes rows by key, and it is not part of the undo history. Local mutations made since the last load are replayed on top of the patched rows.
patch.ts
When the view is sorted and not grouped, a patched row moves to its new position in the sort, so a changed value re-ranks in place without a reload. Cells whose values changed are tracked in grid.rows.get().changed, and the is:changed flag filters to their rows. grid.rows.clearChanged() resets them.