UNPKG

@yamada-ui/react

Version:

React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion

134 lines (130 loc) 3.74 kB
"use client"; import { useSafeLayoutEffect, useUpdateEffect } from "../../utils/effect.js"; import { mergeRefs } from "../../utils/ref.js"; import { utils_exports } from "../../utils/index.js"; import { useCallback, useRef } from "react"; //#region src/components/textarea/use-autosize.ts const SIZING_STYLE_PROPERTIES = [ "borderBottomWidth", "borderLeftWidth", "borderRightWidth", "borderTopWidth", "boxSizing", "fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "lineHeight", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "tabSize", "textIndent", "textRendering", "textTransform", "width", "wordBreak" ]; const HIDDEN_STYLE = { height: "0", "max-height": "none", "min-height": "0", overflow: "hidden", position: "absolute", right: "0", top: "0", visibility: "hidden", "z-index": "-1000" }; const getSizingStyle = (el) => { const style = window.getComputedStyle(el); if (style == null) return null; const computedStyle = (0, utils_exports.pickObject)(style, SIZING_STYLE_PROPERTIES); if (computedStyle.boxSizing === "") return null; const padding = parseFloat(computedStyle.paddingBottom) + parseFloat(computedStyle.paddingTop); return { style: computedStyle, border: parseFloat(computedStyle.borderBottomWidth) + parseFloat(computedStyle.borderTopWidth), padding, rowHeight: parseFloat(computedStyle.lineHeight) }; }; const setHiddenStyle = (el) => { Object.keys(HIDDEN_STYLE).forEach((key) => { el.style.setProperty(key, HIDDEN_STYLE[key], "important"); }); }; const calcRows = (el, sizingStyle, value, maxRows, minRows) => { const cloneEl = el.cloneNode(); Object.assign(cloneEl.style, sizingStyle.style); setHiddenStyle(cloneEl); cloneEl.value = value; document.body.appendChild(cloneEl); let rows; if (cloneEl.scrollHeight) { const rowHeight = sizingStyle.rowHeight; rows = Math.min(maxRows, Math.max(minRows, Math.floor(cloneEl.scrollHeight / rowHeight))); } else { const lineBreaks = (value.match(/\n/g) || []).length; rows = Math.min(maxRows, Math.max(minRows, lineBreaks + 1)); } document.body.removeChild(cloneEl); return rows; }; const useAutosize = ({ disabled = false, maxRows = Infinity, minRows = 2 } = {}) => { const ref = useRef(null); const beforeValueRef = useRef(null); const value = ref.current?.value ?? ""; const onResizeTextarea = useCallback(() => { const el = ref.current; if (!el) return; let { placeholder, value: value$1 } = el; if (value$1 === beforeValueRef.current) return; beforeValueRef.current = value$1; value$1 ||= placeholder || "x"; const sizingStyle = getSizingStyle(el); if (!sizingStyle) return; el.rows = calcRows(el, sizingStyle, value$1, maxRows, minRows); }, [ ref, maxRows, minRows ]); const getTextareaProps = useCallback((props = {}) => ({ ...props, ref: mergeRefs(props.ref, ref), style: { resize: !disabled ? "none" : void 0, ...props.style }, onChange: (0, utils_exports.handlerAll)(props.onChange, !disabled ? onResizeTextarea : utils_exports.noop) }), [ ref, onResizeTextarea, disabled ]); useSafeLayoutEffect(() => { if (!(0, utils_exports.createdDom)() || disabled) return; onResizeTextarea(); const unsubscribeResize = (0, utils_exports.addDomEvent)(window, "resize", onResizeTextarea); const unsubscribeLoadingdone = (0, utils_exports.addDomEvent)(document.fonts, "loadingdone", onResizeTextarea); return () => { unsubscribeResize(); unsubscribeLoadingdone(); }; }, []); useUpdateEffect(() => { if (disabled) return; onResizeTextarea(); }, [value]); return { ref, getTextareaProps, onResizeTextarea }; }; //#endregion export { useAutosize }; //# sourceMappingURL=use-autosize.js.map