feat: Add shift-click to append suggestions to text area (#2081)

* feat: Add shift-click to append suggestions to text area

When a user shift-clicks a suggestion, the text is now appended to the current text area content instead of being sent immediately. This allows users to:
- Build complex prompts by combining multiple suggestions
- Edit suggestions before sending them
- Reuse parts of previous suggestions

The implementation passes the mouse event through the component chain and checks for the shift key before deciding whether to append or send the message.

* Tweak icon and internationalize

---------

Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
This commit is contained in:
Sam Hoang Van 2025-03-31 10:35:02 +07:00 committed by GitHub
parent af6753608f
commit 48148e38d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 80 additions and 9 deletions

View file

@ -4,4 +4,5 @@ export const Check = () => React.createElement("div")
export const ChevronsUpDown = () => React.createElement("div")
export const Loader = () => React.createElement("div")
export const X = () => React.createElement("div")
export const Edit = () => React.createElement("div")
export const Database = (props: any) => React.createElement("span", { "data-testid": "database-icon", ...props })

View file

@ -33,7 +33,7 @@ interface ChatRowProps {
isStreaming: boolean
onToggleExpand: () => void
onHeightChange: (isTaller: boolean) => void
onSuggestionClick?: (answer: string) => void
onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void
}
interface ChatRowContentProps extends Omit<ChatRowProps, "onHeightChange"> {}

View file

@ -1055,8 +1055,15 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
isLast={index === groupedMessages.length - 1}
onHeightChange={handleRowHeightChange}
isStreaming={isStreaming}
onSuggestionClick={(answer: string) => {
handleSendMessage(answer, [])
onSuggestionClick={(answer: string, event?: React.MouseEvent) => {
if (event?.shiftKey) {
// Always append to existing text, don't overwrite
setInputValue((currentValue) => {
return currentValue !== "" ? `${currentValue} \n${answer}` : answer
})
} else {
handleSendMessage(answer, [])
}
}}
/>
)

View file

@ -1,17 +1,20 @@
import { useCallback } from "react"
import { cn } from "../../lib/utils"
import { Button } from "../ui/button"
import { Edit } from "lucide-react"
import { useAppTranslation } from "../../i18n/TranslationContext"
interface FollowUpSuggestProps {
suggestions?: string[]
onSuggestionClick?: (answer: string) => void
onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void
ts: number
}
const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: FollowUpSuggestProps) => {
const { t } = useAppTranslation()
const handleSuggestionClick = useCallback(
(suggestion: string) => {
onSuggestionClick?.(suggestion)
(suggestion: string, event: React.MouseEvent) => {
onSuggestionClick?.(suggestion, event)
},
[onSuggestionClick],
)
@ -26,14 +29,29 @@ const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: Follow
<div className="h-full scrollbar-thin scrollbar-thumb-vscode-scrollbarSlider-background scrollbar-track-transparent">
<div className={cn("flex gap-2.5 pb-2 flex-col h-full")}>
{suggestions.map((suggestion) => (
<div key={`${suggestion}-${ts}`} className="w-full">
<div key={`${suggestion}-${ts}`} className="w-full relative group">
<Button
variant="secondary"
className="w-full text-left whitespace-normal break-words h-auto min-h-[28px] py-2 justify-start"
onClick={() => handleSuggestionClick(suggestion)}
className="w-full text-left whitespace-normal break-words h-auto min-h-[28px] py-2 justify-start pr-8"
onClick={(event) => handleSuggestionClick(suggestion, event)}
aria-label={suggestion}>
<span className="text-left">{suggestion}</span>
</Button>
<div
className="absolute top-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity"
onClick={(e) => {
e.stopPropagation()
// Simulate shift-click by directly calling the handler with shiftKey=true
onSuggestionClick?.(suggestion, { ...e, shiftKey: true })
}}
title={t("chat:followUpSuggest.copyToInput")}>
<Button
variant="ghost"
size="icon"
className="h-6 w-6 p-1 hover:bg-vscode-button-hoverBackground">
<Edit className="h-4 w-4" />
</Button>
</div>
</div>
))}
</div>

View file

@ -207,6 +207,9 @@
"thinking": "Pensant",
"seconds": "{{count}}s"
},
"followUpSuggest": {
"copyToInput": "Copiar a l'entrada (o Shift + clic)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 publicat",
"description": "Roo Code 3.10 aporta potents millores de productivitat!",

View file

@ -207,6 +207,9 @@
"thinking": "Denke nach",
"seconds": "{{count}}s"
},
"followUpSuggest": {
"copyToInput": "In Eingabefeld kopieren (oder Shift + Klick)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 veröffentlicht",
"description": "Roo Code 3.10 bringt leistungsstarke Produktivitätsverbesserungen!",

View file

@ -219,6 +219,9 @@
"thinking": "Thinking",
"seconds": "{{count}}s"
},
"followUpSuggest": {
"copyToInput": "Copy to input (same as shift + click)"
},
"browser": {
"rooWantsToUse": "Roo wants to use the browser:",
"consoleLogs": "Console Logs",

View file

@ -207,6 +207,9 @@
"thinking": "Pensando",
"seconds": "{{count}}s"
},
"followUpSuggest": {
"copyToInput": "Copiar a la entrada (o Shift + clic)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 publicado",
"description": "¡Roo Code 3.10 trae potentes mejoras de productividad!",

View file

@ -207,6 +207,9 @@
"thinking": "Réflexion",
"seconds": "{{count}}s"
},
"followUpSuggest": {
"copyToInput": "Copier vers l'entrée (ou Shift + clic)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 est sortie",
"description": "Roo Code 3.10 apporte de puissantes améliorations de productivité !",

View file

@ -207,6 +207,9 @@
"thinking": "विचार कर रहा है",
"seconds": "{{count}} सेकंड"
},
"followUpSuggest": {
"copyToInput": "इनपुट में कॉपी करें (या Shift + क्लिक)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 रिलीज़ हुआ",
"description": "Roo Code 3.10 शक्तिशाली उत्पादकता सुधार लाता है!",

View file

@ -207,6 +207,9 @@
"thinking": "Sto pensando",
"seconds": "{{count}}s"
},
"followUpSuggest": {
"copyToInput": "Copia nell'input (o Shift + clic)"
},
"announcement": {
"title": "🎉 Rilasciato Roo Code 3.10",
"description": "Roo Code 3.10 porta potenti miglioramenti di produttività!",

View file

@ -207,6 +207,9 @@
"thinking": "考え中",
"seconds": "{{count}}秒"
},
"followUpSuggest": {
"copyToInput": "入力欄にコピーまたはShift + クリック)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 リリース",
"description": "Roo Code 3.10は強力な生産性向上機能をもたらします!",

View file

@ -207,6 +207,9 @@
"thinking": "생각 중",
"seconds": "{{count}}초"
},
"followUpSuggest": {
"copyToInput": "입력창에 복사 (또는 Shift + 클릭)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 출시",
"description": "Roo Code 3.10이 강력한 생산성 향상 기능을 제공합니다!",

View file

@ -207,6 +207,9 @@
"thinking": "Myślenie",
"seconds": "{{count}} s"
},
"followUpSuggest": {
"copyToInput": "Kopiuj do pola wprowadzania (lub Shift + kliknięcie)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 wydany",
"description": "Roo Code 3.10 przynosi potężne usprawnienia produktywności!",

View file

@ -207,6 +207,9 @@
"thinking": "Pensando",
"seconds": "{{count}}s"
},
"followUpSuggest": {
"copyToInput": "Copiar para entrada (ou Shift + clique)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 Lançado",
"description": "Roo Code 3.10 traz poderosas melhorias de produtividade!",

View file

@ -207,6 +207,9 @@
"thinking": "Düşünüyor",
"seconds": "{{count}}sn"
},
"followUpSuggest": {
"copyToInput": "Giriş alanına kopyala (veya Shift + tıklama)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 Yayınlandı",
"description": "Roo Code 3.10 güçlü üretkenlik iyileştirmeleri getiriyor!",

View file

@ -207,6 +207,9 @@
"thinking": "Đang suy nghĩ",
"seconds": "{{count}} giây"
},
"followUpSuggest": {
"copyToInput": "Sao chép vào ô nhập liệu (hoặc Shift + nhấp chuột)"
},
"announcement": {
"title": "🎉 Roo Code 3.10 Đã phát hành",
"description": "Roo Code 3.10 mang đến những cải tiến năng suất mạnh mẽ!",

View file

@ -207,6 +207,9 @@
"thinking": "思考中",
"seconds": "{{count}}秒"
},
"followUpSuggest": {
"copyToInput": "复制到输入框或按住Shift点击"
},
"announcement": {
"title": "🎉 Roo Code 3.10 已发布",
"description": "Roo Code 3.10带来强大的生产力提升!",

View file

@ -207,6 +207,9 @@
"thinking": "思考中",
"seconds": "{{count}}秒"
},
"followUpSuggest": {
"copyToInput": "複製到輸入框或按住Shift點擊"
},
"announcement": {
"title": "🎉 Roo Code 3.10 已發布",
"description": "Roo Code 3.10帶來強大的生產力提升!",