fix(app): make composer track clearance deterministic

Layout measurement excluded pill margin on some renderers, collapsing the intended gap above visible tracks. Keep the two-pill rail on one line and derive its complete tail clearance from shared geometry so chat switching and layout callbacks cannot change the result.
This commit is contained in:
Mohamed Boudra
2026-08-17 23:23:51 +02:00
parent a6a533bc6a
commit 1cc6712e51
8 changed files with 62 additions and 69 deletions
+14 -19
View File
@@ -25,7 +25,7 @@ import { FileDropZone } from "@/components/file-drop/file-drop-zone";
import { useRetainedPanelActive } from "@/components/retained-panel";
import { SidebarCallout } from "@/components/sidebar-callout";
import { Composer } from "@/composer";
import { COMPOSER_PILL_MIN_HEIGHT, resolveComposerPillClearance } from "@/composer/pill-styles";
import { resolveComposerTrackTailClearance } from "@/composer/pill-styles";
import { getActiveMessageSubmissions } from "@/composer/submission/model";
import { RewindComposerRestoreProvider } from "@/components/rewind/composer-restore";
import { getProviderIcon } from "@/components/provider-icons";
@@ -1213,7 +1213,7 @@ const ChatAgentReadyContent = memo(function ChatAgentReadyContent({
}) {
const { t } = useTranslation();
const isCompactFormFactor = useIsCompactFormFactor();
const composerPillClearance = resolveComposerPillClearance(isCompactFormFactor);
const composerTrackTailClearance = resolveComposerTrackTailClearance(isCompactFormFactor);
const subagentRows = useSubagentsForParent({ serverId, parentAgentId: agentId });
const tasks = useSessionStore((state): TodoEntry[] | undefined =>
state.sessions[serverId]?.agentTasks.get(agentId),
@@ -1223,14 +1223,14 @@ const ChatAgentReadyContent = memo(function ChatAgentReadyContent({
parentAgentId: agentId,
rows: subagentRows,
});
const showAgentTracks = hasAgentTracks({
subagentRows,
tasks,
archiveFinishedStatus: archiveFinishedSubagents.status,
});
const [agentTracksHeight, setAgentTracksHeight] = useState(
COMPOSER_PILL_MIN_HEIGHT + composerPillClearance,
);
const hasActiveComposer = !agentState.archivedAt && !isArchivingCurrentAgent;
const showAgentTracks =
hasActiveComposer &&
hasAgentTracks({
subagentRows,
tasks,
archiveFinishedStatus: archiveFinishedSubagents.status,
});
const rawAgentInputDraft = useAgentInputDraft({
draftKey: buildDraftStoreKey({
serverId,
@@ -1305,8 +1305,7 @@ const ChatAgentReadyContent = memo(function ChatAgentReadyContent({
agent={effectiveAgent}
routeBottomAnchorRequest={routeBottomAnchorRequest}
hasAppliedAuthoritativeHistory={hasAppliedAuthoritativeHistory}
bottomOverlayHeight={showAgentTracks ? agentTracksHeight : 0}
bottomOverlayClearance={showAgentTracks ? composerPillClearance : 0}
bottomOverlayTailClearance={showAgentTracks ? composerTrackTailClearance : 0}
toast={toastApi}
onOpenWorkspaceFile={onOpenWorkspaceFile}
/>
@@ -1318,7 +1317,6 @@ const ChatAgentReadyContent = memo(function ChatAgentReadyContent({
tasks={tasks}
archiveFinishedStatus={archiveFinishedSubagents.status}
onArchiveFinished={archiveFinishedSubagents.archiveFinished}
onHeightChange={setAgentTracksHeight}
/>
) : null}
</ReanimatedAnimated.View>
@@ -1372,8 +1370,7 @@ const AgentStreamSection = memo(function AgentStreamSection({
agent,
routeBottomAnchorRequest,
hasAppliedAuthoritativeHistory,
bottomOverlayHeight,
bottomOverlayClearance,
bottomOverlayTailClearance,
toast,
onOpenWorkspaceFile,
}: {
@@ -1383,8 +1380,7 @@ const AgentStreamSection = memo(function AgentStreamSection({
agent: AgentScreenAgent;
routeBottomAnchorRequest: RouteBottomAnchorRequest;
hasAppliedAuthoritativeHistory: boolean;
bottomOverlayHeight: number;
bottomOverlayClearance: number;
bottomOverlayTailClearance: number;
toast: ReturnType<typeof useToastHost>["api"];
onOpenWorkspaceFile?: (request: WorkspaceFileOpenRequest) => void;
}) {
@@ -1443,8 +1439,7 @@ const AgentStreamSection = memo(function AgentStreamSection({
pendingPermissions={pendingPermissions}
routeBottomAnchorRequest={routeBottomAnchorRequest}
isAuthoritativeHistoryReady={hasAppliedAuthoritativeHistory}
bottomOverlayHeight={bottomOverlayHeight}
bottomOverlayClearance={bottomOverlayClearance}
bottomOverlayTailClearance={bottomOverlayTailClearance}
toast={toast}
pendingMessageSubmissions={pendingMessageSubmissions}
turnPresentation={turnPresentation}
+1 -3
View File
@@ -26,14 +26,12 @@ export const AgentTracks = memo(function AgentTracks({
tasks,
archiveFinishedStatus,
onArchiveFinished,
onHeightChange,
}: {
serverId: string;
subagentRows: SubagentRow[];
tasks: TodoEntry[] | undefined;
archiveFinishedStatus: ArchiveFinishedStatus;
onArchiveFinished: () => void;
onHeightChange?: (height: number) => void;
}): ReactElement | null {
const { openTab } = usePaneContext();
const canDetachSubagents = useSessionStore(
@@ -59,7 +57,7 @@ export const AgentTracks = memo(function AgentTracks({
}
return (
<ComposerTrackBar onHeightChange={onHeightChange}>
<ComposerTrackBar>
<SubagentsTrack
rows={subagentRows}
onOpenSubagent={handleOpenSubagent}