Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions webview-ui/src/components/chat/ChatTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(

const allModes = useMemo(() => getAllModes(customModes), [customModes])

// Memoized check for whether the input has content
// Memoized check for whether the input has content (text or images)
const hasInputContent = useMemo(() => {
return inputValue.trim().length > 0
}, [inputValue])
return inputValue.trim().length > 0 || selectedImages.length > 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Consider decoupling visibility flags. hasInputContent now gates both send and enhance; suggest using hasSendableContent (text || images) for the send button while keeping Enhance gated by text-only to avoid surfacing it on image-only messages.

}, [inputValue, selectedImages])

const queryItems = useMemo(() => {
return [
Expand Down
82 changes: 82 additions & 0 deletions webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1057,4 +1057,86 @@ describe("ChatTextArea", () => {
expect(apiConfigDropdown).toHaveAttribute("disabled")
})
})

describe("send button visibility", () => {
it("should show send button when there are images but no text", () => {
const { container } = render(
<ChatTextArea
{...defaultProps}
inputValue=""
selectedImages={["data:image/png;base64,test1", "data:image/png;base64,test2"]}
/>,
)

// Find the send button by looking for the button with SendHorizontal icon
const buttons = container.querySelectorAll("button")
const sendButton = Array.from(buttons).find(
(button) => button.querySelector(".lucide-send-horizontal") !== null,
)

expect(sendButton).toBeInTheDocument()

// Check that the button is visible (has opacity-100 class when content exists)
expect(sendButton).toHaveClass("opacity-100")
expect(sendButton).toHaveClass("pointer-events-auto")
expect(sendButton).not.toHaveClass("opacity-0")
expect(sendButton).not.toHaveClass("pointer-events-none")
})

it("should hide send button when there is no text and no images", () => {
const { container } = render(<ChatTextArea {...defaultProps} inputValue="" selectedImages={[]} />)

// Find the send button by looking for the button with SendHorizontal icon
const buttons = container.querySelectorAll("button")
const sendButton = Array.from(buttons).find(
(button) => button.querySelector(".lucide-send-horizontal") !== null,
)

expect(sendButton).toBeInTheDocument()

// Check that the button is hidden (has opacity-0 class when no content)
expect(sendButton).toHaveClass("opacity-0")
expect(sendButton).toHaveClass("pointer-events-none")
expect(sendButton).not.toHaveClass("opacity-100")
expect(sendButton).not.toHaveClass("pointer-events-auto")
})

it("should show send button when there is text but no images", () => {
const { container } = render(<ChatTextArea {...defaultProps} inputValue="Some text" selectedImages={[]} />)

// Find the send button by looking for the button with SendHorizontal icon
const buttons = container.querySelectorAll("button")
const sendButton = Array.from(buttons).find(
(button) => button.querySelector(".lucide-send-horizontal") !== null,
)

expect(sendButton).toBeInTheDocument()

// Check that the button is visible
expect(sendButton).toHaveClass("opacity-100")
expect(sendButton).toHaveClass("pointer-events-auto")
})

it("should show send button when there is both text and images", () => {
const { container } = render(
<ChatTextArea
{...defaultProps}
inputValue="Some text"
selectedImages={["data:image/png;base64,test1"]}
/>,
)

// Find the send button by looking for the button with SendHorizontal icon
const buttons = container.querySelectorAll("button")
const sendButton = Array.from(buttons).find(
(button) => button.querySelector(".lucide-send-horizontal") !== null,
)

expect(sendButton).toBeInTheDocument()

// Check that the button is visible
expect(sendButton).toHaveClass("opacity-100")
expect(sendButton).toHaveClass("pointer-events-auto")
})
})
})