Repository navigation
fix(app-shell): the narrow-window sidebar rail draws no expanded first frame, folds on one Esc, and keeps the wide-window choice apart - #28141
Conversation
…t frame, folds on one Esc, and keeps the wide-window choice apart - The console layout hands the sidebar provider the rail before it mounts on a window below the fold width, so the first frame is the 48 px rail. - A hidden entry tooltip in the expanded overlay no longer swallows the first Esc: an Esc only a hidden tooltip would take folds the overlay. - The wide-window expanded/collapsed choice is kept under its own key, written only by an open or close on a wide window; "Keep sidebar open" on a narrow window never touches it, across a resize and a reload. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Utp6CZr8r7CoQCcbJ15irL
… sidebar choice between mounts Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Utp6CZr8r7CoQCcbJ15irL
…rework Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Utp6CZr8r7CoQCcbJ15irL
|
domain:ui#4 · os-bill · session_01Utp6CZr8r7CoQCcbJ15irL Preview review (proxy for epic:#26676#1) · b832e42 · PASS Proxy preview review under ruling B (6520722066 on #26676) of this PR's head, after CI turned green on it (55 check runs: 44 success, 11 skipped). Surface: branch head Overall: PASS on every Acceptance checkbox of the three cards. #28077 · every frame from the first one at 1280 px is the 48 px rail · PASS
#28078 · one Esc folds the overlay · PASSEach scenario started from the 1280 px overlay (256 px) with the hidden tooltip the card describes present (
Shots: pointer, before · pointer, after 1 Esc · Tab focus on item, after 1 Esc · Tab focus on Keep open, after 1 Esc #28079 · the wide-window choice survives Keep sidebar open on/off, after a reload too · PASS
Seen, outside the verdict
Generated by Claude Code |
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh 席位核对ACCEPT · head
Generated by Claude Code |
Requested by Bill · project thread
维护者速读
consoleSidebarRail.ts、useResponsiveSidebar.ts、ConsoleLayout.tsx一行)和测试;阈值 1416 不变;components/src/ui/**没碰,无新 i18n 键、无发布包新导出。宽窗选择沿用原来的os:console-sidebar:wide-open键,老数据语义一致。回滚即还原本 PR。ui/packages/app-shell/src/layout/consoleSidebarRail.ts(primeConsoleSidebarOpen首帧、escapeOnlyForHiddenTooltipEsc 判定、宽窗选择的读写);ui/packages/app-shell/src/hooks/useResponsiveSidebar.ts(只有宽窗的开合写宽窗选择)。pnpm --dir ui exec vitest run packages/app-shell/src/layout/__tests__/ConsoleLayout.sidebarFirstFrame-28077.test.tsx packages/app-shell/src/layout/__tests__/UnifiedSidebar.railOverlay-27593.test.tsx,预期全绿;或 1280 px 打开 app-crm 联系人,点轨道空白处浮出,鼠标停在「Accounts」上按一次 Esc,侧栏收回。Fixes #28077
Fixes #28078
Fixes #28079
Clause-②: no
Metadata-protocol: none
What changes
SidebarProvidertakes its first open state from thesidebar_statecookie the last page wrote, so a narrow window drew the expanded sidebar once and the fold then closed it, with the primitive's 200 ms width transition in between.ConsoleLayoutnow callsprimeConsoleSidebarOpen()once (auseStateinitializer) beforeAppShell's provider renders: below the fold width with no "keep open" it sets the cookie tofalse, on a wide window to the reader's wide-window choice; a sidebar kept open and the phone keep what the cookie says. The viewport hook was already synchronous (useIsViewportBelowreadsinnerWidthin its initializer), so the flash came from the provider's cookie, not from the hook.useConsoleSidebarRailalso reads the phone breakpoint synchronously, so a phone-width first render is never taken for a narrow one whileuseIsMobilestill answersfalse.hidden(hover or focus opens it); its dismissable layer takes the next Esc on the document's capture phase and callspreventDefault, so the overlay's "a layer handled it" check skipped the fold. The overlay now also listens on the window's capture phase, ahead of every layer: when an open tooltip is hidden and no dialog, alert dialog, menu or listbox is shown, that Esc folds the overlay even though it arrives marked handled. An entry's open menu still takes the Esc first (pinned). Fixed from the sidebar side;components/src/ui/**untouched.os:console-sidebar:wide-openwas a stash written when the rail took over and cleared when keep-open turned on, so keep-open on and then off re-stashed the narrow overlay's state. It is now the reader's wide-window choice: written on every open and close while the window is at or above the fold width, and only then; handed back when the window turns wide and on a wide load. The fold, the overlay and a sidebar kept open on a narrow window never write it;console.sidebar.keepOpenstays under its own key. When no wide-window choice is kept yet (first visit on a narrow window), the open state the fold first closes seeds it.Tests
layout/__tests__/ConsoleLayout.sidebarFirstFrame-28077.test.tsx(5): the realConsoleLayout/AppShell/SidebarProvider, a probe in the sidebar's place recording the state of every render. At 1280 px a first visit, a load after an expanded wide window, and a reload with the cookie expanded: every render, the first included, iscollapsed. 1440: every renderexpanded. Keep-open at 1280 keeps the cookie's state.layout/__tests__/UnifiedSidebar.railOverlay-27593.test.tsx(+6): one Esc folds with focus on an entry (its hidden tooltip open), with the pointer on an entry, with focus on Keep sidebar open; an entry's open menu still takes the Esc; the Console sidebar: toggling "Keep sidebar open" on a narrow window overwrites the wide-window collapsed/expanded choice #28079 sequence in both directions (collapsed and expanded wide-window choice), widened and then reloaded.hooks/__tests__/useResponsiveSidebar.test.tsx: follows the kept wide-window choice (it is no longer cleared when the window widens).chrome/KeyboardShortcutsDialog.wiredOnly-11674.test.tsx: its probe already cleared the sidebar cookie between mounts; it now also clears the wide-window key, since the ⌘ run's toggle is kept as the wide-window choice the Ctrl run would otherwise start from.scripts/ablation-replace.mjs, landed and restored by blob,git diff HEADempty after each): drop theprimeConsoleSidebarOpencall: the three 1280 first-frame tests red, 1440 and keep-open green. Answerfalsefor the hidden-tooltip check: the three one-Esc tests red. Let the narrow keep-open sidebar write the wide-window choice: the expanded-direction Console sidebar: toggling "Keep sidebar open" on a narrow window overwrites the wide-window collapsed/expanded choice #28079 test red. Let the fold write (not seed) the wide-window choice: both Console sidebar: toggling "Keep sidebar open" on a narrow window overwrites the wide-window collapsed/expanded choice #28079 tests red.Acceptance notes
chrome/KeyboardShortcutsDialog.wiredOnly-11674.test.tsx, a test that mounts the realConsoleLayout; the change is its between-mounts cleanup, one line.role=tooltipinside ahiddenelement; a showndialog/alertdialog/menu/listbox). A layer drawn with none of those roles that marks Esc handled while a hidden tooltip is open would see the overlay fold too; none is drawn in the console shell today.CONSOLE_SIDEBAR_RAIL_BELOW_WIDTH) is unchanged, as ruled.Verification
Head
55d0fb34.pnpm --dir ui exec vitest runof the 103 app-shell test files that referenceConsoleLayout,UnifiedSidebar,useResponsiveSidebar,consoleSidebarRail,SidebarProviderorsidebar_state: Test Files 103 passed, Tests 1009 passed.pnpm --filter @object-ui/app-shell lint: 0 errors.@object-ui/app-shelltest (1967 files; stopped locally after an hour on the shared box) andtype-check(needs every@object-ui/*package built).examples/app-crmwithobjectstack dev --seed-admin --fresh, the console on its Vite dev server, Contacts): at 1280 px every sampled animation frame from the first one is the 48 px rail on a first visit, a load after an expanded 1440 px window, and a reload with the overlay shown; at 1440 px every frame is 256 px. In the overlay one Esc folds it with the pointer on Accounts (its tooltip open and hidden), with focus on the Accounts link, and with focus on Keep sidebar open. Collapse at 1440, 1280, keep open on and off, 1440: collapsed, and after a reload; the expanded direction comes back expanded, and after a reload.