"use client";
import { useCallback, useEffect, useRef, useState } from "react";
import { useEnsuredRef } from "../useEnsuredRef.js";
import { useResizeObserver } from "../useResizeObserver.js";
// this is the default of 1.5rem line-height in the styles
const DEFAULT_LINE_HEIGHT = 24;
const noop = ()=>{
// do nothing
};
/** @internal */ export function useResizingTextArea(options) {
    const { maxRows, resize, onChange = noop, containerRef: propContainerRef, disableTransition } = options;
    const maskRef = useRef(null);
    const [containerRef, containerRefCallback] = useEnsuredRef(propContainerRef);
    const [height, setHeight] = useState();
    useEffect(()=>{
        if (resize !== "auto") {
            setHeight(undefined);
        }
    }, [
        resize
    ]);
    // Since access to the DOM is required to calculate the current height of the
    // textarea, do not enable the height transition until it has been calculated
    // once.
    const isHeightSet = useRef(true);
    useEffect(()=>{
        isHeightSet.current = !height;
    }, [
        height
    ]);
    // Do not enable the scrollbar until the max height has been reached since
    // it'll flash as the user types on OS that display scrollbars.
    //
    // Note: This does cause an infinite loop issue on browsers that display OS
    // when rendered in a flex/grid container and a "fluid" width since:
    // - the width changes when the overflow changes to `auto`
    // - the resize observer triggers since there was a width change
    // - the number of rows imght change because of this width change
    // - it might no longer be at the max height, so remove the scrollbar
    // - restart
    const [isMaxHeightReached, setMaxHeightReached] = useState(false);
    const updateHeight = useCallback(()=>{
        const mask = maskRef.current;
        const container = containerRef.current;
        /* c8 ignore start */ if (!mask || !container) {
            return;
        }
        /* c8 ignore stop */ const containerStyles = window.getComputedStyle(container);
        const isBorderBox = containerStyles.boxSizing === "border-box";
        let borderHeight = 0;
        if (isBorderBox) {
            borderHeight = parseFloat(containerStyles.borderTopWidth) + parseFloat(containerStyles.borderBottomWidth);
        }
        let nextHeight = mask.scrollHeight + borderHeight;
        if (maxRows > 0) {
            nextHeight -= borderHeight;
            const maskStyles = window.getComputedStyle(mask);
            // in tests, this is `"normal"` by default instead of a number
            let lineHeight = parseFloat(maskStyles.lineHeight);
            if (Number.isNaN(lineHeight)) {
                lineHeight = DEFAULT_LINE_HEIGHT;
            }
            const maxHeight = maxRows * lineHeight;
            nextHeight = Math.min(maxHeight, nextHeight);
            setMaxHeightReached(nextHeight === maxHeight);
            nextHeight += borderHeight;
        }
        // This just makes snapshots look nicer since `nextHeight` will be 0 in
        // tests unless the user mocks out all the DOM properties
        if (nextHeight) {
            setHeight(nextHeight);
        }
    }, [
        containerRef,
        maxRows
    ]);
    const maskRefCallback = useResizeObserver({
        ref: maskRef,
        onUpdate: updateHeight,
        disableHeight: true
    });
    return {
        height: typeof height === "number" ? `${height}px` : undefined,
        maskRef: maskRefCallback,
        containerRef: containerRefCallback,
        scrollable: maxRows > 0 && isMaxHeightReached,
        disableTransition: disableTransition || isHeightSet.current,
        onChange (event) {
            onChange(event);
            const mask = maskRef.current;
            if (!mask || resize !== "auto") {
                return;
            }
            // to get the height transition to work, you have to set the height on:
            // - the main container element (including padding) that has the height
            //    transition enabled
            // - a child div wrapper (without padding) that has the height transition
            //    enabled
            // - the textarea element (without padding) and without a height transition
            //
            // if it isn't done this way, the height transition will look weird since
            // the text will be fixed to the bottom of the area and more text at the top
            // will become visible as the height transition completes. applying the
            // transition on the two parent elements work because:
            // - the height is set immediately on the text field so it expands to show all
            //    the text
            // - the height is correctly applied to both parent elements, but their height
            //    haven't fully been adjusted due to the animation
            // - the parent divs have overflow visible by default, so the textarea's text
            //    will expand past the boundaries of the divs and not cause the upwards
            //    animation weirdness.
            mask.value = event.currentTarget.value;
            updateHeight();
        }
    };
}

//# sourceMappingURL=useResizingTextArea.js.map