fix: send button overlaps toolbar border and empty code block glitch

- Move send button into MarkdownComposer children slot so it positions
  relative to the editor content area, not the full container
- Always create a text node when inserting a code block to prevent
  Lexical from rendering a split/empty code block artifact

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-25 19:31:24 +01:00
co-authored by Copilot
parent 77194d1f01
commit d84de12f45
2 changed files with 24 additions and 21 deletions
+18 -17
View File
@@ -1013,7 +1013,7 @@ export function ChatPane({
</div>
)}
<div className="relative rounded-xl border border-zinc-700 bg-zinc-900 transition-colors focus-within:border-indigo-500/50">
<div className="rounded-xl border border-zinc-700 bg-zinc-900 transition-colors focus-within:border-indigo-500/50">
<MarkdownComposer
ref={composerRef}
disabled={isComposerDisabled}
@@ -1028,23 +1028,24 @@ export function ChatPane({
? 'Saving scratchpad settings...'
: 'Message...'
}
/>
<button
className={`absolute bottom-2 right-2 flex size-8 items-center justify-center rounded-lg transition ${
canSubmitInput
? 'bg-indigo-600 text-white hover:bg-indigo-500'
: 'bg-zinc-800 text-zinc-600'
}`}
disabled={!canSubmitInput}
onClick={() => composerRef.current?.submit()}
type="button"
>
{isSessionBusy ? (
<Loader2 className="size-4 animate-spin" />
) : (
<ArrowUp className="size-4" />
)}
</button>
<button
className={`absolute bottom-2 right-2 flex size-8 items-center justify-center rounded-lg transition ${
canSubmitInput
? 'bg-indigo-600 text-white hover:bg-indigo-500'
: 'bg-zinc-800 text-zinc-600'
}`}
disabled={!canSubmitInput}
onClick={() => composerRef.current?.submit()}
type="button"
>
{isSessionBusy ? (
<Loader2 className="size-4 animate-spin" />
) : (
<ArrowUp className="size-4" />
)}
</button>
</MarkdownComposer>
</div>
</div>
</div>
+6 -4
View File
@@ -87,6 +87,7 @@ export interface MarkdownComposerProps {
placeholder: string;
onSubmit: (markdown: string) => void;
onContentChange: (hasContent: boolean) => void;
children?: React.ReactNode;
}
/* ── Internal plugins ─────────────────────────────────── */
@@ -283,10 +284,10 @@ function ToolbarPlugin({ disabled }: { disabled: boolean }) {
p.selectEnd();
} else {
const code = $createCodeNode();
const text = topElement.getTextContent();
if (text) code.append($createTextNode(text));
const textNode = $createTextNode(topElement.getTextContent());
code.append(textNode);
topElement.replace(code);
code.selectEnd();
textNode.select(0, 0);
}
});
}, [editor]);
@@ -341,7 +342,7 @@ function ToolbarButton({
/* ── MarkdownComposer ─────────────────────────────────── */
export const MarkdownComposer = forwardRef<MarkdownComposerHandle, MarkdownComposerProps>(
function MarkdownComposer({ disabled, placeholder, onSubmit, onContentChange }, ref) {
function MarkdownComposer({ disabled, placeholder, onSubmit, onContentChange, children }, ref) {
const editorRef = useRef<LexicalEditor | null>(null);
const submitRef = useRef(() => {});
@@ -390,6 +391,7 @@ export const MarkdownComposer = forwardRef<MarkdownComposerHandle, MarkdownCompo
}
ErrorBoundary={LexicalErrorBoundary}
/>
{children}
</div>
<HistoryPlugin />