From a52bca40d516198569c2e98d447fc98164164914 Mon Sep 17 00:00:00 2001 From: Nicolas Varrot Date: Sat, 14 Feb 2026 00:49:53 +0000 Subject: [PATCH] refactor: remove HighlightedTextarea (cursor desync unfixable) --- src/components/ChatInput.tsx | 18 +---- src/components/HighlightedTextarea.tsx | 97 -------------------------- src/index.css | 73 ------------------- 3 files changed, 3 insertions(+), 185 deletions(-) delete mode 100644 src/components/HighlightedTextarea.tsx diff --git a/src/components/ChatInput.tsx b/src/components/ChatInput.tsx index 927e559..9ca8f13 100644 --- a/src/components/ChatInput.tsx +++ b/src/components/ChatInput.tsx @@ -1,7 +1,6 @@ import { useState, useRef, useEffect, useCallback, lazy, Suspense } from 'react'; -import { Send, Square, Paperclip, X, FileText, Eye, EyeOff, Highlighter } from 'lucide-react'; +import { Send, Square, Paperclip, X, FileText, Eye, EyeOff } from 'lucide-react'; import { useT } from '../hooks/useLocale'; -import { HighlightedTextarea } from './HighlightedTextarea'; const ReactMarkdown = lazy(() => import('react-markdown')); const remarkGfm = import('remark-gfm').then(m => m.default); @@ -92,7 +91,6 @@ export function ChatInput({ onSend, onAbort, isGenerating, disabled, sessionKey const [files, setFiles] = useState([]); const [isDragOver, setIsDragOver] = useState(false); const [showPreview, setShowPreview] = useState(() => localStorage.getItem('pinchchat-md-preview') === '1'); - const [highlightEnabled, setHighlightEnabled] = useState(() => localStorage.getItem('pinchchat-syntax-hl') === '1'); const textareaRef = useRef(null); const fileInputRef = useRef(null); @@ -285,15 +283,6 @@ export function ChatInput({ onSend, onAbort, isGenerating, disabled, sessionKey > {showPreview ? : } - {/* Syntax highlight toggle — hidden on mobile */} - - setText((e.target as HTMLTextAreaElement).value)} + onChange={(e) => setText(e.target.value)} onKeyDown={handleKeyDown} onPaste={handlePaste} placeholder={t('chat.inputPlaceholder')} diff --git a/src/components/HighlightedTextarea.tsx b/src/components/HighlightedTextarea.tsx deleted file mode 100644 index 66598d0..0000000 --- a/src/components/HighlightedTextarea.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { forwardRef, useRef, useEffect, useImperativeHandle, useCallback } from 'react'; - -/** - * A textarea with a syntax-highlighted backdrop overlay. - * The textarea text is transparent; a
 behind it renders colored tokens.
- */
-
-interface Props extends Omit, 'style'> {
-  value: string;
-  highlightEnabled?: boolean;
-}
-
-// Simple markdown tokenizer — returns HTML with  wrappers
-function highlightMarkdown(text: string): string {
-  if (!text) return '\n'; // pre needs at least a newline to size correctly
-
-  // Escape HTML first
-  let html = text
-    .replace(/&/g, '&')
-    .replace(//g, '>');
-
-  // Fenced code blocks: ```...```
-  html = html.replace(/(```[\s\S]*?```)/g, '$1');
-
-  // Inline code: `...`  (but not inside code blocks — already wrapped)
-  html = html.replace(/(?[\s\S]*?)(`[^`\n]+?`)/g, '$1');
-
-  // Bold: **...**
-  html = html.replace(/(\*\*[^*]+?\*\*)/g, '$1');
-
-  // Italic: *...* (single, not inside bold)
-  html = html.replace(/(?$1');
-
-  // Headers at line start: # ...
-  html = html.replace(/(^|\n)(#{1,6}\s[^\n]*)/g, '$1$2');
-
-  // Links: [text](url)
-  html = html.replace(/(\[[^\]]*\]\([^)]*\))/g, '$1');
-
-  // Ensure trailing newline for proper sizing
-  if (!html.endsWith('\n')) html += '\n';
-
-  return html;
-}
-
-export const HighlightedTextarea = forwardRef(
-  ({ value, highlightEnabled = true, className = '', ...props }, ref) => {
-    const textareaRef = useRef(null);
-    const backdropRef = useRef(null);
-
-    useImperativeHandle(ref, () => textareaRef.current!);
-
-    // Sync scroll
-    const syncScroll = useCallback(() => {
-      if (textareaRef.current && backdropRef.current) {
-        backdropRef.current.scrollTop = textareaRef.current.scrollTop;
-        backdropRef.current.scrollLeft = textareaRef.current.scrollLeft;
-      }
-    }, []);
-
-    useEffect(() => {
-      syncScroll();
-    }, [value, syncScroll]);
-
-    if (!highlightEnabled) {
-      return (
-