@@ -740,6 +740,7 @@ interface MarkdownEditorProps {
740740 onKeyDown ?: ( e : React . KeyboardEvent ) => void ;
741741 placeholder ?: string ;
742742 minHeight ?: string ;
743+ maxHeight ?: string ;
743744 autoFocus ?: boolean ;
744745 disabled ?: boolean ;
745746}
@@ -769,7 +770,8 @@ export const MarkdownEditor = memo(function MarkdownEditor({
769770 onChange,
770771 onKeyDown,
771772 placeholder = "Leave a comment..." ,
772- minHeight = "100px" ,
773+ minHeight = "160px" , // ~8 lines at default text-sm size
774+ maxHeight = "50vh" ,
773775 autoFocus = false ,
774776 disabled = false ,
775777} : MarkdownEditorProps ) {
@@ -806,13 +808,64 @@ export const MarkdownEditor = memo(function MarkdownEditor({
806808 }
807809 } , [ autoFocus ] ) ;
808810
811+ // Track if user has manually resized the textarea
812+ const userResizedRef = useRef ( false ) ;
813+
814+ // Auto-resize textarea to fit content (fallback for browsers without field-sizing)
815+ useEffect ( ( ) => {
816+ const textarea = textareaRef . current ;
817+ if ( ! textarea ) return ;
818+
819+ // Skip auto-resize if user has manually resized via drag handle
820+ if ( userResizedRef . current ) return ;
821+
822+ // Check if browser supports field-sizing (then CSS handles it)
823+ if ( CSS . supports ( "field-sizing" , "content" ) ) return ;
824+
825+ // Reset height to auto to get the correct scrollHeight
826+ textarea . style . height = "auto" ;
827+ // Set height to scrollHeight to fit content
828+ textarea . style . height = `${ textarea . scrollHeight } px` ;
829+ } , [ value ] ) ;
830+
831+ // Detect manual resize via mouseup on textarea
832+ useEffect ( ( ) => {
833+ const textarea = textareaRef . current ;
834+ if ( ! textarea ) return ;
835+
836+ let startHeight = textarea . offsetHeight ;
837+
838+ const handleMouseDown = ( ) => {
839+ startHeight = textarea . offsetHeight ;
840+ } ;
841+
842+ const handleMouseUp = ( ) => {
843+ // If height changed without value change, user manually resized
844+ if ( textarea . offsetHeight !== startHeight ) {
845+ userResizedRef . current = true ;
846+ }
847+ } ;
848+
849+ textarea . addEventListener ( "mousedown" , handleMouseDown ) ;
850+ textarea . addEventListener ( "mouseup" , handleMouseUp ) ;
851+
852+ return ( ) => {
853+ textarea . removeEventListener ( "mousedown" , handleMouseDown ) ;
854+ textarea . removeEventListener ( "mouseup" , handleMouseUp ) ;
855+ } ;
856+ } , [ ] ) ;
857+
809858 // Switch back to write mode when content is cleared externally (like after submit)
810859 const prevValueRef = useRef ( value ) ;
811860 useEffect ( ( ) => {
812861 // Only switch if value was cleared (had content before, empty now)
813862 if ( prevValueRef . current && ! value && activeTab === "preview" ) {
814863 setActiveTab ( "write" ) ;
815864 }
865+ // Reset manual resize flag when content is cleared (new comment)
866+ if ( prevValueRef . current && ! value ) {
867+ userResizedRef . current = false ;
868+ }
816869 prevValueRef . current = value ;
817870 } , [ value , activeTab ] ) ;
818871
@@ -1370,11 +1423,19 @@ export const MarkdownEditor = memo(function MarkdownEditor({
13701423 placeholder = { placeholder }
13711424 disabled = { disabled }
13721425 className = { cn (
1373- "w-full px-3 py-2 text-sm bg-transparent resize-none focus:outline-none" ,
1426+ "w-full px-3 py-2 text-sm bg-transparent resize-vertical focus:outline-none" ,
13741427 "placeholder:text-muted-foreground" ,
13751428 disabled && "opacity-50 cursor-not-allowed"
13761429 ) }
1377- style = { { minHeight } }
1430+ style = { {
1431+ minHeight,
1432+ maxHeight,
1433+ // Use field-sizing for browsers that support it (Chrome 123+, Safari 26.2+)
1434+ // Falls back to JS auto-resize for others
1435+ fieldSizing : "content" ,
1436+ // overflow: auto is required for resize handle to appear
1437+ overflowY : "auto" ,
1438+ } }
13781439 />
13791440 </ div >
13801441 < PopoverContent
@@ -1427,7 +1488,10 @@ export const MarkdownEditor = memo(function MarkdownEditor({
14271488 </ PopoverContent >
14281489 </ Popover >
14291490 ) : (
1430- < div className = "px-3 py-2 overflow-auto" style = { { minHeight } } >
1491+ < div
1492+ className = "px-3 py-2 overflow-auto"
1493+ style = { { minHeight, maxHeight } }
1494+ >
14311495 { value . trim ( ) ? (
14321496 < Markdown className = "text-sm" > { value } </ Markdown >
14331497 ) : (
0 commit comments