import { useEffect, useRef } from 'react' import { callFnsInSequence } from '../../utils/functions' import { MergeAndOverride } from '../../../../types/utils' export const resetHeight = ( e: | React.ChangeEvent | React.KeyboardEvent ) => { const el = e.target as HTMLTextAreaElement window.requestAnimationFrame(() => { const curHeight = el.offsetHeight const fitHeight = el.scrollHeight // clear height if text area is empty if (!el.value.length) { el.style.removeProperty('height') } // otherwise expand to fit text else if (fitHeight > curHeight) { el.style.height = `${fitHeight}px` } }) } type AutoExpandingTextAreaProps = MergeAndOverride< React.ComponentProps<'textarea'>, { onResize?: () => void } > function AutoExpandingTextArea({ onChange, onResize, ...rest }: AutoExpandingTextAreaProps) { const ref = useRef(null) useEffect(() => { if (!ref.current || !onResize || !('ResizeObserver' in window)) { return } let isFirstResize = true const resizeObserver = new ResizeObserver(() => { // Ignore the resize that is triggered when the element is first // inserted into the DOM if (isFirstResize) { isFirstResize = false } else { // Prevent errors like "ResizeObserver loop completed with undelivered // notifications" that occur if onResize does something complicated. // The cost of this is that onResize lags one frame behind, but it's // unlikely to matter. window.requestAnimationFrame(onResize) } }) resizeObserver.observe(ref.current) return () => { resizeObserver.disconnect() } }, [onResize]) return (