feat(ui): add resizable session composer#1
Open
jollyxenon wants to merge 12 commits into
Open
Conversation
Allow the CodeNomad session composer to be resized by dragging its top edge while keeping the minimum height at the default collapsed size and clamping the maximum height to the chat area's visible bounds. The prompt controls now keep their intended three-column layout during resize, the expand/collapse icon reflects the current height, and sending a message resets the composer back to its default size so follow-up prompts start from a consistent state. This commit also removes prompt-resize remnants that no longer participate in the new height-based behavior, keeping the implementation aligned with the shipped interaction model.
There was a problem hiding this comment.
Pull request overview
This PR replaces the session composer’s previous two-state expand behavior with a height-driven resizing model, adding a top-edge drag handle, clamping growth to the visible chat area, and ensuring the composer resets back to its default height after sending.
Changes:
- Implement continuous composer resizing via a top-edge drag handle + height signal, and reset height on send.
- Update the expand/shrink button to reflect the actual current height rather than a removed expand-state enum.
- Adjust prompt-input layout/CSS to keep controls in a stable three-column grid and add i18n strings for the resize handle.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/ui/src/components/prompt-input.tsx | Introduces height-driven resizing logic, drag handle, height reset on send, and updates control layout wiring. |
| packages/ui/src/components/expand-button.tsx | Switches expand/shrink icon logic to be based on current height vs default height. |
| packages/ui/src/styles/messaging/prompt-input.css | Adds resize-handle styling and revises grid layout to keep controls aligned. |
| packages/ui/src/components/instance/instance-shell2.tsx | Adds a stable toolbar selector (data-session-toolbar) for clamping calculations; removes compactLayout prop usage. |
| packages/ui/src/components/session/session-view.tsx | Removes the dropped compactLayout prop when rendering PromptInput. |
| packages/ui/src/components/prompt-input/types.ts | Removes ExpandState and compactLayout from public prompt-input types. |
| packages/ui/src/lib/i18n/messages/en/messaging.ts | Adds localized strings for resize-handle label/title. |
| packages/ui/src/lib/i18n/messages/es/messaging.ts | Adds localized strings for resize-handle label/title. |
| packages/ui/src/lib/i18n/messages/fr/messaging.ts | Adds localized strings for resize-handle label/title. |
| packages/ui/src/lib/i18n/messages/he/messaging.ts | Adds localized strings for resize-handle label/title. |
| packages/ui/src/lib/i18n/messages/ja/messaging.ts | Adds localized strings for resize-handle label/title. |
| packages/ui/src/lib/i18n/messages/ru/messaging.ts | Adds localized strings for resize-handle label/title. |
| packages/ui/src/lib/i18n/messages/zh-Hans/messaging.ts | Adds localized strings for resize-handle label/title. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+372
to
+375
| // Fallback: use viewport-based calculation | ||
| const viewportHeight = window.innerHeight; | ||
| const maxFromViewport = viewportHeight - 100; | ||
| return Math.max(DEFAULT_EXPANDED_HEIGHT, maxFromViewport); |
Comment on lines
+808
to
+809
| aria-label={t("promptInput.resizeHandle.ariaLabel")} | ||
| title={t("promptInput.resizeHandle.title")} |
Comment on lines
+433
to
+436
| document.addEventListener("pointermove", handlePointerMove); | ||
| document.addEventListener("pointerup", handlePointerUp); | ||
| document.addEventListener("pointercancel", handlePointerUp); | ||
| } |
Comment on lines
+1
to
+20
| import { | ||
| Suspense, | ||
| createEffect, | ||
| createSignal, | ||
| lazy, | ||
| on, | ||
| onCleanup, | ||
| Show, | ||
| } from "solid-js"; | ||
| import { | ||
| ArrowBigUp, | ||
| ArrowBigDown, | ||
| Loader2, | ||
| Mic, | ||
| Paperclip, | ||
| Volume2, | ||
| X, | ||
| } from "lucide-solid"; | ||
| import ExpandButton from "./expand-button"; | ||
| import { clearAttachments, removeAttachment } from "../stores/attachments"; |
Refine the resizable session composer in response to PR review feedback. Keep the resize cleanup and viewport-based max-height fallback fixes, while removing the newly introduced keyboard resizing behavior so the feature stays aligned with the existing interaction model. This update prevents document-level pointer listeners from leaking when the composer unmounts mid-drag and avoids over-expanding the composer on small viewports or layouts without the toolbar anchor. It intentionally leaves unrelated local edits in package-lock, Electron dev-server files, and workspace metadata out of the commit. Validation: npm run typecheck --workspace @codenomad/ui; npm run build --workspace @codenomad/ui
…e/session-input-resize
Restore the maintainer-owned prompt model for default height, expand state, and compact narrow-pane behavior while keeping top-edge drag resizing as an additive capability. This keeps the feature aligned with the existing composer interaction model instead of replacing it with a separate height-only workflow. The commit limits itself to prompt logic and supporting component APIs so the baseline UX remains recognizable. Validation was completed with npm run typecheck --workspace @codenomad/ui and npm run build --workspace @codenomad/ui.
Add the top-edge resize affordance while preserving the maintainer's narrow-pane grid, inline controls, and compact-height rules. The CSS remains responsible for the original responsive layout, and the drag handle only overlays new pointer behavior on top of it. Validation was completed with npm run typecheck --workspace @codenomad/ui and npm run build --workspace @codenomad/ui.
Add the new resize-handle tooltip text for the locales touched by this branch so the drag affordance remains localized alongside the prompt composer updates. This keeps the new interaction discoverable without changing the maintainer's existing layout semantics. Validation was completed with npm run typecheck --workspace @codenomad/ui and npm run build --workspace @codenomad/ui.
Limit manual prompt resizing to sixty percent of the local session center so the composer cannot consume the full message area. The resize handle now lives inside the prompt field container, keeping the affordance visually centered over the text editor instead of spanning the full composer chrome. Removing the toolbar lookup also drops the temporary data attribute from the session toolbar and avoids cross-pane DOM coupling. Validation: npm run typecheck --workspace @codenomad/ui; npm run build --workspace @codenomad/ui.
Use pointer capture on the resize handle instead of document-level pointer listeners so resize state stays local to the prompt control and no manual listener teardown is needed. Keep explicit resized-height styling through the prompt field stack because the existing expanded-state CSS otherwise prevents the textarea from filling the resized container. Also remove the whitespace-only prompt input type diff. Validation: npm run typecheck --workspace @codenomad/ui.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What Changed
packages/ui/src/components/prompt-input.tsxpackages/ui/src/components/expand-button.tsxso the control reflects the actual composer height instead of a removed expand state enumpackages/ui/src/styles/messaging/prompt-input.cssto support top-edge dragging, maintain the input / utility controls / primary actions three-column layout, and preserve narrow-window behavior without pushing controls under the textareapackages/ui/src/components/instance/instance-shell2.tsxso the composer can clamp against the correct upper boundaryExpandState, unusedcompactLayoutplumbing, duplicate history draft clearing, unused focus-only signal) that would otherwise leave the feature code internally inconsistentWhy
The previous composer behavior only supported a coarse collapsed/expanded switch and regressed when the new resize affordance was introduced. This change makes height adjustment continuous, keeps the controls anchored where users expect them, and ensures each new send starts from a predictable default composer height.
Validation
npm run typecheck --workspace @codenomad/uinpm run build --workspace @codenomad/uivirtuaJSX warning from../../node_modules/virtua/lib/solid/index.jsxNotes
.opencode/package-lock.json,packages/electron-app/electron.vite.config.ts,packages/electron-app/electron/main/process-manager.ts, and.sisyphus/