@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
JavaScript
"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