Uh oh!
There was an error while loading. Please reload this page.
fix(deps): #3184 可合并版 —— focus-scope 栈驱逐竞态补丁,解冲突 + 补丁存废说明 - #3200
Merged
Conversation
产线 console 里,新建/编辑模态中 lookup 快捷下拉的搜索框和 Record Picker
表格弹窗都无法输入:焦点在 focusout 阶段就被外层 Dialog 的 FocusScope
同步拽回触发按钮,列表永不过滤("新建记录时 lookup 无法搜索")。
根因是 @radix-ui/react-focus-scope@1.1.16(上游最新 rc 同样存在)的竞态:
栈管理 effect 的 cleanup 用 setTimeout(0) 延迟执行
focusScopesStack.remove(scope)。当该 effect 因 container ref 抖动在组件
未卸载时重跑,顺序变成"重跑先 add → 旧 cleanup 的延时 remove 后执行",
刚加回去的 scope 被永久踢出栈——dialog 的陷阱监听器还活着,却再也没有
弹层能 pause 它。vite dev 不触发该抖动,所以只有产线 bundle 复现。
pnpm patch:effect 重跑(scope 存活)时取消挂起的延时驱逐;真实卸载路径
(autofocus-on-unmount + 栈移除)不变。回归测试用 asChild 子元素换 key
确定性复现竞态:未打补丁必红。已在 rc.1 后端 + 修复后产线 console 真机
验证下拉与表格弹窗搜索均恢复。
Closes#3183
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>…htl4 # Conflicts: # packages/components/package.json # pnpm-lock.yaml
合并 main 后的补充: - 新增 patches/README.md —— 本仓首次引入 pnpm patchedDependencies,而「为什么打、 什么时候删」此前只写在 PR 描述里,合并后即消失。README 记下上游 issue、删除条件 (上游在 effect 重跑时取消挂起的驱逐)、编辑/删除补丁的操作,以及「版本号一变补丁 失配就直接让 pnpm install 失败」这一刻意为之的响亮失败。 - changeset 与测试文件顶部注释里的中文改为英文 —— AGENTS.md 准则 #-1 要求代码注释与 文档(changeset 会进 CHANGELOG,随 npm 发布)一律英文。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUhj4LiXcXGT93m3683KFK
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-zhuang
marked this pull request as ready for review
August 2, 2026 12:39
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
接续 #3184(
claude/lookup-search-new-record-a5cbae)。原 PR 的诊断与补丁都是对的、CI 也全绿,但它落后 main 15 个提交且 mergeable_state 已变成dirty(packages/components/package.json与pnpm-lock.yaml冲突),合不进去。本 PR 是把同一修复重新落到当前 main 之上的可合并版本,并补了两处仓库规约上的欠账。原始问题与根因分析见 #3183 / #3184,此处不再重复。
本 PR 相对 #3184 的改动
1. 解冲突
packages/components/package.json—— main 已把@objectstack/spec从devDependencies提升到dependencies(^17.0.0-rc.1),而 fix(deps): 模态表单里 lookup 搜索框聚焦即被夺回——补丁修复 focus-scope 栈驱逐竞态 (#3183) #3184 的分支上它还留在devDependencies里。冲突按 main 的形态解:丢掉过时的 devDependencies 条目,只保留新增的@radix-ui/react-focus-scope(测试文件直接 import 它,pnpm 严格模式下必须显式声明)。pnpm-lock.yaml—— 直接取 main 的 lockfile,再跑pnpm install --lockfile-only让补丁重新落上去,而不是手工调和冲突块。副作用是顺带清掉了 fix(deps): 模态表单里 lookup 搜索框聚焦即被夺回——补丁修复 focus-scope 栈驱逐竞态 (#3183) #3184 里那段与本次修复无关的 lockfile 抖动(esbuild@0.27.7↔esbuild@0.28.1在两个 importer 之间来回换、外加一条@vitejs/plugin-reactsnapshot 被删)。锁文件净改动从 31 行降到 18 行,只剩patchedDependencies声明 + 5 处patch_hash标注,补丁 hash 与原 PR 一致(41d44316…)。2.
patches/README.md(新增)这是本仓第一次引入
pnpm patchedDependencies,而「为什么打这个补丁、什么时候可以删」原本只存在于 PR 描述里 —— 合并之后就消失了,下一个升级 radix 的人无从判断。README 记下:上游 issue、删除条件(上游在 effect 重跑时取消挂起的驱逐)、pnpm patch/patch-commit的编辑方式,以及「版本一变、补丁失配就直接让pnpm install硬失败」这一刻意为之的响亮失败 —— 逼人工确认上游是否真修了,而不是把补丁悄悄迁移过去。3. 中文串改英文
AGENTS.md 准则 #-1 要求代码注释与文档一律英文,而 changeset 会进
CHANGELOG.md并随 npm 发布。两处:changeset 正文里的"新建记录时 lookup 无法搜索"、测试文件顶部注释里的"lookup 无法搜索"。语义不变,只换语言。验证
在当前 main 之上的 worktree 里全量跑过:
node_modules里的dist/index.mjs、dist/index.js都带上了__pendingStackRemove。dialog-popover-focus-scope.test.tsx3/3 绿;把node_modules里的补丁patch -R掉换成原版 radix 后,第一个用例必红,失败形态正是线上症状 ——document.activeElement是「选择…」触发按钮而不是搜索框;补丁装回去立刻转绿。pnpm vitest run:814 文件 / 9539 用例通过,0 失败(1 文件、25 用例为既有 skip)。这一条是关键 —— 补丁改的是全仓每一个 Dialog / Popover / DropdownMenu 的焦点栈行为,不只是 lookup 那一处。pnpm type-check:78/78 包通过。关于补丁本身(复核结论)
复核过
focusScope的对象标识:它是React.useRef({...}).current,在同一组件实例的 re-render / effect 重跑之间稳定,且实例之间互不相同 —— 所以把挂起的 timeout 挂在focusScope上,只会取消该实例自己的驱逐。真实卸载路径不受影响:组件没了,没有重跑去clearTimeout,延时回调照常派发focusScope.autoFocusOnUnmount并把 scope 移出栈。另外focusScopesStack.add内部本来就arrayRemove去重,重跑重复add不会在栈里留下重影。备注
@object-ui/components的第三方仍需等上游修复 —— 这点已写进patches/README.md,不再只活在 PR 描述里。radix-ui/primitives至今未修该竞态,补丁需保留至上游修复;升级 radix 时须按 README 的流程确认并迁移。🤖 Generated with Claude Code
https://claude.ai/code/session_01NUhj4LiXcXGT93m3683KFK
Generated by Claude Code