diff --git a/packages/studio/src/player/components/LayerDisclosureRow.tsx b/packages/studio/src/player/components/LayerDisclosureRow.tsx index b630482d6..c061da300 100644 --- a/packages/studio/src/player/components/LayerDisclosureRow.tsx +++ b/packages/studio/src/player/components/LayerDisclosureRow.tsx @@ -50,7 +50,9 @@ export function LayerDisclosureRow({ > ◇ - {name} + + {name} + ); } diff --git a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx index 57d6fb127..094b54a5f 100644 --- a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx +++ b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx @@ -167,6 +167,37 @@ describe("TimelineTrackHeader", () => { act(() => view.root.unmount()); }); + // The lane header sits inside the track row, whose own click handler selects + // the track. Every control in the label column has to own its click, or + // seeking to a keyframe also reselects whatever is behind the header. + it("keeps lane-header control clicks off the ancestor track row", () => { + const onAncestorClick = vi.fn(); + const view = renderHeader({ + currentTime: 1, + onSeek: vi.fn(), + onTogglePropertyGroupKeyframe: vi.fn(), + }); + // React 18 delegates from the root container, so an ancestor of it is where + // a leaked click actually shows up. + document.body.addEventListener("click", onAncestorClick); + + // Every control in the lane's label column, found by row rather than by + // label, so a wording change to one button can't silently drop it here. + const controls = view.host.querySelectorAll( + '[data-property-group="position"] button', + ); + expect(controls.length).toBeGreaterThanOrEqual(3); + for (const button of controls) { + act(() => { + button.dispatchEvent(new MouseEvent("click", { bubbles: true })); + }); + } + + document.body.removeEventListener("click", onAncestorClick); + expect(onAncestorClick).not.toHaveBeenCalled(); + act(() => view.root.unmount()); + }); + it("fills the toggle diamond exactly at that group's keyframe", () => { const view = renderHeader({ currentTime: 0.5 }); const positionToggle = view.host.querySelector( diff --git a/packages/studio/src/player/components/TimelineTrackHeader.tsx b/packages/studio/src/player/components/TimelineTrackHeader.tsx index e27812aab..c0fac5b49 100644 --- a/packages/studio/src/player/components/TimelineTrackHeader.tsx +++ b/packages/studio/src/player/components/TimelineTrackHeader.tsx @@ -197,7 +197,11 @@ function LegacyTrackHeader({ {isAudioTrack && (