mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-11 11:19:24 +00:00
fix(v3): dismiss Section Practice popover when another player popover opens (#638)
* fix(v3): dismiss Section Practice popover when another player popover opens The Section Practice popover (Songs > Song > Practice pill) stayed open when the user then clicked a v3 player-rail icon (Plugins, Audio, …), leaving two popovers stacked on top of each other. Reported on 0.3.0 (macOS) and still reproducing in the 2026-06-28 build. Root cause: the popover's outside-click dismiss was bound in the bubbling phase, but the v3 rail's icon buttons call e.stopPropagation() in their click handler (player-chrome.js wireRail), which kills bubbling before the click reaches document. So the dismiss listener never fired for a rail-icon click and the popover was orphaned open. Fix: bind the outside-click dismiss in the capture phase, which runs before the target's handler so stopPropagation() can't swallow it. This mirrors the audio mixer popover (audio-mixer.js), which already dismisses outside-clicks via capture-phase listeners for exactly this reason. Esc handling stays in the bubble phase (no rail handler stops keydown propagation, and capturing it would reorder it ahead of the player's Escape-to-exit handling). Shared app.js code, so v2 is covered too; v2 has no stopPropagation rail, so its outside-click dismiss behaviour is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbexxfTt8q2tAn436MqGWF * chore(#638): add CHANGELOG entry + capture-phase regression test Review follow-ups for the Section Practice popover dismiss fix: - CHANGELOG [Unreleased] → Fixed entry (repo workflow requires one). - tests/js/section_practice_dismiss.test.js pins the fix: the outside-click dismiss binds in the CAPTURE phase (so a rail icon's stopPropagation can't swallow it), exactly one capture binding (Escape keydown stays bubble-phase), and the #section-practice-control containment guard (no self-close). A revert to bubble-phase fails the test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
byrongamatos
parent
8fbbc761fc
commit
199550e5fb
+13
-1
@@ -8714,12 +8714,24 @@ function _installSectionPracticeDismiss() {
|
||||
// inside #section-practice-control so it never self-closes. Listeners added
|
||||
// mid-dispatch don't fire for the opening click, so there's no immediate
|
||||
// close race.
|
||||
//
|
||||
// The click listener uses the CAPTURE phase: the v3 player rail's icon
|
||||
// buttons call e.stopPropagation() in their click handler (player-chrome.js
|
||||
// wireRail), which kills bubbling before it reaches document. A bubble-phase
|
||||
// outside-click dismiss would therefore never fire when the user clicks a
|
||||
// rail icon (Plugins, Audio, …) to open another popover, leaving this
|
||||
// popover stranded open on top of it. Capture runs before the target's
|
||||
// handler, so the stopPropagation can't swallow it. This mirrors the audio
|
||||
// mixer popover (audio-mixer.js), which dismisses outside-clicks the same
|
||||
// way. (Esc stays bubble-phase — no rail handler stops keydown propagation,
|
||||
// so it already reaches us, and capturing it would reorder it ahead of the
|
||||
// player's Escape-to-exit handling.)
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!_sectionPracticePopoverOpen()) return;
|
||||
const ctrl = document.getElementById('section-practice-control');
|
||||
if (ctrl && ctrl.contains(e.target)) return;
|
||||
_closeSectionPracticePopover();
|
||||
});
|
||||
}, true);
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && _sectionPracticePopoverOpen()) _closeSectionPracticePopover();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user