UNPKG

@material-ui/core

Version:

Quickly build beautiful React apps. Material-UI is a simple and customizable component library to build faster, beautiful, and more accessible React applications. Follow your own design system, or start with Material Design.

234 lines (194 loc) 8.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var React = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _debounce = _interopRequireDefault(require("../utils/debounce")); var _useForkRef = _interopRequireDefault(require("../utils/useForkRef")); var _useEnhancedEffect = _interopRequireDefault(require("../utils/useEnhancedEffect")); var _ownerWindow = _interopRequireDefault(require("../utils/ownerWindow")); var _jsxRuntime = require("react/jsx-runtime"); const _excluded = ["onChange", "maxRows", "minRows", "style", "value"]; function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function getStyleValue(computedStyle, property) { return parseInt(computedStyle[property], 10) || 0; } const styles = { shadow: { // Visibility needed to hide the extra text area on iPads visibility: 'hidden', // Remove from the content flow position: 'absolute', // Ignore the scrollbar width overflow: 'hidden', height: 0, top: 0, left: 0, // Create a new layer, increase the isolation of the computed values transform: 'translateZ(0)' } }; const TextareaAutosize = /*#__PURE__*/React.forwardRef(function TextareaAutosize(props, ref) { const { onChange, maxRows, minRows = 1, style, value } = props, other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded); const { current: isControlled } = React.useRef(value != null); const inputRef = React.useRef(null); const handleRef = (0, _useForkRef.default)(ref, inputRef); const shadowRef = React.useRef(null); const renders = React.useRef(0); const [state, setState] = React.useState({}); const syncHeight = React.useCallback(() => { const input = inputRef.current; const containerWindow = (0, _ownerWindow.default)(input); const computedStyle = containerWindow.getComputedStyle(input); // If input's width is shrunk and it's not visible, don't sync height. if (computedStyle.width === '0px') { return; } const inputShallow = shadowRef.current; inputShallow.style.width = computedStyle.width; inputShallow.value = input.value || props.placeholder || 'x'; if (inputShallow.value.slice(-1) === '\n') { // Certain fonts which overflow the line height will cause the textarea // to report a different scrollHeight depending on whether the last line // is empty. Make it non-empty to avoid this issue. inputShallow.value += ' '; } const boxSizing = computedStyle['box-sizing']; const padding = getStyleValue(computedStyle, 'padding-bottom') + getStyleValue(computedStyle, 'padding-top'); const border = getStyleValue(computedStyle, 'border-bottom-width') + getStyleValue(computedStyle, 'border-top-width'); // The height of the inner content const innerHeight = inputShallow.scrollHeight; // Measure height of a textarea with a single row inputShallow.value = 'x'; const singleRowHeight = inputShallow.scrollHeight; // The height of the outer content let outerHeight = innerHeight; if (minRows) { outerHeight = Math.max(Number(minRows) * singleRowHeight, outerHeight); } if (maxRows) { outerHeight = Math.min(Number(maxRows) * singleRowHeight, outerHeight); } outerHeight = Math.max(outerHeight, singleRowHeight); // Take the box sizing into account for applying this value as a style. const outerHeightStyle = outerHeight + (boxSizing === 'border-box' ? padding + border : 0); const overflow = Math.abs(outerHeight - innerHeight) <= 1; setState(prevState => { // Need a large enough difference to update the height. // This prevents infinite rendering loop. if (renders.current < 20 && (outerHeightStyle > 0 && Math.abs((prevState.outerHeightStyle || 0) - outerHeightStyle) > 1 || prevState.overflow !== overflow)) { renders.current += 1; return { overflow, outerHeightStyle }; } if (process.env.NODE_ENV !== 'production') { if (renders.current === 20) { console.error(['Material-UI: Too many re-renders. The layout is unstable.', 'TextareaAutosize limits the number of renders to prevent an infinite loop.'].join('\n')); } } return prevState; }); }, [maxRows, minRows, props.placeholder]); React.useEffect(() => { const handleResize = (0, _debounce.default)(() => { renders.current = 0; syncHeight(); }); const containerWindow = (0, _ownerWindow.default)(inputRef.current); containerWindow.addEventListener('resize', handleResize); return () => { handleResize.clear(); containerWindow.removeEventListener('resize', handleResize); }; }, [syncHeight]); (0, _useEnhancedEffect.default)(() => { syncHeight(); }); React.useEffect(() => { renders.current = 0; }, [value]); const handleChange = event => { renders.current = 0; if (!isControlled) { syncHeight(); } if (onChange) { onChange(event); } }; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(React.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("textarea", (0, _extends2.default)({ value: value, onChange: handleChange, ref: handleRef // Apply the rows prop to get a "correct" first SSR paint , rows: minRows, style: (0, _extends2.default)({ height: state.outerHeightStyle, // Need a large enough difference to allow scrolling. // This prevents infinite rendering loop. overflow: state.overflow ? 'hidden' : null }, style) }, other)), /*#__PURE__*/(0, _jsxRuntime.jsx)("textarea", { "aria-hidden": true, className: props.className, readOnly: true, ref: shadowRef, tabIndex: -1, style: (0, _extends2.default)({}, styles.shadow, style, { padding: 0 }) })] }); }); process.env.NODE_ENV !== "production" ? TextareaAutosize.propTypes /* remove-proptypes */ = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the d.ts file and run "yarn proptypes" | // ---------------------------------------------------------------------- /** * @ignore */ className: _propTypes.default.string, /** * Maximum number of rows to display. */ maxRows: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** * Minimum number of rows to display. * @default 1 */ minRows: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** * @ignore */ onChange: _propTypes.default.func, /** * @ignore */ placeholder: _propTypes.default.string, /** * @ignore */ style: _propTypes.default.object, /** * @ignore */ value: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.string), _propTypes.default.number, _propTypes.default.string]) } : void 0; var _default = TextareaAutosize; exports.default = _default;