Editing an alignment
The alignment never edits its data. It reports what the user asked for, and you decide what happens. Double-click a name to rename it, hover a name for its ×, select columns (Shift-drag) and press Delete:
The simplest version: a history of alignments
Section titled “The simplest version: a history of alignments”const [history, setHistory] = useState([initial]);const alignment = history[history.length - 1];const apply = (next) => setHistory((h) => [...h, next]);const undo = () => setHistory((h) => h.slice(0, -1));
<MultipleSequenceAlignment msa={alignment} onRenameRow={(id, name) => apply(alignment.map((s) => (s.id === id ? { ...s, identifier: name } : s)))} onRemoveRows={(ids) => apply(alignment.filter((s) => !ids.includes(s.id)))} onRemoveColumns={(cols) => { const removed = new Set(cols); apply(alignment.map((s) => ({ ...s, sequence: [...s.sequence].filter((_, i) => !removed.has(i)).join("") }))); }}/>;Give every row an id (e.g. its original identifier) so a renamed row keeps its identity — selection
and row order are keyed by it.
An edit log
Section titled “An edit log”For reproducibility, record edits instead of snapshots and replay them over the original, as acacia does:
type Edit = | { type: "rename"; id: string; name: string } | { type: "remove_row"; id: string } | { type: "remove_column"; originalIndex: number };Columns are reported as indices into the alignment as displayed; map them back to original indices before logging, so the log stays valid as earlier columns disappear. The log can be saved as JSON and replayed later on the same input.