penpot/frontend
Andrey Antukh 531e276a69 🐛 Fix workspace crash on rapid sidebar measures input changes (#10793)
The sidebar measures panel numeric inputs (X, Y, width, height,
rotation) emitted one full apply-modifiers commit per DOM event with
no throttle: every arrow key-repeat, wheel tick and scrub pointermove
became update-positions / update-dimensions / increase-rotation. A
sustained gesture starved the React renderer and crashed the
workspace with error #185 (Maximum update depth exceeded).

Coalesce those bursts at the data layer (potok), following the
update-position-data debounce pattern in texts.cljs:

- update-positions is now burst-coalesced in place (its only caller
  is the measures panel); new update-dimensions-coalesced and
  increase-rotation-coalesced variants are used by the measures
  panel, while the immediate events keep serving plugins, variants
  and token application (including the delta? rotation path).
- The first event of a burst commits immediately (leading edge, so
  single edits stay synchronous); further ticks commit at most once
  per 50 ms (throttle); a trailing debounced flush guarantees the
  exact final value lands. All payloads are absolute values, so
  keeping the latest queued value per shape/attribute is lossless.
- Pending payloads are drained atomically and stale shape ids
  (deleted mid-burst) are skipped. The drain stream lives until the
  workspace is finalized, so bursts reuse a single subscription.
- Fewer commits per burst also means fewer undo entries; scrub drags
  still produce a single entry via the input's outer transaction.

Tests: new frontend-tests.logic.sidebar-transform-coalescing-test (8
tests, legacy SVG and WASM renderer branches) guards the invariant
that a 20-event burst commits the exact final value in a handful of
commits. The previously unregistered update-position-test is wired
into the runner with WASM mock fixtures (it fails in full-suite
context without them due to a pre-existing global mock-state issue).

AI-assisted-by: kimi-k3
2026-08-03 17:50:09 +02:00
..
2026-06-22 14:35:10 +02:00
2026-05-29 11:24:58 +02:00
2026-04-07 21:35:00 +02:00
2026-07-30 16:56:10 +02:00
2026-07-30 13:05:28 +02:00
2026-07-31 18:53:05 +02:00
2026-07-31 18:53:05 +02:00
2026-07-31 18:53:05 +02:00
2026-07-31 18:53:05 +02:00