Skip to content

🐛 修复新建脚本按钮点击被 hover 菜单吞掉,改为直接新建用户脚本 - #1704

Merged
CodFrm merged 3 commits into
mainfrom
fix/1699-create-script-click
Aug 30, 2026
Merged

CodFrm merged 3 commits into
mainfrom
fix/1699-create-script-click

Conversation

@CodFrm

@CodFrm CodFrm commented Aug 30, 2026 •

Copy link
Copy Markdown
Member

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

背景

Fix #1699。报告人指出「不能直接點擊 Create Script」,并猜测「Create Script 的點擊跟 hover 撞了」——这个猜测是对的。

桌面工具栏的 + Create Script 按钮同时承担两个角色:

  1. Radix 的 DropdownMenuTrigger(asChild,pointerdown 会 onOpenToggle);
  2. useHoverMenu() 的 hover 触发目标(onMouseEnter → setIsOpen(true))。

菜单 open 由 useHoverMenu 受控。鼠标移上按钮 → hover 已把菜单打开;此时按下鼠标 → Radix 调 onOpenChange(!open) = false → 菜单被关掉。而鼠标并未离开按钮,不会再触发 mouseEnter,所以要移开再移回、或者再点一次才能重新展开。

复现(本地 vitest,改动前):mouseEnter trigger → 菜单展开;原地 pointerDown + click → 菜单消失;再点一次 → 又展开。用户视角就是「鼠标移上去菜单弹出来,手一按菜单没了,点了没反应」。

除此之外还有一层预期落差:按钮长得像主操作按钮(+ 图标 + Create Script 文案),但整块区域只是下拉触发器,没有任何直接新建脚本的行为;要新建必须再进菜单点 Create User Script。

