fix(studio): widen FlatSlider's click/drag hit area vertically

The track's visible line was only 2px tall, and pointerdown was bound
directly to that thin element, making it hard to grab. The hit area is
now 20px tall (a wrapping div) with the visible line rendered as a
thin decorative child, centered inside it — the ratio math only reads
left/width so click accuracy is unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-07-14 15:51:56 -07:00
co-authored by Claude Sonnet 5
parent 2aefec3e68
commit ce07dfcd4d
2 changed files with 43 additions and 16 deletions
@@ -253,6 +253,33 @@ describe("FlatSlider", () => {
expect(onCommit).toHaveBeenCalledWith(50); expect(onCommit).toHaveBeenCalledWith(50);
act(() => root.unmount()); act(() => root.unmount());
}); });
it("widens the click/drag hit area vertically beyond the thin visible line", () => {
const onCommit = vi.fn();
const { host, root } = renderInto(
<FlatSlider
label="Opacity"
value={50}
min={0}
max={100}
tier="explicitCustom"
displayValue="50%"
onCommit={onCommit}
/>,
);
const track = host.querySelector<HTMLElement>('[data-flat-slider-track="true"]');
if (!track) throw new Error("expected a track element");
Object.defineProperty(track, "getBoundingClientRect", {
value: () => ({ left: 0, width: 200, top: 0, height: 20, right: 200, bottom: 20 }),
});
act(() => {
track.dispatchEvent(
new MouseEvent("pointerdown", { bubbles: true, clientX: 20, clientY: 18 }),
);
});
expect(onCommit).toHaveBeenCalledWith(10);
act(() => root.unmount());
});
}); });
describe("FlatSlider — Grade extensions", () => { describe("FlatSlider — Grade extensions", () => {
@@ -259,14 +259,13 @@ export function FlatSlider({
aria-label={label} aria-label={label}
aria-valuenow={value} aria-valuenow={value}
aria-disabled={disabled} aria-disabled={disabled}
className={`relative h-0.5 flex-1 rounded-full bg-panel-hover ${ className={`relative h-5 flex-1 ${disabled ? "cursor-not-allowed" : "cursor-pointer"}`}
disabled ? "cursor-not-allowed" : "cursor-pointer"
}`}
onPointerDown={(e) => { onPointerDown={(e) => {
if (disabled) return; if (disabled) return;
commitFromClientX(e.clientX, e.currentTarget.getBoundingClientRect()); commitFromClientX(e.clientX, e.currentTarget.getBoundingClientRect());
}} }}
> >
<div className="absolute inset-x-0 top-1/2 h-0.5 -translate-y-1/2 rounded-full bg-panel-hover">
{centerTick && ( {centerTick && (
<div <div
data-flat-slider-center-tick="true" data-flat-slider-center-tick="true"
@@ -280,6 +279,7 @@ export function FlatSlider({
style={{ width: `${clampedPct}%` }} style={{ width: `${clampedPct}%` }}
/> />
)} )}
</div>
<div <div
data-flat-slider-knob="true" data-flat-slider-knob="true"
className={`absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full ${ className={`absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full ${