fix(site): add inline decorator spacing to chat input via Lexical theme (#23308)

This commit is contained in:
Danielle Maywood
2026-03-19 18:10:23 +00:00
committed by GitHub
parent 0a0c976a1a
commit 748022f2ba
4 changed files with 72 additions and 5 deletions
@@ -324,6 +324,7 @@ const ChatMessageInput = memo(
namespace: "ChatMessageInput",
theme: {
paragraph: "m-0",
inlineDecorator: "mx-1",
},
onError: (error: Error) => console.error("Lexical error:", error),
nodes: [FileReferenceNode],
@@ -122,8 +122,9 @@ export class FileReferenceNode extends DecoratorNode<ReactNode> {
this.__content = content;
}
createDOM(_config: EditorConfig): HTMLElement {
createDOM(config: EditorConfig): HTMLElement {
const span = document.createElement("span");
span.className = config.theme.inlineDecorator ?? "";
span.style.display = "inline";
span.style.userSelect = "none";
return span;
@@ -1,4 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import type { ChatMessageInputRef } from "components/ChatMessageInput/ChatMessageInput";
import { useEffect, useRef } from "react";
import { expect, fn, userEvent, waitFor, within } from "storybook/test";
import { AgentChatInput, type UploadState } from "./AgentChatInput";
@@ -260,6 +262,72 @@ export const WithAttachmentError: Story = {
})(),
};
/** File reference chip rendered inline with text in the editor. */
export const WithFileReference: Story = {
render: (args) => {
const ref = useRef<ChatMessageInputRef>(null);
useEffect(() => {
const handle = ref.current;
if (!handle) return;
handle.addFileReference({
fileName: "site/src/components/Button.tsx",
startLine: 42,
endLine: 42,
content: "export const Button = ...",
});
}, []);
return <AgentChatInput {...args} inputRef={ref} />;
},
args: {
initialValue: "Can you refactor ",
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await waitFor(() => {
expect(canvas.getByText(/Button\.tsx/)).toBeInTheDocument();
});
},
};
/** Multiple file reference chips rendered inline with text. */
export const WithMultipleFileReferences: Story = {
render: (args) => {
const ref = useRef<ChatMessageInputRef>(null);
useEffect(() => {
const handle = ref.current;
if (!handle) return;
handle.addFileReference({
fileName: "api/handler.go",
startLine: 1,
endLine: 50,
content: "...",
});
handle.insertText(" and ");
handle.addFileReference({
fileName: "api/handler_test.go",
startLine: 10,
endLine: 30,
content: "...",
});
}, []);
return <AgentChatInput {...args} inputRef={ref} />;
},
args: {
initialValue: "Compare ",
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await waitFor(() => {
expect(canvas.getByText(/handler\.go/)).toBeInTheDocument();
expect(canvas.getByText(/handler_test\.go/)).toBeInTheDocument();
});
},
};
export const AttachmentsOnly: Story = {
args: (() => {
const file = createMockFile("photo.png", "image/png");
@@ -366,10 +366,7 @@ const ChatMessageItem = memo<{
fileName={block.file_name}
startLine={block.start_line}
endLine={block.end_line}
className={cn(
i > 0 && "ml-1",
i < userInlineContent.length - 1 && "mr-1",
)}
className="mx-1"
/>
),
)