该按钮自新 UI 重写(#1514)引入后一直是这个行为;现有单测只覆盖了 hover 展开与菜单项点击,没有覆盖「hover 之后点 trigger」这条路径。

本次改动

把「点击」的语义交给新建脚本,同时保证没有 hover 能力的设备仍能打开菜单。判据是 (hover: hover) 媒体查询而非视口宽度:

  • 可 hover 的指针 + 带文字按钮:hover / ArrowDown 展开菜单,点击 / Enter / Space 直接新建用户脚本。
  • 其余情况(移动 header 的 + 图标按钮、以及触摸设备上的桌面工具栏):一律点击展开菜单,与原行为一致。
场景 输入 改动前 改动后
鼠标 / 触控板 悬停 展开菜单 展开菜单(不变)
鼠标 / 触控板 点击(菜单已由 hover 展开) 菜单被关掉,无其他动作 进入编辑器新建用户脚本
鼠标 / 触控板 Enter / Space 展开菜单 进入编辑器新建用户脚本
鼠标 / 触控板 ArrowDown 展开菜单 展开菜单(不变)
触摸屏(桌面视口) 点击 展开菜单 展开菜单(不变)
移动 header 的 + 图标 点击 展开菜单 展开菜单(不变)

新增 src/pages/components/use-can-hover.ts(useCanHover),与既有的 use-is-mobile.ts 同构:useSyncExternalStore 订阅 (hover: hover),接上/拔掉鼠标时会更新。

菜单内容、导入分组、LinkImportDialog 均未改动;菜单里的 Create User Script 项改为复用同一个 createUserScript 函数。无视觉变化。

实现考虑

为什么按 hover 能力而不是视口宽度分支。 桌面工具栏在视口 ≥768px 就渲染(useIsMobile 的断点),平板横屏、触屏笔记本都落在这个区间但没有 hover。若这些设备也走 hover 菜单,下拉里的「后台脚本 / 定时脚本 / 导入本地 / 链接导入 / 导入 Skill」五个入口将完全无法触达——这会是比原 issue 更严重的回归。因此触摸设备复用已有的点击菜单路径(isHoverMenu === false),该路径本身已有测试覆盖,且不套用 useHoverMenu 的 dismiss 拦截,Esc 与点击外部都能正常关闭。

为什么用 preventDefault() 拦 Radix 的 toggle。 DropdownMenuTrigger 用 composeEventHandlers(props.onPointerDown, …) 挂载 toggle,而 composeEventHandlers 在 event.defaultPrevented 时会跳过自己那一半;asChild 走 Slot,其 mergeProps 对 on[A-Z]* 属性的合成顺序是「先子元素 handler,后 slot handler」。因此在 Button 上挂 onPointerDown={(e) => e.preventDefault()} 可以稳定拦掉 toggle,同时不影响 click 照常派发(取消 pointerdown 只阻止兼容鼠标事件与聚焦,不阻止 click)。这一依赖已写进代码注释。版本已核对:@radix-ui/react-slot@1.2.5、@radix-ui/react-dropdown-menu@2.1.17(radix-ui@1.5.0)。

e2e 环境需要显式声明指针能力。 首次推送后 CI 的 Run E2E tests (2/4) 失败:两条桌面用例挂掉、触摸用例通过——正是 canHover === false 的症状。原因是无头 Linux 检测不到任何输入设备,把 (hover: hover) / (pointer: fine) 报成 false,而无头 macOS 报 true,同一套用例在两个平台结果不同。因此在 e2e/fixtures.ts 的共享启动参数里加上 --blink-settings=availableHoverTypes=2,primaryHoverType=2,availablePointerTypes=4,primaryPointerType=4,让默认环境稳定对应「有鼠标的桌面」;触摸用例自建上下文覆盖,不受影响。同时给 hover 用例加了一行前置断言 (hover: hover) === true,以后环境再变能一眼区分「环境问题」与「功能回归」。

键盘单独处理。 Radix 在 Enter/Space 上除了 toggle 还会 preventDefault()(顺带吃掉原生 click),所以这两个键在自己的 onKeyDown 里拦下并直接调用 createUserScript();ArrowDown 不拦,仍交给 Radix 展开菜单——即「带默认操作的菜单按钮」的常规键盘模型。

已知限制

  • 按钮上的 ChevronDown 在可 hover 的设备上不再是「点这里展开」的可点击 affordance,而只是「还有更多选项」的提示。本 PR 未调整其样式。
  • preventDefault() 拦截 pointerdown 会同时抑制该按钮的鼠标聚焦。由于点击后即导航到编辑器,实际影响可忽略;键盘 Tab 聚焦不受影响。
  • 触摸设备上没有「一步直达新建用户脚本」,需经菜单第一项,与移动端 + 按钮一致。
  • 依赖 Radix Slot 的 handler 合成顺序与 composeEventHandlers 的 defaultPrevented 短路,属于 Radix 的公开行为约定,但升级 Radix 大版本时值得回归这几条测试。
  • (hover: hover) 取决于浏览器检测到的主指针。若某些环境(远程桌面、部分 Linux 配置)在有鼠标时仍报 hover: none,这些用户会退化为「点击展开菜单」,即本 PR 之前、且不含 [BUG] (UI UX)不能直接點擊"Create Script" #1699 碰撞的行为。降级方向是安全的:判据只会导致「少一个直达入口」,不会导致「菜单够不着」。

建议审查重点

  • 鼠标:hover 展开后点击,是否稳定进入编辑器且菜单不残留。
  • 触摸:平板横屏 / 触屏笔记本上点击按钮应展开菜单(而非直接进编辑器),且 Esc / 点击外部能关闭。
  • 移动 header 的 + 图标是否仍为点击展开、Esc 可关(variant="icon" 未改)。
  • 键盘:ArrowDown 展开菜单、Enter / Space 新建脚本。
  • 引导流程 data-tour="install-entry"(src/pages/options/onboarding/steps.ts)仍指向同一按钮,未受影响。

关联

Fix #1699

验证

两处行为改动均先写失败测试再改实现:CreateScriptMenu.test.tsx 先加 3 条(hover 后点击、无 hover 直接点击、键盘 Enter/ArrowDown)确认全红;触摸降级再加 2 条(点击展开菜单不导航、Esc 可关)确认全红。

npx vitest run src/pages/options/routes/ScriptList/CreateScriptMenu.test.tsx
  → 各阶段修复前分别 3 failed / 2 failed;最终 10 passed (10)

npx vitest run src/pages
  → Test Files 182 passed (182),Tests 1358 passed (1358)(连续 3 次全绿)

npx tsc --noEmit                                   → 通过
npx eslint <5 个改动文件>                           → 无输出
npx prettier --check <5 个改动文件>                 → All matched files use Prettier code style!

pnpm build                                         → Rspack compiled with 4 warnings(均为既有的
                                                      monaco-editor critical dependency 警告,与本改动无关)
pnpm exec playwright test e2e/options.spec.ts      → 7 passed
pnpm exec playwright test                          → 64 passed (2.8m,全量,因改了共享 fixture)

e2e 侧:把原来断言「点击展开菜单」的用例改为 hover 版,新增「点击应直接进入编辑器」,并新增一条触摸设备用例。Playwright 的 .click() 会先把鼠标移到元素上(触发 hover 展开)再点击,因此那条用例正好在真实 Chromium 中覆盖 #1699 的原始路径。

CI 上的 e2e 失败已定位并修复,过程留档:先用 --blink-settings=...HoverTypes=1...PointerTypes=1(强制「无指针」)在本地复现,两条桌面用例以与 CI 完全相同的报错失败、触摸用例通过,确认是环境的指针能力而非功能问题;再用探针验证该 flag 双向可控(默认 hover:true → 强制 none 得 false → 强制 hover 得 true),据此在共享 fixture 中固定为「有鼠标的桌面」。因改动了共享 fixture,本地跑了全量 e2e:64 passed。

触摸用例需要真实的无 hover 环境:CDP Emulation.setEmulatedMedia 的 hover/pointer 特性对 chrome-extension:// 页面不生效(实测 (hover: hover) 仍为 true),因此该用例自行以 hasTouch: true + isMobile: true + viewport 1200×800 启动持久化上下文(参照 gm-api.spec.ts 自建上下文的做法),并在断言前先探测确认 (hover: hover) === false 且 innerWidth ≥ 768,再 tap() 断言菜单展开且 URL 未跳转。

一处需要说明的观测:期间有两次 src/pages 全量运行出现 1–3 条无关文件(SubscribeListMobile / GeneralSection / SettingsPane / StoragePane)的失败,每次失败集合不同,单独重跑均通过;随后在本分支与干净 main 上各连续跑 3 次全量,均 100% 通过(本分支 1358/1358,main 1355/1355)。判断为 vitest.config.ts 中 ui project 已知的超时预算在机器满载时的偶发抖动(该文件注释已记录此问题),与本改动无关。

Screenshots / 截图

无视觉变化——按钮外观、布局、菜单内容均未改动,本次仅改变点击/键盘的行为语义,详见上文行为对照表。

@CodFrm
CodFrm merged commit 8cbe983 into main Aug 30, 2026
10 checks passed
@CodFrm
CodFrm deleted the fix/1699-create-script-click branch August 30, 2026 07:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] (UI UX)不能直接點擊"Create Script"

1 participant