From fc70d5f3310b25d7088d351375d1824202814f16 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Tue, 14 Jul 2026 12:55:28 -0700 Subject: [PATCH] fix(studio): guard slider release reentrancy, scope Grade persist to schedule-time callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the four blockers from the #2416 re-review at head d6a40c38b: - FlatSlider's onPointerUp calls releasePointerCapture() explicitly, which fires lostpointercapture SYNCHRONOUSLY in real browsers — the prior unconditional onLostPointerCapture resync ran mid-onPointerUp, flipping draggingRef false before onPointerUp's own check, silently dropping every normal drag-release's final commitDraft(). happy-dom doesn't replicate the synchronous cascade, so this shipped without a failing test. Added an explicitReleaseRef flag set right before each deliberate releasePointerCapture() call so onLostPointerCapture can tell "our own release, caller's logic already handles it" apart from a genuine external capture loss. Added a regression test that monkey-patches releasePointerCapture to reproduce the real-browser ordering. - persistColorGradingValue read onSetAttributeLiveRef.current (reassigned every render) instead of the callback live when the debounced edit was scheduled — a timer for element A firing after a re-render for element B would wrongly call B's callback with A's data. Removed the ref; the callback is now an explicit parameter captured by commitColorGrading's own closure (added to its useCallback deps) and threaded through to persistColorGradingValue and flushPendingPersist. - flushPendingPersist passed () => true as its isLatestAttempt checker, bypassing the per-commit version guard entirely. Now calls bumpDomEditCommitVersion(gradingVersionRef) like a regular debounced commit, so a newer edit landing before the flushed write settles still wins the race. - The selection-identity cleanup effect stopped clearing statusTimersRef during an earlier refactor — stale RUNTIME_STATUS_REFRESH_DELAYS timers for an outgoing element could fire after switching selection and stamp the new element's runtimeStatus with the old element's answer. Restored the clear in the same effect cleanup. Also gave the Custom LUT and "Copy grade to" scope { const src = e.target.value; @@ -525,6 +526,7 @@ export function FlatColorGradingSection({ Copy grade to