From b6e5afd25d4cce2b505608079c5f30b294b7cd92 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Wed, 19 Aug 2026 20:47:48 -0700 Subject: [PATCH] feat(studio): show the full name on hover for truncated rack labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rack's label column is a fixed 86px, so "Gap between repeats" reads as "Gap between re…" and "How many repeats" as "How many repe…" — the part that tells two knobs apart is the part that gets cut. The row already carried a `title`, but that is the param's HINT: what the knob does. Useful, and no substitute for the name. So the name is titled on the label itself and the hint stays on the row — two different questions, neither standing in for the other. Same fix for the three other truncating labels in the rack, since a truncated effect name is the same defect one line up: the node name, its one-line summary, and the carve module's own name and "Listen to" row. Titled unconditionally rather than only when the text overflows: whether it does depends on the rendered font and the panel's width, and a title that matches the visible text costs nothing. Two tests, mutation-checked — the label carries the full name, the row still carries the hint, and the label is titled even when there is no hint. Co-Authored-By: Claude Opus 5 (1M context) --- .../editor/propertyPanelFxCarveModule.tsx | 7 ++- .../editor/propertyPanelFxControls.test.tsx | 45 +++++++++++++++++++ .../editor/propertyPanelFxControls.tsx | 13 +++++- .../editor/propertyPanelFxNodeRow.tsx | 8 +++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/packages/studio/src/components/editor/propertyPanelFxCarveModule.tsx b/packages/studio/src/components/editor/propertyPanelFxCarveModule.tsx index 706595b82..e86a976ac 100644 --- a/packages/studio/src/components/editor/propertyPanelFxCarveModule.tsx +++ b/packages/studio/src/components/editor/propertyPanelFxCarveModule.tsx @@ -230,6 +230,8 @@ export function FxCarveModule({ // sets `tracking-normal`, and two Tailwind tracking utilities on one // element resolve by stylesheet order, not by the order written. style={{ color: tint, letterSpacing: "0.16em" }} + // Truncates in a narrow panel like every other name in the rack. + title="Voiceover carve" aria-expanded={open} onClick={onToggleOpen} > @@ -256,7 +258,10 @@ export function FxCarveModule({
- + Listen to {soleVoice ? ( diff --git a/packages/studio/src/components/editor/propertyPanelFxControls.test.tsx b/packages/studio/src/components/editor/propertyPanelFxControls.test.tsx index e49887582..68e35c8e8 100644 --- a/packages/studio/src/components/editor/propertyPanelFxControls.test.tsx +++ b/packages/studio/src/components/editor/propertyPanelFxControls.test.tsx @@ -113,3 +113,48 @@ describe("FxParamRow commit", () => { expect(onCommit).not.toHaveBeenCalled(); }); }); + +describe("FxParamRow label tooltip", () => { + // The label column is a fixed 86px and truncates: "Gap between repeats" reads + // as "Gap between re…", "How many repeats" as "How many repe…". The row + // already carried a `title`, but that is the HINT — what the knob does — so a + // truncated name had no way to be read in full. + const LONG: HfAudioFxNumberParam = { + kind: "number", + key: "time", + label: "Gap between repeats", + min: 0, + max: 1000, + step: 1, + default: 250, + unit: "ms", + hint: "How long before the echo comes back.", + }; + + it("titles the label with the full name, and leaves the hint on the row", () => { + const host = document.createElement("div"); + document.body.append(host); + act(() => { + createRoot(host).render(); + }); + const label = host.querySelector(".hf-fx-label"); + expect(label?.getAttribute("title")).toBe("Gap between repeats"); + // The hint stays where it was: the two are different questions, and the + // name is not a substitute for the explanation either. + expect(host.querySelector(".hf-fx-row")?.getAttribute("title")).toBe( + "How long before the echo comes back.", + ); + }); + + it("titles it even with no hint to fall back on", () => { + const host = document.createElement("div"); + document.body.append(host); + const { hint: _hint, ...noHint } = LONG; + act(() => { + createRoot(host).render(); + }); + expect(host.querySelector(".hf-fx-label")?.getAttribute("title")).toBe( + "Gap between repeats", + ); + }); +}); diff --git a/packages/studio/src/components/editor/propertyPanelFxControls.tsx b/packages/studio/src/components/editor/propertyPanelFxControls.tsx index 7b41e1f16..6895b0787 100644 --- a/packages/studio/src/components/editor/propertyPanelFxControls.tsx +++ b/packages/studio/src/components/editor/propertyPanelFxControls.tsx @@ -188,7 +188,15 @@ export function FxParamRow({ if (param.kind === "enum") { return (