From 11b444a3ec30bf7eca233991490fe38e506505d8 Mon Sep 17 00:00:00 2001 From: Peter Vachon Date: Thu, 30 Apr 2026 08:18:26 -0400 Subject: [PATCH] feat(apollo-vertex): ai-chat text selection Ask AI [5/5] Adds text-selection-to-AI flow: - AiChatSelectionMenu: floating "Ask AI" pill shown on text selection, scoped to the chat container, with fade+scale entrance animation - AiChatInput: quotedText chip with left-accent border, dismissable with X - AiChat: enableTextSelection prop wires selection menu to quote chip; clicking "Ask AI" pre-fills the input and focuses the textarea - registry.json: ai-chat-selection-menu.tsx registered Co-Authored-By: Claude Sonnet 4.6 --- apps/apollo-vertex/registry.json | 5 + .../ai-chat/components/ai-chat-input.tsx | 26 +++- .../components/ai-chat-selection-menu.tsx | 112 ++++++++++++++++++ .../registry/ai-chat/components/ai-chat.tsx | 32 ++++- .../templates/ai-chat/AiChatAgentHubMode.tsx | 25 +++- 5 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 apps/apollo-vertex/registry/ai-chat/components/ai-chat-selection-menu.tsx diff --git a/apps/apollo-vertex/registry.json b/apps/apollo-vertex/registry.json index b5d85c435..baf2690b8 100644 --- a/apps/apollo-vertex/registry.json +++ b/apps/apollo-vertex/registry.json @@ -443,6 +443,11 @@ "type": "registry:ui", "target": "components/ui/ai-chat/components/ai-chat-message-actions.tsx" }, + { + "path": "registry/ai-chat/components/ai-chat-selection-menu.tsx", + "type": "registry:ui", + "target": "components/ui/ai-chat/components/ai-chat-selection-menu.tsx" + }, { "path": "registry/ai-chat/components/ai-chat-thinking.tsx", "type": "registry:ui", diff --git a/apps/apollo-vertex/registry/ai-chat/components/ai-chat-input.tsx b/apps/apollo-vertex/registry/ai-chat/components/ai-chat-input.tsx index d8df47b38..45c93514a 100644 --- a/apps/apollo-vertex/registry/ai-chat/components/ai-chat-input.tsx +++ b/apps/apollo-vertex/registry/ai-chat/components/ai-chat-input.tsx @@ -8,12 +8,12 @@ import { type FormEvent, type KeyboardEvent, type Ref, - createPortal, useEffect, useImperativeHandle, useRef, useState, } from "react"; +import { createPortal } from "react-dom"; import { useTranslation } from "react-i18next"; import { DropdownMenu, @@ -65,6 +65,10 @@ interface AiChatInputProps { placeholder?: string; hasMessages?: boolean; maxLength?: number; + /** Pre-filled quoted text shown as a chip above the input */ + quotedText?: string; + /** Called when the user dismisses the quoted text chip */ + onClearQuote?: () => void; ref?: Ref; } @@ -82,6 +86,8 @@ export function AiChatInput({ placeholder, hasMessages = false, maxLength, + quotedText, + onClearQuote, ref, }: AiChatInputProps) { const { t } = useTranslation(); @@ -246,6 +252,22 @@ export function AiChatInput({ ) : null; + const quoteChip = quotedText ? ( +
+
+ {quotedText} + +
+
+ ) : null; + const plusMenu = ( @@ -341,6 +363,7 @@ export function AiChatInput({ {hasMessages ? (
+ {quoteChip} {fileChips}
{plusMenu} @@ -362,6 +385,7 @@ export function AiChatInput({ ) : (
+ {quoteChip} {fileChips}