UNPKG

react-expanding-textarea

Version:

React textarea component to automatically expand and contract your textareas

87 lines (86 loc) 3.78 kB
import { __assign, __rest } from "tslib"; import React, { useCallback, useLayoutEffect, useMemo, useRef, } from 'react'; import withForwardedRef from 'react-with-forwarded-ref'; import { equal as isShallowEqual } from 'fast-shallow-equal'; export var getHeight = function (rows, el) { var _a = window.getComputedStyle(el), borderBottomWidth = _a.borderBottomWidth, borderTopWidth = _a.borderTopWidth, fontSize = _a.fontSize, lineHeight = _a.lineHeight, paddingBottom = _a.paddingBottom, paddingTop = _a.paddingTop; var lh = lineHeight === 'normal' ? parseFloat(fontSize) * 1.2 : parseFloat(lineHeight); var rowHeight = rows === 0 ? 0 : lh * rows + parseFloat(borderBottomWidth) + parseFloat(borderTopWidth) + parseFloat(paddingBottom) + parseFloat(paddingTop); var scrollHeight = el.scrollHeight + parseFloat(borderBottomWidth) + parseFloat(borderTopWidth); return Math.max(rowHeight, scrollHeight); }; export var resize = function (rows, el) { if (el) { var overflowY = 'hidden'; var maxHeight = window.getComputedStyle(el).maxHeight; if (maxHeight !== 'none') { var maxHeightN = parseFloat(maxHeight); if (maxHeightN < el.scrollHeight) { overflowY = ''; } } el.style.height = '0'; el.style.overflowY = overflowY; el.style.height = "".concat(getHeight(rows, el), "px"); } }; // ============================================================================= var useShallowObjectMemo = function (obj) { var refObject = useRef(obj); var refCounter = useRef(0); if (!isShallowEqual(obj, refObject.current)) { refObject.current = obj; refCounter.current += 1; } // eslint-disable-next-line react-hooks/exhaustive-deps return useMemo(function () { return refObject.current; }, [refCounter.current]); }; // ============================================================================= var useSSRLayoutEffect = typeof window === 'undefined' ? Function.prototype : useLayoutEffect; var ExpandingTextarea = function (_a) { var forwardedRef = _a.forwardedRef, props = __rest(_a, ["forwardedRef"]); var isForwardedRefFn = typeof forwardedRef === 'function'; var style = useShallowObjectMemo(props.style); var internalRef = useRef(); var ref = (isForwardedRefFn || !forwardedRef ? internalRef : forwardedRef); var rows = props.rows ? parseInt('' + props.rows, 10) : 0; var onChange = props.onChange, onInput = props.onInput, rest = __rest(props, ["onChange", "onInput"]); useSSRLayoutEffect(function () { resize(rows, ref.current); }, [props.className, props.value, ref, rows, style]); useSSRLayoutEffect(function () { if (!window.ResizeObserver) { return; } var observer = new ResizeObserver(function () { resize(rows, ref.current); }); observer.observe(ref.current); return function () { observer.disconnect(); }; }, [ref, rows]); var handleInput = useCallback(function (e) { onChange === null || onChange === void 0 ? void 0 : onChange(e); onInput === null || onInput === void 0 ? void 0 : onInput(e); resize(rows, ref.current); }, [onChange, onInput, ref, rows]); var handleRef = useCallback(function (node) { ref.current = node; if (isForwardedRefFn) { forwardedRef(node); } }, [forwardedRef, isForwardedRefFn, ref]); return (React.createElement("textarea", __assign({}, rest, { onInput: handleInput, ref: handleRef, rows: rows }))); }; export default withForwardedRef(ExpandingTextarea);