From 4ac8eecc399a0e9a9758055379d8f84d559bd254 Mon Sep 17 00:00:00 2001 From: 4gray Date: Wed, 30 Sep 2026 20:27:30 +0200 Subject: [PATCH] fix(playback): decide an edge press from the panel state at pointerdown A press held on the edge past the hover dwell opened the panel before the release, which then read the open state and dismissed it. The press now remembers whether it began on an open panel. Co-Authored-By: Claude Opus 5.5 --- .../fullscreen-channel-panel.component.spec.ts | 15 +++++++++++++++ .../fullscreen-channel-panel.component.ts | 9 ++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.spec.ts b/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.spec.ts index 53f427d4d..5f99342d6 100644 --- a/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.spec.ts +++ b/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.spec.ts @@ -558,6 +558,21 @@ describe('FullscreenChannelPanelComponent', () => { expect(query('host-list')).not.toBeNull(); }); + it('keeps the panel open when the hover dwell opens it during a held press', () => { + setFullscreen(stage); + stage.dispatchEvent(pointerEvent('pointermove')); + hotZone()?.dispatchEvent(pointerEvent('pointerenter')); + hotZone()?.dispatchEvent(pointerEvent('pointerdown')); + jest.advanceTimersByTime(CHANNEL_PANEL_OPEN_DWELL_MS); + fixture.detectChanges(); + expect(isOpen()).toBe(true); + + hotZone()?.dispatchEvent(pointerEvent('pointerup')); + fixture.detectChanges(); + + expect(isOpen()).toBe(true); + }); + it('closes on the scrim but keeps the list mounted for the next opening', () => { setFullscreen(stage); openByHover(); diff --git a/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.ts b/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.ts index 07ebbf87b..72bf25238 100644 --- a/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.ts +++ b/libs/ui/playback/src/lib/fullscreen-channel-panel/fullscreen-channel-panel.component.ts @@ -151,6 +151,12 @@ export class FullscreenChannelPanelComponent implements OnDestroy { /** Pointer whose primary press began inside the hot zone, if any. */ private hotZonePressPointerId: number | null = null; + /** + * Whether that press began on an open panel. Decided at pointerdown: the + * hover dwell can open the panel while the button is still held, and that + * release must not read as a dismissal. + */ + private hotZonePressBeganOpen = false; private readonly onDocumentKeydown = (event: KeyboardEvent) => this.handleKeydown(event); @@ -236,6 +242,7 @@ export class FullscreenChannelPanelComponent implements OnDestroy { onHotZonePointerDown(event: PointerEvent): void { this.hotZonePressPointerId = event.button === 0 ? event.pointerId : null; + this.hotZonePressBeganOpen = this.state.open(); } onHotZonePointerUp(event: PointerEvent): void { @@ -244,7 +251,7 @@ export class FullscreenChannelPanelComponent implements OnDestroy { if (pressed === null || pressed !== event.pointerId) { return; } - if (this.state.open()) { + if (this.hotZonePressBeganOpen) { this.state.hide(); return; }