diff --git a/server/src/components/ui/TextArea.tsx b/server/src/components/ui/TextArea.tsx index 8b85c881..fc29f717 100644 --- a/server/src/components/ui/TextArea.tsx +++ b/server/src/components/ui/TextArea.tsx @@ -6,51 +6,60 @@ interface TextAreaProps extends React.TextareaHTMLAttributes( ({ label, onChange, className, value = '', ...props }, ref) => { - // Keep track of whether initial adjustment has been done - const initialAdjustmentDone = useRef(false); + const textareaRef = useRef(null); + const combinedRef = (node: HTMLTextAreaElement) => { + textareaRef.current = node; + if (typeof ref === 'function') { + ref(node); + } else if (ref) { + ref.current = node; + } + }; const adjustHeight = (element: HTMLTextAreaElement) => { - // Force a reflow - void element.offsetHeight; - - // Reset height to get proper scrollHeight + // Temporarily collapse to get the minimum height element.style.height = 'auto'; - // Set new height - const newHeight = element.scrollHeight; + // Get the computed line height to ensure proper minimum height + const computedStyle = window.getComputedStyle(element); + const lineHeight = parseInt(computedStyle.lineHeight); + + // Calculate height based on content + const newHeight = Math.max( + element.scrollHeight, + lineHeight * 1.5 // Minimum height of ~1.5 lines + ); + + // Set the new height element.style.height = `${newHeight}px`; }; - // Immediate mount effect for initial content + // Initial setup and content-based adjustment useEffect(() => { - if (!initialAdjustmentDone.current && ref && 'current' in ref && ref.current) { - const textarea = ref.current; + if (textareaRef.current) { + const element = textareaRef.current; - // Force immediate height adjustment - const adjustInitialHeight = () => { - // Force a reflow first - void textarea.offsetHeight; - textarea.style.height = 'auto'; - const scrollHeight = textarea.scrollHeight; - textarea.style.height = `${scrollHeight}px`; - initialAdjustmentDone.current = true; - }; - - // Run adjustment immediately and after a small delay - adjustInitialHeight(); - setTimeout(adjustInitialHeight, 0); + // Ensure proper initial display + element.style.height = 'auto'; + element.style.overflow = 'hidden'; + + // Force a reflow and adjust height + void element.offsetHeight; + adjustHeight(element); } }, []); - // Handle subsequent value changes + // Handle value changes useLayoutEffect(() => { - if (ref && 'current' in ref && ref.current) { - adjustHeight(ref.current); + if (textareaRef.current) { + adjustHeight(textareaRef.current); } }, [value]); const handleInput = (e: React.ChangeEvent) => { - adjustHeight(e.target); + if (textareaRef.current) { + adjustHeight(textareaRef.current); + } if (onChange) { onChange(e); @@ -65,9 +74,25 @@ export const TextArea = forwardRef( )}