From 854aa30a9e126f1a2e05fde1f6a468c2a8878a6f Mon Sep 17 00:00:00 2001 From: Gagancreates Date: Mon, 8 Jun 2026 01:27:42 +0530 Subject: [PATCH] refactor: replace JS overflow logic with CSS container queries Drop the ResizeObserver/useLayoutEffect collapse machinery and the estimated pixel thresholds in favor of declarative @container variants. Each toolbar item swaps to icon-only at a fixed container-width breakpoint (code 560, perm 460, search 410, workDir 370px), collapsing right-to-left. Atomic swaps mean no half-clipped text and no disappearing buttons. --- .../components/chat-input-with-mentions.tsx | 136 ++++++------------ 1 file changed, 46 insertions(+), 90 deletions(-) diff --git a/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx b/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx index 015d8253..46171662 100644 --- a/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx +++ b/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useRef, useState } from 'react' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' import { ArrowUp, @@ -282,41 +282,6 @@ function ChatInputInner({ const [codeModeFeatureEnabled, setCodeModeFeatureEnabled] = useState(false) const [permissionMode, setPermissionMode] = useState('auto') const [recentWorkDirs, setRecentWorkDirs] = useState([]) - const toolbarRef = useRef(null) - const leftGroupRef = useRef(null) - // 0 = all full; collapse order (right→left): 1=code, 2=perm, 3=search, 4=workDir - const [collapseLevel, setCollapseLevel] = useState(0) - - // After every render, synchronously check if the left group overflows and step up - // one collapse level if so. Cascades (each level change triggers another check) - // until items fit — all resolved before the browser paints, so no half-visible text. - useLayoutEffect(() => { - const left = leftGroupRef.current - if (!left) return - if (left.scrollWidth > left.clientWidth + 1) { - setCollapseLevel(prev => Math.min(4, prev + 1)) - } - }, [collapseLevel, workDir, codeModeEnabled, codeModeFeatureEnabled, searchEnabled, searchAvailable]) - - // When the outer toolbar grows, try stepping back down one level at a time. - // Require slack > item's expansion delta + buffer to avoid oscillation at boundaries. - useEffect(() => { - const outer = toolbarRef.current - const left = leftGroupRef.current - if (!outer || !left) return - // Width gained when un-collapsing each level (full-width minus icon-width, px) - const expandDelta = [107, 62, 52, 132] // levels 1→0, 2→1, 3→2, 4→3 - const ro = new ResizeObserver(() => { - const slack = left.clientWidth - left.scrollWidth - setCollapseLevel(prev => { - if (prev === 0) return 0 - return slack > (expandDelta[prev - 1] ?? 0) + 20 ? prev - 1 : prev - }) - }) - ro.observe(outer) - return () => ro.disconnect() - }, []) - // When a run exists, freeze the dropdown to the run's resolved model+provider. useEffect(() => { if (!runId) { @@ -791,8 +756,8 @@ function ChatInputInner({ className="min-h-6 rounded-none border-0 py-0 shadow-none focus-visible:ring-0" /> -
-
+
+
@@ -900,34 +865,25 @@ function ChatInputInner({ {workDir && ( - {collapseLevel >= 4 ? ( - - ) : ( -
+ {/* Collapses to a square icon below ~370px container width */} +
- )} Work directory: {workDir} @@ -948,8 +904,8 @@ function ChatInputInner({ )} > - {searchEnabled && collapseLevel < 3 && ( - + {searchEnabled && ( + Search )} @@ -965,8 +921,7 @@ function ChatInputInner({ }} disabled={Boolean(runId)} className={cn( - "flex h-7 shrink-0 items-center gap-1.5 rounded-full text-xs font-medium transition-colors", - collapseLevel >= 2 ? "w-7 justify-center" : "px-2.5", + "flex h-7 shrink-0 items-center gap-1.5 rounded-full px-2.5 text-xs font-medium transition-colors @max-[460px]:w-7 @max-[460px]:justify-center @max-[460px]:px-0", permissionMode === 'auto' ? "bg-secondary text-foreground hover:bg-secondary/70" : "text-muted-foreground hover:bg-muted hover:text-foreground", @@ -975,7 +930,7 @@ function ChatInputInner({ aria-label="Permission mode" > - {collapseLevel < 2 && {permissionMode === 'auto' ? 'Auto' : 'Manual'}} + {permissionMode === 'auto' ? 'Auto' : 'Manual'} @@ -987,51 +942,52 @@ function ChatInputInner({ {codeModeFeatureEnabled && (codeModeEnabled ? ( - collapseLevel >= 1 ? ( + <> + {/* Compact icon — shown below ~560px when there's no room for the full pill */} Code mode on ({codingAgent === 'claude' ? 'Claude Code' : 'Codex'}) — click to disable - ) : ( -
- - - - - Code mode on — click to disable - - · - - - - - - Coding agent: {codingAgent === 'claude' ? 'Claude Code' : 'Codex'} — click to swap - - -
- ) + {/* Full pill — hidden below ~560px */} +
+ + + + + Code mode on — click to disable + + · + + + + + + Coding agent: {codingAgent === 'claude' ? 'Claude Code' : 'Codex'} — click to swap + + +
+ ) : (