Repository navigation
fix(desktop): own Settings Escape before paint - #3730
Conversation
Install the Settings dismissal listener during the layout phase so the first visible frame already has an Escape owner. Keep the listener stable across streamed shell renders while preserving nested-dialog precedence. Generated-by: Codex
EnglishReviewed at The listener lifetime is right. The ref refresh runs in the layout phase on every render with no dependency array, so a streaming re-render can never leave the handler holding a stale Two things are worth fixing before this merges. 1. The first observable Settings frame still has no Escape owner
That is exactly the failure this change sets out to remove. The PR states that Settings owns Escape from its first observable frame; on a cold first open the first observable frame is the fallback, and a slow chunk load widens that window arbitrarily. The reproduction shape is unchanged from #3728: the Settings transition is visible, one Escape does nothing, and the titlebar identity is still gone. Note this is not a regression — the previous The existing coverage cannot reach it. Suggested direction: hoist the layout-phase owner to the Settings overlay / 2. Modified Escape combinations now close SettingsThe handler matches on These combinations are usually claimed by the OS, so Either restore the old matching with Checked and fine
Approval is still pending terminal-green hosted checks on the exact head. 简体中文审查基于 监听器的生命周期没有问题。ref 刷新在布局阶段、每次渲染后执行且无依赖数组,因此流式重渲染不会让 handler 持有过期的 合并前有两处需要处理。 一、Settings 首个可观察帧仍然没有 Escape 的处理者
这正是本次改动要消除的失败。PR 声明 Settings 从首个可观察帧起就拥有 Escape;但冷启动首次打开时,首个可观察帧就是 fallback,chunk 加载慢会把这个窗口任意放大。复现形态与 #3728 一致:Settings 过渡已可见、按一次 Escape 没有反应、标题栏 identity 仍然缺失。 需要说明这不是回归——原来的 现有验证覆盖不到它。 建议方向:把布局阶段的处理者上提到 Settings overlay / 二、带修饰键的 Escape 现在会关闭 Settings新 handler 仅以 这些组合通常被操作系统占用, 要么在 handler 开头恢复旧的匹配语义 已核对、没有问题的部分裸 Escape 上调用 批准仍以该 exact head 的 hosted checks 全部终态绿为前提。 |
Generated-by: Codex
Generated-by: Codex
|
Update for exact head I rechecked the earlier concerns against this head. The Suspense fallback Escape-owner issue and the modifier-key Escape issue are both closed. The Escape owner is now installed by Two independent rechecks found no new P0–P3 issue. The PR remains unapproved only because the required exact-head CI run 简体中文针对 exact head 我已在当前 head 上重新核对之前的疑点。Suspense fallback 阶段没有 Escape owner 的问题,以及修饰键 Escape 的问题,均已闭合。现在由 两条独立复核线均未发现新的 P0–P3 问题。当前仍未批准的唯一原因是 required exact-head CI run |
English
Summary
The Settings overlay now installs its Escape owner during the layout phase, above the lazy-loaded Settings component. The same owner therefore covers both the visible Suspense loading surface and the resolved Settings surface from their first observable frame.
The listener remains stable across shell re-renders and reads the current close callback from a ref. It preserves the existing keyboard contract: nested layers that already prevented Escape keep priority, Ctrl/Cmd/Alt+Escape remain untouched, and unmodified or Shift+Escape close Settings even from an input.
Fixes #3728
Root cause
The previous
useHotkeyssubscription lived inside the lazy Settings component and attached its global listener from a passive effect. This left two intervals with no Escape owner:The existing titlebar-rename E2E waited for the resolved Settings main region before pressing Escape, so it could expose the second race intermittently but could not exercise the loading fallback at all.
Verification
npm --workspace @maka/desktop run build:with-depsnpm --workspace @maka/desktop run typechecknpm --workspace @maka/desktop test— 1,436 passednpx biome checkon all changed source and E2E filesgit diff --checkAI use
Select exactly one:
Tool(s) and scope: Codex implemented and verified the event-lifecycle fix. The affected commits include a
Generated-by: Codextrailer.Checklist
Does this PR entail a change in behavior?
简体中文
摘要
Settings overlay 现在会在布局阶段、lazy Settings 组件之外安装 Escape 的唯一处理者。因此从可见的 Suspense 加载界面到解析完成的 Settings 界面,两段都从各自首次可观察的帧开始拥有同一个处理者。
监听器在 shell 重渲染期间保持稳定,并通过 ref 读取当前的关闭回调。现有键盘契约保持不变:已经阻止 Escape 的内层界面优先处理;Ctrl/Cmd/Alt+Escape 不受影响;裸 Escape 或 Shift+Escape 即使在输入框中也会关闭 Settings。
修复 #3728
根因
原来的
useHotkeys订阅位于 lazy Settings 组件内部,并在被动 effect 中安装全局监听器。这会留下两个没有 Escape 处理者的时间窗:原有标题栏重命名 E2E 会先等待解析完成的 Settings main 区域再按 Escape,因此它可能间歇性暴露第二个竞态,但完全无法覆盖 loading fallback。
验证
npm --workspace @maka/desktop run build:with-depsnpm --workspace @maka/desktop run typechecknpm --workspace @maka/desktop test— 1,436 条通过npx biome checkgit diff --checkAI 使用
工具与范围:Codex 实现并验证了事件生命周期修复。相关提交包含
Generated-by: Codextrailer。检查清单
此 PR 是否改变行为?