'use client'; import * as React from 'react'; import { cn } from '@/lib/utils'; import { useImperativeHandle } from 'react'; interface UseAutosizeTextAreaProps { textAreaRef: React.MutableRefObject; minHeight?: number; maxHeight?: number; triggerAutoSize: string; } export const useAutosizeTextArea = ({ textAreaRef, triggerAutoSize, maxHeight = Number.MAX_SAFE_INTEGER, minHeight = 0, }: UseAutosizeTextAreaProps) => { const [init, setInit] = React.useState(true); React.useEffect(() => { // We need to reset the height momentarily to get the correct scrollHeight for the textarea const offsetBorder = 6; const textAreaElement = textAreaRef.current; if (textAreaElement) { if (init) { textAreaElement.style.minHeight = `${minHeight + offsetBorder}px`; if (maxHeight > minHeight) { textAreaElement.style.maxHeight = `${maxHeight}px`; } setInit(false); } textAreaElement.style.height = `${minHeight + offsetBorder}px`; const scrollHeight = textAreaElement.scrollHeight; // We then set the height directly, outside of the render loop // Trying to set this with state or a ref will product an incorrect value. if (scrollHeight > maxHeight) { textAreaElement.style.height = `${maxHeight}px`; } else { textAreaElement.style.height = `${scrollHeight + offsetBorder}px`; } } }, [textAreaRef.current, triggerAutoSize]); }; export type AutosizeTextAreaRef = { textArea: HTMLTextAreaElement; maxHeight: number; minHeight: number; }; type AutosizeTextAreaProps = { maxHeight?: number; minHeight?: number; } & React.TextareaHTMLAttributes; export const AutosizeTextarea = React.forwardRef( ( { maxHeight = Number.MAX_SAFE_INTEGER, minHeight = 52, className, onChange, value, ...props }: AutosizeTextAreaProps, ref: React.Ref, ) => { const textAreaRef = React.useRef(null); const [triggerAutoSize, setTriggerAutoSize] = React.useState(''); useAutosizeTextArea({ textAreaRef, triggerAutoSize: triggerAutoSize, maxHeight, minHeight, }); useImperativeHandle(ref, () => ({ textArea: textAreaRef.current as HTMLTextAreaElement, focus: () => textAreaRef?.current?.focus(), maxHeight, minHeight, })); React.useEffect(() => { setTriggerAutoSize(value as string); }, [props?.defaultValue, value]); return (