diff --git a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx index 86cdc1064..d11f2abd5 100644 --- a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx +++ b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx @@ -263,6 +263,34 @@ describe("TimelineTrackHeader", () => { act(() => view.root.unmount()); }); + // The visibility control is the old hide eye. On an audio track it silences + // rather than hides, and the row already says so with a speaker elsewhere — + // so the eye's slot stays empty there. A non-audio track is untouched. + it("keeps the visibility control off audio track headers", () => { + const audio: TimelineElement = { ...ELEMENT, tag: "audio" }; + const view = renderHeader({ + keyframeClip: audio, + trackElements: [audio], + isAudioTrack: true, + animations: [], + }); + const labels = Array.from(view.host.querySelectorAll("button")).map((b) => + b.getAttribute("aria-label"), + ); + expect(labels.some((l) => l && /^(Hide|Show) track/.test(l))).toBe(false); + expect(labels).not.toContain("Mute"); + act(() => view.root.unmount()); + }); + + it("keeps it on a non-audio track", () => { + const view = renderHeader({ isAudioTrack: false }); + const labels = Array.from(view.host.querySelectorAll("button")).map((b) => + b.getAttribute("aria-label"), + ); + expect(labels.some((l) => l && /^Hide track/.test(l))).toBe(true); + act(() => view.root.unmount()); + }); + // The eye acts on the layer, so it has to be reachable without a pointer and // in every disclosure state — a hover-gated eye is unusable by keyboard. it("keeps the visibility eye mounted whether the layer is expanded or collapsed", () => { diff --git a/packages/studio/src/player/components/TimelineTrackHeader.tsx b/packages/studio/src/player/components/TimelineTrackHeader.tsx index 1f246e93d..9c88b7cc9 100644 --- a/packages/studio/src/player/components/TimelineTrackHeader.tsx +++ b/packages/studio/src/player/components/TimelineTrackHeader.tsx @@ -600,7 +600,7 @@ export function TimelineTrackHeader({ hidden={isTrackHidden} trackNumber={trackNumber} trackDisplayNumber={trackDisplayNumber} - visible + visible={!isAudioTrack} isAudioTrack={isAudioTrack} onToggle={onToggleTrackHidden} /> diff --git a/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx b/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx index 6f1cf65f9..e5dacfcd9 100644 --- a/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx +++ b/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx @@ -103,11 +103,16 @@ export function PlainTrackHeader({ )} {showTrackLabel && } + {/* Not on an audio track. The control is the old visibility eye, and on + audio it silences rather than hides — but a row that already says what + it is with a speaker does not also need the hide affordance sitting in + the eye's slot. `visible={false}` rather than omitting the element, so + the spacer keeps every row's control columns aligned. */}