mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 12:54:29 +00:00
feat(studio): show the full name on hover for truncated rack labels
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) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
be71b59523
commit
b6e5afd25d
@@ -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({
|
||||
<div className="hf-fx-carve-body border-t border-panel-border-input">
|
||||
<div className="hf-fx-carve-controls space-y-0.5 px-1.5 py-1.5">
|
||||
<div className="hf-fx-row flex min-h-6 items-center gap-2">
|
||||
<span className="hf-fx-label w-[86px] flex-shrink-0 truncate text-[10px] text-panel-text-2">
|
||||
<span
|
||||
className="hf-fx-label w-[86px] flex-shrink-0 truncate text-[10px] text-panel-text-2"
|
||||
title="Listen to"
|
||||
>
|
||||
Listen to
|
||||
</span>
|
||||
{soleVoice ? (
|
||||
|
||||
@@ -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(<FxParamRow param={LONG} value={250} onChange={vi.fn()} />);
|
||||
});
|
||||
const label = host.querySelector<HTMLElement>(".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<HTMLElement>(".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(<FxParamRow param={noHint} value={250} onChange={vi.fn()} />);
|
||||
});
|
||||
expect(host.querySelector<HTMLElement>(".hf-fx-label")?.getAttribute("title")).toBe(
|
||||
"Gap between repeats",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -188,7 +188,15 @@ export function FxParamRow({
|
||||
if (param.kind === "enum") {
|
||||
return (
|
||||
<label className="hf-fx-row flex min-h-6 items-center gap-2" title={param.hint}>
|
||||
<span className="hf-fx-label w-[86px] flex-shrink-0 truncate text-[10px] text-panel-text-2">
|
||||
{/* `title` on the LABEL, not just the row: the row's is the hint, which
|
||||
explains what the knob does — useful, and no substitute for the name
|
||||
when 86px truncates it to "Gap between re…". Titled unconditionally
|
||||
rather than only when it overflows, since whether it does depends on
|
||||
the rendered font and the panel's width. */}
|
||||
<span
|
||||
className="hf-fx-label w-[86px] flex-shrink-0 truncate text-[10px] text-panel-text-2"
|
||||
title={param.label}
|
||||
>
|
||||
{param.label}
|
||||
</span>
|
||||
<select
|
||||
@@ -227,10 +235,13 @@ export function FxParamRow({
|
||||
title={param.hint}
|
||||
data-automated={automated ? "" : undefined}
|
||||
>
|
||||
{/* See the enum row above for why the name is titled here as well as the
|
||||
hint being titled on the row. */}
|
||||
<span
|
||||
className={`hf-fx-label w-[86px] flex-shrink-0 truncate text-[10px] ${
|
||||
automated ? "text-panel-accent" : "text-panel-text-2"
|
||||
}`}
|
||||
title={param.label}
|
||||
>
|
||||
{param.label}
|
||||
</span>
|
||||
|
||||
@@ -184,6 +184,9 @@ function FxNodeHeader({
|
||||
<button
|
||||
type="button"
|
||||
className={`hf-fx-node-name flex-1 truncate text-left text-[11px] text-panel-text-1 hover:text-panel-text-0 ${family}`}
|
||||
// Truncated in the same narrow column as the param labels below, so it
|
||||
// needs the same fallback to the full text on hover.
|
||||
title={label}
|
||||
aria-expanded={open}
|
||||
onClick={onToggleOpen}
|
||||
>
|
||||
@@ -304,7 +307,10 @@ export function FxNodeRow({
|
||||
onRemove={() => onRemove(index)}
|
||||
/>
|
||||
{summary ? (
|
||||
<p className="hf-fx-node-summary truncate px-1.5 pb-1 text-[10px] text-panel-text-2">
|
||||
<p
|
||||
className="hf-fx-node-summary truncate px-1.5 pb-1 text-[10px] text-panel-text-2"
|
||||
title={summary}
|
||||
>
|
||||
{summary}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user