From c16942777dba264f644fddb279ea215c543a641f Mon Sep 17 00:00:00 2001 From: agent_coder Date: Thu, 2 Jul 2026 03:09:03 +0300 Subject: [PATCH] test(ai-chat): extract+test navbar-visibility predicate; dock label on useDock (#276 review F1/F2) F1: extract the navbar-visibility crux (width/height 0 or right<=0 -> hidden) from getNavbarRect into a pure isNavbarRectVisible in dock-helpers.ts + 3 tests; getNavbarRect calls it (identical null cases). F2: base the dock/undock button's label/icon/title on the effective useDock state (docked && dockRect present) rather than the raw docked flag, so a docked window that fell back to floating (collapsed sidebar) doesn't show 'Undock'. Toggle action unchanged; no remount. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ai-chat/components/ai-chat-window.tsx | 20 ++++++++---- .../ai-chat/utils/dock-helpers.test.ts | 32 ++++++++++++++++++- .../features/ai-chat/utils/dock-helpers.ts | 16 ++++++++++ 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/apps/client/src/features/ai-chat/components/ai-chat-window.tsx b/apps/client/src/features/ai-chat/components/ai-chat-window.tsx index 94923771..c26bfa2d 100644 --- a/apps/client/src/features/ai-chat/components/ai-chat-window.tsx +++ b/apps/client/src/features/ai-chat/components/ai-chat-window.tsx @@ -56,6 +56,7 @@ import { import { selectContextBadge } from "@/features/ai-chat/utils/context-badge.ts"; import { isPointWithinRect, + isNavbarRectVisible, type NavbarRect, } from "@/features/ai-chat/utils/dock-helpers.ts"; import { useClipboard } from "@/hooks/use-clipboard"; @@ -134,7 +135,8 @@ function getNavbarRect(): NavbarRect | null { const el = document.getElementById(APP_NAVBAR_ID); if (!el) return null; const r = el.getBoundingClientRect(); - if (r.width === 0 || r.height === 0 || r.right <= 0) return null; + // Off-screen/collapsed navbar (visibility predicate extracted + unit-tested). + if (!isNavbarRectVisible(r)) return null; return { left: r.left, top: r.top, width: r.width, height: r.height }; } @@ -751,17 +753,21 @@ export default function AiChatWindow() { )} )} - {/* Dock/undock toggle. Docked -> "Undock" (expand icon) pops the window - back out to floating; floating -> "Dock to sidebar" (collapse icon) - pins it into the navbar. */} + {/* Dock/undock toggle. Effectively docked -> "Undock" (expand icon) pops + the window back out to floating; floating -> "Dock to sidebar" + (collapse icon) pins it into the navbar. The LABEL/icon reflect the + EFFECTIVE state (useDock), consistent with the Minimize gate: when + docked but the navbar is absent/collapsed the window renders floating, + so an "Undock" label there would misdescribe a floating window. The + action still toggles the raw `docked` atom. */}