Ctrl+Z After Editing a Property Field Does Nothing: The Before-State Timing Bug
TLDR
When users edit property panel inputs (e.g., changing width from 100 to 250) and pressCtrl+Z, the editor fails to revert the change. This occurs because the undo before-state snapshot was being captured during the change or blur event, after the DOM value had already updated. Capturing before-state during focus ensures the original unmodified value is saved, restoring full undo functionality.
| Event Timing | Captured Before-State Value | Restored Undo Value | User Outcome |
|---|---|---|---|
change / blur Capture | 250 (Modified) | 250 | Undo does nothing (NO-OP) |
focus Capture | 100 (Original) | 100 | Reverts position correctly |
Problem statement: the property panel undo defect
After editing an element's coordinate in the inspector panel from 100 to 250, pressing Ctrl+Z leaves the value at 250.
Pressing Ctrl+Z a second time skips the property change entirely and undoes the previous canvas operation.
The history stack contains an entry for "Property Edit", but restoring its before state fails because the recorded before-state value equals the after-state value.
Technical failure mode: input DOM value contamination
HTML form fields update their internal DOM value as users type.
Executing captureState() inside a change event handler reads the updated DOM value:
// DEFECTIVE IMPLEMENTATION: Reading state after DOM modification
$('#prop-x').on('change', function() {
const before = captureState(); // Reads updated DOM value (250)
applyToModel(this.value);
const after = captureState(); // Reads updated DOM value (250)
pushHistory('Property Edit', before, after); // before === after! });
The fix: capture state on focus
Capture propBeforeState when the user focuses the field, before typing begins:
let propBeforeState = null;
// 1. Capture original value on focus $(document).on('focus', '#prop-x, #prop-y, #prop-w, #prop-h', function() { propBeforeState = captureState(); // Reads original value (100) });
// 2. Commit history on change using saved before-state $(document).on('change', '#prop-x, #prop-y, #prop-w, #prop-h', function() { const before = propBeforeState || captureState(); propBeforeState = null;
applyToModel(this.value); const after = captureState();
pushHistory('Property Edit', before, after); });
Rule of thumb: Capture property before-state during thefocusevent. Never capture before-state insidechangeorblurhandlers where input DOM values are already modified.