FN-8178: fix task-card context menu autofocus dismissal
Prevent portaled task-card menus from closing when autofocus creates a scroll event. - Focus the first menu action with preventScroll while preserving keyboard access. - Cover all card menu entry points and intentional dismissal paths. - Document the interaction lifecycle fix and publish a patch changeset. Files changed: .changeset/fn-8178-context-menu-flash-dismiss.md | 7 +++ docs/dashboard-guide.md | 2 +- .../task-card-context-menu-flash-dismiss-layers.md | 35 +++++++++++ .../dashboard/app/components/TaskContextMenu.tsx | 9 ++- .../app/components/__tests__/TaskCard.test.tsx | 69 ++++++++++++++++++++++ 5 files changed, 120 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-8178 Fusion-Task-Lineage: 2eb94ffd-e922-497d-8904-1aea8bf760b1 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "Task-card popup menus dismiss after autofocus scroll"
|
||||
date: 2026-07-16
|
||||
category: ui-bugs
|
||||
module: packages/dashboard/app/components/TaskContextMenu
|
||||
problem_type: interaction_lifecycle_race
|
||||
component: dashboard-task-card
|
||||
tags:
|
||||
- task-card
|
||||
- context-menu
|
||||
- portal
|
||||
- focus
|
||||
- scroll
|
||||
- fn-8178
|
||||
---
|
||||
|
||||
# Task-card popup menus dismiss after autofocus scroll
|
||||
|
||||
## Problem
|
||||
|
||||
A task-card context menu could flash open and immediately dismiss, leaving lifecycle actions unusable. The menu is portaled to `document.body`, but Board card and ListView hosts intentionally listen for capture-phase `scroll` and close an open menu when the operator scrolls.
|
||||
|
||||
## Root cause
|
||||
|
||||
`TaskContextMenu` automatically focused its first enabled action after mount. In browsers, focusing that fixed, portaled action can scroll a scrollable board ancestor into view. The resulting scroll reached the host's capture-phase dismissal listener, which correctly treated ordinary board scrolling as an explicit dismissal but could not distinguish focus-created scrolling. The result was an open → autofocus → scroll → close loop.
|
||||
|
||||
This was not a card stacking-context or outside-pointer containment failure: the popover is a `document.body` portal and its ref correctly recognizes presses inside the menu. All card entry methods converge on the same mounted `TaskContextMenu`, so ⋯ click, right-click, touch/pen long-press, and keyboard context-menu access shared the fault.
|
||||
|
||||
## Resolution
|
||||
|
||||
Keep automatic keyboard focus, but call `focus({ preventScroll: true })` for the first enabled menu item. This prevents the synthetic scroll while preserving intentional dismissal on item selection, outside pointerdown, Escape, and real board scrolling. Because `TaskContextMenu` is shared, ListView and Task Detail also retain their focus behavior without duplicated lifecycle guards.
|
||||
|
||||
## Regression coverage
|
||||
|
||||
The TaskCard suite simulates a browser that dispatches a scroll after default focus and verifies that each card entry method remains open with `preventScroll`, invokes its action, and still honors outside-click, Escape, and real-scroll dismissal.
|
||||
Reference in New Issue
Block a user