mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 03:13:12 +00:00
fix(ui): wrap codex config highlight editor (#1217)
This commit is contained in:
1 parent
a3e8e2e58c
commit
ba761a0d1e
2 files changed
+26
-16
No files matched your search
@@ -196,8 +196,8 @@ export function CodeEditor({
|
|||||||
const layer = highlightLayerRef.current;
|
const layer = highlightLayerRef.current;
|
||||||
if (!layer) return;
|
if (!layer) return;
|
||||||
|
|
||||||
const { scrollLeft, scrollTop } = event.currentTarget;
|
const { scrollTop } = event.currentTarget;
|
||||||
layer.style.transform = `translate(${-scrollLeft}px, ${-scrollTop}px)`;
|
layer.style.transform = `translateY(${-scrollTop}px)`;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -218,12 +218,15 @@ export function CodeEditor({
|
|||||||
data-slot="code-editor-surface"
|
data-slot="code-editor-surface"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(isFillParent && 'scrollbar-editor min-h-0 flex-1 overflow-auto')}
|
className={cn(
|
||||||
|
isFillParent && 'scrollbar-editor min-h-0 flex-1',
|
||||||
|
isFillParent && (exactText ? 'overflow-hidden' : 'overflow-auto')
|
||||||
|
)}
|
||||||
data-slot={isFillParent ? 'code-editor-viewport' : undefined}
|
data-slot={isFillParent ? 'code-editor-viewport' : undefined}
|
||||||
>
|
>
|
||||||
{exactText ? (
|
{exactText ? (
|
||||||
// Exact mode keeps the native textarea as the editable/copyable source of truth while
|
// 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.
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative w-full overflow-hidden',
|
'relative w-full overflow-hidden',
|
||||||
@@ -238,16 +241,16 @@ export function CodeEditor({
|
|||||||
ref={highlightLayerRef}
|
ref={highlightLayerRef}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className={cn(
|
className={cn(
|
||||||
'pointer-events-none absolute left-0 top-0 min-w-full p-3 font-mono text-sm leading-relaxed',
|
'pointer-events-none absolute inset-x-0 top-0 w-full p-3 font-mono text-sm leading-relaxed',
|
||||||
'whitespace-pre overflow-visible'
|
'whitespace-pre-wrap overflow-visible break-words'
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
||||||
fontSize: '0.875rem',
|
fontSize: '0.875rem',
|
||||||
minHeight,
|
minHeight,
|
||||||
tabSize: 2,
|
tabSize: 2,
|
||||||
overflowWrap: 'normal',
|
overflowWrap: 'anywhere',
|
||||||
wordBreak: 'normal',
|
wordBreak: 'break-word',
|
||||||
}}
|
}}
|
||||||
data-slot="code-editor-highlight-layer"
|
data-slot="code-editor-highlight-layer"
|
||||||
>
|
>
|
||||||
@@ -259,14 +262,14 @@ export function CodeEditor({
|
|||||||
if (!readonly) onChange(event.target.value);
|
if (!readonly) onChange(event.target.value);
|
||||||
}}
|
}}
|
||||||
readOnly={readonly}
|
readOnly={readonly}
|
||||||
wrap="off"
|
wrap="soft"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
onFocus={() => setIsFocused(true)}
|
onFocus={() => setIsFocused(true)}
|
||||||
onBlur={() => setIsFocused(false)}
|
onBlur={() => setIsFocused(false)}
|
||||||
onScroll={syncHighlightScroll}
|
onScroll={syncHighlightScroll}
|
||||||
className={cn(
|
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',
|
'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'
|
readonly && 'cursor-not-allowed'
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
@@ -274,8 +277,9 @@ export function CodeEditor({
|
|||||||
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
||||||
fontSize: '0.875rem',
|
fontSize: '0.875rem',
|
||||||
tabSize: 2,
|
tabSize: 2,
|
||||||
overflowWrap: 'normal',
|
overflowWrap: 'anywhere',
|
||||||
wordBreak: 'normal',
|
wordBreak: 'break-word',
|
||||||
|
WebkitTextFillColor: 'transparent',
|
||||||
}}
|
}}
|
||||||
data-slot="code-editor-plain-textarea"
|
data-slot="code-editor-plain-textarea"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ describe('CodeEditor', () => {
|
|||||||
expect(screen.getByText('Valid TOML')).toBeInTheDocument();
|
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 =
|
const rawToml =
|
||||||
'model = "gpt-5.4"\n' +
|
'model = "gpt-5.4"\n' +
|
||||||
'[mcp_servers.playwright]\n' +
|
'[mcp_servers.playwright]\n' +
|
||||||
@@ -92,17 +92,23 @@ describe('CodeEditor', () => {
|
|||||||
|
|
||||||
expect(textarea).toBeInstanceOf(HTMLTextAreaElement);
|
expect(textarea).toBeInstanceOf(HTMLTextAreaElement);
|
||||||
expect(textarea).toHaveValue(rawToml);
|
expect(textarea).toHaveValue(rawToml);
|
||||||
expect(textarea).toHaveAttribute('wrap', 'off');
|
expect(textarea).toHaveAttribute('wrap', 'soft');
|
||||||
expect(textarea).toHaveClass('text-transparent');
|
expect(textarea).toHaveClass('text-transparent');
|
||||||
|
expect(textarea).toHaveClass('whitespace-pre-wrap');
|
||||||
|
expect(textarea).toHaveClass('overflow-x-hidden');
|
||||||
expect(highlightLayer).toBeInTheDocument();
|
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(highlightedToken).toBeInTheDocument();
|
||||||
expect(container.querySelector('pre')).not.toBeInTheDocument();
|
expect(container.querySelector('pre')).not.toBeInTheDocument();
|
||||||
if (textarea instanceof HTMLTextAreaElement && highlightLayer instanceof HTMLElement) {
|
if (textarea instanceof HTMLTextAreaElement && highlightLayer instanceof HTMLElement) {
|
||||||
textarea.scrollLeft = 96;
|
textarea.scrollLeft = 96;
|
||||||
textarea.scrollTop = 24;
|
textarea.scrollTop = 24;
|
||||||
fireEvent.scroll(textarea);
|
fireEvent.scroll(textarea);
|
||||||
expect(highlightLayer.style.transform).toBe('translate(-96px, -24px)');
|
expect(highlightLayer.style.transform).toBe('translateY(-24px)');
|
||||||
}
|
}
|
||||||
expect(screen.getByText('Valid TOML')).toBeInTheDocument();
|
expect(screen.getByText('Valid TOML')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user