现象
线上 https://windup.xin/workspace(以及任何产品页),登录后点右上角头像,账号菜单会正常弹出,但**鼠标一往菜单方向移动,菜单就消失**。结果是「账号中心」「修改密码」「退出登录」三项鼠标点不到——不是难点,是没有任何一条鼠标路径能点到。
键盘用户不受影响(Tab 进菜单可用),触屏用户不受影响。受影响的是全部鼠标用户,也就是绝大多数人。
根因
app-header.tsx 的账号区域挂了 onPointerLeave 关闭:
frontend/src/app/layout/app-header.tsx:354
<div ref={accountRegionRef} aria-label="账号" onPointerLeave={accountMenu.close} ...>
菜单是点击打开的(没有 hover 打开的路径),却按 hover 菜单的方式关闭。而菜单绝对定位在区域外:
- 与头像之间隔着
top-[calc(100%+0.5rem)] = 8px 垂直空隙
- 菜单 176px 宽、头像按钮 110px 宽且右对齐,菜单向左探出约 66px
这两块区域都不属于账号区域本身,也不是它的后代。鼠标从头像走向菜单必然经过它们,pointerleave 于是在指针到达菜单之前就触发,菜单关闭。
实测(真实构建产物 + 真实鼠标轨迹,1440×900):
未修复:点开=open → 鼠标移到「账号中心」上=closed → 点击无效,仍停在 /workspace
去掉 pointerleave:点开=open → 移到「账号中心」上=open → 点击进入 /account
引入位置
#913(69f3e8ed,2026-08-29)把「指针离开」加进了关闭路径,与点击外部、Escape、失焦并列。另外三条都是正确的关闭路径,只有这一条与「点击打开」的交互模型冲突。
线上部署(last-modified: 2026-08-29)已包含该改动,压缩包里可见 onPointerLeave:h.close。
建议
移除 onPointerLeave 关闭。菜单的关闭已经由区域外 pointerdown、Escape、焦点移出以及点击菜单项四条路径覆盖,去掉这一条不会留下关不掉的浮层。
如果要保留「移出即关」的手感,则需要同时补上 hover 打开、把空隙纳入命中区(安全三角或透明桥接),本 issue 不主张这条路线——顶栏另外两个浮层(active-run 菜单、页面内 popover)都是纯点击模型,统一更省。
现象
线上 https://windup.xin/workspace(以及任何产品页),登录后点右上角头像,账号菜单会正常弹出,但**鼠标一往菜单方向移动,菜单就消失**。结果是「账号中心」「修改密码」「退出登录」三项鼠标点不到——不是难点,是没有任何一条鼠标路径能点到。
键盘用户不受影响(Tab 进菜单可用),触屏用户不受影响。受影响的是全部鼠标用户,也就是绝大多数人。
根因
app-header.tsx的账号区域挂了onPointerLeave关闭:菜单是点击打开的(没有 hover 打开的路径),却按 hover 菜单的方式关闭。而菜单绝对定位在区域外:
top-[calc(100%+0.5rem)]= 8px 垂直空隙这两块区域都不属于账号区域本身,也不是它的后代。鼠标从头像走向菜单必然经过它们,
pointerleave于是在指针到达菜单之前就触发,菜单关闭。实测(真实构建产物 + 真实鼠标轨迹,1440×900):
引入位置
#913(
69f3e8ed,2026-08-29)把「指针离开」加进了关闭路径,与点击外部、Escape、失焦并列。另外三条都是正确的关闭路径,只有这一条与「点击打开」的交互模型冲突。线上部署(
last-modified: 2026-08-29)已包含该改动,压缩包里可见onPointerLeave:h.close。建议
移除
onPointerLeave关闭。菜单的关闭已经由区域外pointerdown、Escape、焦点移出以及点击菜单项四条路径覆盖,去掉这一条不会留下关不掉的浮层。如果要保留「移出即关」的手感,则需要同时补上 hover 打开、把空隙纳入命中区(安全三角或透明桥接),本 issue 不主张这条路线——顶栏另外两个浮层(active-run 菜单、页面内 popover)都是纯点击模型,统一更省。