Colour widget: commit the value being released

The brightness column changes and commits in one handler, so the commit
read the render's draft (still null) and sent nothing; the queued draft then
stuck and rode along with the next release. The pending colour lives in a ref
now. color-drag.spec gains a column drag.
This commit is contained in:
Melvin Strobl
2026-10-14 08:44:38 +02:00
parent a5afd88a5e
commit 13a0c69edc
2 changed files with 59 additions and 9 deletions
@@ -1,4 +1,4 @@
import { useState } from "react"
import { useRef, useState } from "react"
import { usePublish } from "./publish"
import { useUi } from "./ui"
@@ -46,6 +46,10 @@ export function ColorWidget({ widget, dashboard }: WidgetProps) {
const { target, value, send, pulse, locked } = usePublish(widget, dashboard)
// While dragging, the disc follows the finger rather than the engine.
const [draft, setDraft] = useState<Triple | null>(null)
// What a release sends. The brightness column changes and commits in one
// handler, before `setDraft` has rendered, so the state would still be the
// last render's — read the value from here, which is set the moment it moves.
const pending = useRef<Triple | null>(null)
if (!target) return <p className="text-muted-foreground">Pick a message.</p>
const format = colorFormatOf(widget)
@@ -59,10 +63,14 @@ export function ColorWidget({ widget, dashboard }: WidgetProps) {
name={widget.title || target}
hsv={current}
disabled={locked}
onChange={setDraft}
onChange={(hsv) => {
pending.current = hsv
setDraft(hsv)
}}
onCommit={() => {
if (draft === null) return
send(encodeColor(draft, format))
if (pending.current === null) return
send(encodeColor(pending.current, format))
pending.current = null
setDraft(null)
}}
/>