import * as React from 'react'; import { cn } from '@renderer/lib/utils'; interface AutoResizeTextareaProps extends React.ComponentProps<'textarea'> { minRows?: number; maxRows?: number; } const AutoResizeTextarea = React.forwardRef( ({ className, minRows = 2, maxRows = 12, onChange, ...props }, forwardedRef) => { const internalRef = React.useRef(null); const setRefs = React.useCallback( (node: HTMLTextAreaElement | null) => { internalRef.current = node; if (typeof forwardedRef === 'function') { forwardedRef(node); } else if (forwardedRef) { // eslint-disable-next-line no-param-reassign -- ref merging requires mutation forwardedRef.current = node; } }, [forwardedRef] ); const adjustHeight = React.useCallback(() => { const textarea = internalRef.current; if (!textarea) return; const computedStyle = window.getComputedStyle(textarea); const lineHeight = parseFloat(computedStyle.lineHeight) || 20; const paddingTop = parseFloat(computedStyle.paddingTop) || 0; const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0; const borderTop = parseFloat(computedStyle.borderTopWidth) || 0; const borderBottom = parseFloat(computedStyle.borderBottomWidth) || 0; const minHeight = minRows * lineHeight + paddingTop + paddingBottom + borderTop + borderBottom; const maxHeight = maxRows * lineHeight + paddingTop + paddingBottom + borderTop + borderBottom; textarea.style.height = 'auto'; const scrollHeight = textarea.scrollHeight; const clampedHeight = Math.min(Math.max(scrollHeight, minHeight), maxHeight); textarea.style.height = `${clampedHeight}px`; textarea.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden'; }, [minRows, maxRows]); React.useEffect(() => { adjustHeight(); }, [adjustHeight, props.value]); const handleChange = React.useCallback( (e: React.ChangeEvent) => { onChange?.(e); adjustHeight(); }, [onChange, adjustHeight] ); return (