perf: reduce UI render fanout and scroll jitter
- Cut broad render fanout across the app by replacing shared-store whole-object subscriptions with leaf selectors, memoizing hot chrome boundaries, and isolating disabled global providers from live session/message state. This keeps header controls, composer toolbars, side panels, and other non-hot UI surfaces from repainting on every assistant update or keystroke. - Rework sidebar session ordering so recent, project groups, and worktree groups derive from one ordering source while avoiding streaming-time thrash. The sidebar now uses a stabilized session snapshot, preserves structural identity for unchanged rows, reads live row status/details per session, and applies a one-shot sort bump on idle->busy instead of continuously resorting during activity. - Fix chat/input scroll instability by separating viewport-resize handling from message-growth handling, disabling conflicting native scroll anchoring, and stopping textarea autosize from collapsing on every growth keystroke. This removes the multiline typing jiggle during streaming and reduces unnecessary composer rerenders. - Also gate voice context wiring behind voice-mode enablement and codify the learned render/scroll/order anti-patterns in AGENTS.md so future changes avoid the same classes of regressions.
This commit is contained in:
@@ -14,8 +14,8 @@ import type { ToolPopupContent } from './message/types';
|
||||
|
||||
export const FileAttachmentButton = memo(() => {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const { addAttachedFile } = useInputStore();
|
||||
const { isMobile } = useUIStore();
|
||||
const addAttachedFile = useInputStore((state) => state.addAttachedFile);
|
||||
const isMobile = useUIStore((state) => state.isMobile);
|
||||
const isVSCodeRuntime = useIsVSCodeRuntime();
|
||||
const buttonSizeClass = isMobile ? 'h-9 w-9' : 'h-7 w-7';
|
||||
const iconSizeClass = isMobile ? 'h-5 w-5' : 'h-[18px] w-[18px]';
|
||||
@@ -256,7 +256,8 @@ const FileChip = memo(({ file, onRemove }: FileChipProps) => {
|
||||
FileChip.displayName = 'FileChip';
|
||||
|
||||
export const AttachedFilesList = memo(() => {
|
||||
const { attachedFiles, removeAttachedFile } = useInputStore();
|
||||
const attachedFiles = useInputStore((state) => state.attachedFiles);
|
||||
const removeAttachedFile = useInputStore((state) => state.removeAttachedFile);
|
||||
|
||||
const localFiles = attachedFiles.filter((file) => file.source !== 'server');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user