From ba761a0d1e75dac9090f58848bf1f0f10d855519 Mon Sep 17 00:00:00 2001
From: "Kai (Tam Nhu) Tran" <61256810+kaitranntt@users.noreply.github.com>
Date: Mon, 11 May 2026 21:58:55 -0400
Subject: [PATCH] fix(ui): wrap codex config highlight editor (#1217)
---
ui/src/components/shared/code-editor.tsx | 28 +++++++++++--------
.../unit/components/ui/code-editor.test.tsx | 14 +++++++---
2 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/ui/src/components/shared/code-editor.tsx b/ui/src/components/shared/code-editor.tsx
index 6454828b..715a62d4 100644
--- a/ui/src/components/shared/code-editor.tsx
+++ b/ui/src/components/shared/code-editor.tsx
@@ -196,8 +196,8 @@ export function CodeEditor({
const layer = highlightLayerRef.current;
if (!layer) return;
- const { scrollLeft, scrollTop } = event.currentTarget;
- layer.style.transform = `translate(${-scrollLeft}px, ${-scrollTop}px)`;
+ const { scrollTop } = event.currentTarget;
+ layer.style.transform = `translateY(${-scrollTop}px)`;
}, []);
return (
@@ -218,12 +218,15 @@ export function CodeEditor({
data-slot="code-editor-surface"
>
{exactText ? (
// Exact mode keeps the native textarea as the editable/copyable source of truth while
- // rendering Prism colors behind it with the same non-wrapping layout contract.
+ // rendering Prism colors behind it with the same soft-wrap layout contract.
@@ -259,14 +262,14 @@ export function CodeEditor({
if (!readonly) onChange(event.target.value);
}}
readOnly={readonly}
- wrap="off"
+ wrap="soft"
spellCheck={false}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
onScroll={syncHighlightScroll}
className={cn(
'absolute inset-0 z-10 block h-full w-full resize-none border-0 bg-transparent p-3 font-mono text-sm leading-relaxed',
- 'whitespace-pre overflow-auto text-transparent caret-foreground selection:bg-primary/25 focus:outline-none',
+ 'whitespace-pre-wrap overflow-y-auto overflow-x-hidden break-words text-transparent caret-foreground selection:bg-transparent focus:outline-none',
readonly && 'cursor-not-allowed'
)}
style={{
@@ -274,8 +277,9 @@ export function CodeEditor({
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
fontSize: '0.875rem',
tabSize: 2,
- overflowWrap: 'normal',
- wordBreak: 'normal',
+ overflowWrap: 'anywhere',
+ wordBreak: 'break-word',
+ WebkitTextFillColor: 'transparent',
}}
data-slot="code-editor-plain-textarea"
/>
diff --git a/ui/tests/unit/components/ui/code-editor.test.tsx b/ui/tests/unit/components/ui/code-editor.test.tsx
index df9d83bc..8aef532c 100644
--- a/ui/tests/unit/components/ui/code-editor.test.tsx
+++ b/ui/tests/unit/components/ui/code-editor.test.tsx
@@ -68,7 +68,7 @@ describe('CodeEditor', () => {
expect(screen.getByText('Valid TOML')).toBeInTheDocument();
});
- it('renders raw TOML with syntax color while visible lines match copied text', () => {
+ it('renders raw TOML with wrapping syntax color while copied text stays raw', () => {
const rawToml =
'model = "gpt-5.4"\n' +
'[mcp_servers.playwright]\n' +
@@ -92,17 +92,23 @@ describe('CodeEditor', () => {
expect(textarea).toBeInstanceOf(HTMLTextAreaElement);
expect(textarea).toHaveValue(rawToml);
- expect(textarea).toHaveAttribute('wrap', 'off');
+ expect(textarea).toHaveAttribute('wrap', 'soft');
expect(textarea).toHaveClass('text-transparent');
+ expect(textarea).toHaveClass('whitespace-pre-wrap');
+ expect(textarea).toHaveClass('overflow-x-hidden');
expect(highlightLayer).toBeInTheDocument();
- expect(highlightLayer).toHaveClass('whitespace-pre');
+ expect(highlightLayer).toHaveClass('whitespace-pre-wrap');
+ expect(highlightLayer).toHaveStyle({
+ overflowWrap: 'anywhere',
+ wordBreak: 'break-word',
+ });
expect(highlightedToken).toBeInTheDocument();
expect(container.querySelector('pre')).not.toBeInTheDocument();
if (textarea instanceof HTMLTextAreaElement && highlightLayer instanceof HTMLElement) {
textarea.scrollLeft = 96;
textarea.scrollTop = 24;
fireEvent.scroll(textarea);
- expect(highlightLayer.style.transform).toBe('translate(-96px, -24px)');
+ expect(highlightLayer.style.transform).toBe('translateY(-24px)');
}
expect(screen.getByText('Valid TOML')).toBeInTheDocument();
});