1
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
import * as React from 'react';
|
||||
import type { ResizableTextAreaRef } from './interface';
|
||||
declare const ResizableTextArea: React.ForwardRefExoticComponent<Omit<import("./interface").HTMLTextareaProps, "value" | "onResize"> & {
|
||||
value?: string | number | bigint | readonly string[];
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
autoSize?: boolean | import("./interface").AutoSizeType;
|
||||
onPressEnter?: React.KeyboardEventHandler<HTMLTextAreaElement>;
|
||||
onResize?: (size: {
|
||||
width: number;
|
||||
height: number;
|
||||
}) => void;
|
||||
classNames?: {
|
||||
affixWrapper?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
groupWrapper?: string;
|
||||
wrapper?: string;
|
||||
variant?: string;
|
||||
} & {
|
||||
textarea?: string;
|
||||
count?: string;
|
||||
};
|
||||
styles?: {
|
||||
textarea?: React.CSSProperties;
|
||||
count?: React.CSSProperties;
|
||||
};
|
||||
} & Pick<import("@rc-component/input/lib/interface").BaseInputProps, "allowClear" | "suffix"> & Pick<import("@rc-component/input").InputProps, "showCount" | "count" | "onClear"> & React.RefAttributes<ResizableTextAreaRef>>;
|
||||
export default ResizableTextArea;
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _resizeObserver = _interopRequireDefault(require("@rc-component/resize-observer"));
|
||||
var _useControlledState = _interopRequireDefault(require("@rc-component/util/lib/hooks/useControlledState"));
|
||||
var _useLayoutEffect = _interopRequireDefault(require("@rc-component/util/lib/hooks/useLayoutEffect"));
|
||||
var _raf = _interopRequireDefault(require("@rc-component/util/lib/raf"));
|
||||
var _clsx = require("clsx");
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _calculateNodeHeight = _interopRequireDefault(require("./calculateNodeHeight"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
const RESIZE_START = 0;
|
||||
const RESIZE_MEASURING = 1;
|
||||
const RESIZE_STABLE = 2;
|
||||
const ResizableTextArea = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
prefixCls,
|
||||
defaultValue,
|
||||
value,
|
||||
autoSize,
|
||||
onResize,
|
||||
className,
|
||||
style,
|
||||
disabled,
|
||||
onChange,
|
||||
// Test only
|
||||
onInternalAutoSize,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
// =============================== Value ================================
|
||||
const [internalValue, setMergedValue] = (0, _useControlledState.default)(defaultValue, value);
|
||||
const mergedValue = internalValue ?? '';
|
||||
const onInternalChange = event => {
|
||||
setMergedValue(event.target.value);
|
||||
onChange?.(event);
|
||||
};
|
||||
|
||||
// ================================ Ref =================================
|
||||
const textareaRef = React.useRef();
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
textArea: textareaRef.current
|
||||
}));
|
||||
|
||||
// ============================== AutoSize ==============================
|
||||
const [minRows, maxRows] = React.useMemo(() => {
|
||||
if (autoSize && typeof autoSize === 'object') {
|
||||
return [autoSize.minRows, autoSize.maxRows];
|
||||
}
|
||||
return [];
|
||||
}, [autoSize]);
|
||||
const needAutoSize = !!autoSize;
|
||||
|
||||
// =============================== Resize ===============================
|
||||
const [resizeState, setResizeState] = React.useState(RESIZE_STABLE);
|
||||
const [autoSizeStyle, setAutoSizeStyle] = React.useState();
|
||||
const startResize = () => {
|
||||
setResizeState(RESIZE_START);
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
onInternalAutoSize?.();
|
||||
}
|
||||
};
|
||||
|
||||
// Change to trigger resize measure
|
||||
(0, _useLayoutEffect.default)(() => {
|
||||
if (needAutoSize) {
|
||||
startResize();
|
||||
}
|
||||
}, [value, minRows, maxRows, needAutoSize]);
|
||||
(0, _useLayoutEffect.default)(() => {
|
||||
if (resizeState === RESIZE_START) {
|
||||
setResizeState(RESIZE_MEASURING);
|
||||
} else if (resizeState === RESIZE_MEASURING) {
|
||||
const textareaStyles = (0, _calculateNodeHeight.default)(textareaRef.current, false, minRows, maxRows);
|
||||
|
||||
// Safari has bug that text will keep break line on text cut when it's prev is break line.
|
||||
// ZombieJ: This not often happen. So we just skip it.
|
||||
// const { selectionStart, selectionEnd, scrollTop } = textareaRef.current;
|
||||
// const { value: tmpValue } = textareaRef.current;
|
||||
// textareaRef.current.value = '';
|
||||
// textareaRef.current.value = tmpValue;
|
||||
|
||||
// if (document.activeElement === textareaRef.current) {
|
||||
// textareaRef.current.scrollTop = scrollTop;
|
||||
// textareaRef.current.setSelectionRange(selectionStart, selectionEnd);
|
||||
// }
|
||||
|
||||
setResizeState(RESIZE_STABLE);
|
||||
setAutoSizeStyle(textareaStyles);
|
||||
} else {
|
||||
// https://github.com/react-component/textarea/pull/23
|
||||
// Firefox has blink issue before but fixed in latest version.
|
||||
}
|
||||
}, [resizeState]);
|
||||
|
||||
// We lock resize trigger by raf to avoid Safari warning
|
||||
const resizeRafRef = React.useRef();
|
||||
const cleanRaf = () => {
|
||||
_raf.default.cancel(resizeRafRef.current);
|
||||
};
|
||||
const onInternalResize = size => {
|
||||
if (resizeState === RESIZE_STABLE) {
|
||||
onResize?.(size);
|
||||
if (autoSize) {
|
||||
cleanRaf();
|
||||
resizeRafRef.current = (0, _raf.default)(() => {
|
||||
startResize();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
React.useEffect(() => cleanRaf, []);
|
||||
|
||||
// =============================== Render ===============================
|
||||
const mergedAutoSizeStyle = needAutoSize ? autoSizeStyle : null;
|
||||
const mergedStyle = {
|
||||
...style,
|
||||
...mergedAutoSizeStyle
|
||||
};
|
||||
if (resizeState === RESIZE_START || resizeState === RESIZE_MEASURING) {
|
||||
mergedStyle.overflowY = 'hidden';
|
||||
mergedStyle.overflowX = 'hidden';
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(_resizeObserver.default, {
|
||||
onResize: onInternalResize,
|
||||
disabled: !(autoSize || onResize)
|
||||
}, /*#__PURE__*/React.createElement("textarea", _extends({}, restProps, {
|
||||
ref: textareaRef,
|
||||
style: mergedStyle,
|
||||
className: (0, _clsx.clsx)(prefixCls, className, {
|
||||
[`${prefixCls}-disabled`]: disabled
|
||||
}),
|
||||
disabled: disabled,
|
||||
value: mergedValue,
|
||||
onChange: onInternalChange
|
||||
})));
|
||||
});
|
||||
var _default = exports.default = ResizableTextArea;
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import type { TextAreaRef } from './interface';
|
||||
declare const TextArea: React.ForwardRefExoticComponent<Omit<import("./interface").HTMLTextareaProps, "value" | "onResize"> & {
|
||||
value?: string | number | bigint | readonly string[];
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
autoSize?: boolean | import("./interface").AutoSizeType;
|
||||
onPressEnter?: React.KeyboardEventHandler<HTMLTextAreaElement>;
|
||||
onResize?: (size: {
|
||||
width: number;
|
||||
height: number;
|
||||
}) => void;
|
||||
classNames?: {
|
||||
affixWrapper?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
groupWrapper?: string;
|
||||
wrapper?: string;
|
||||
variant?: string;
|
||||
} & {
|
||||
textarea?: string;
|
||||
count?: string;
|
||||
};
|
||||
styles?: {
|
||||
textarea?: React.CSSProperties;
|
||||
count?: React.CSSProperties;
|
||||
};
|
||||
} & Pick<import("@rc-component/input/lib/interface").BaseInputProps, "allowClear" | "suffix"> & Pick<import("@rc-component/input").InputProps, "showCount" | "count" | "onClear"> & React.RefAttributes<TextAreaRef>>;
|
||||
export default TextArea;
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _input = require("@rc-component/input");
|
||||
var _useCount = _interopRequireDefault(require("@rc-component/input/lib/hooks/useCount"));
|
||||
var _commonUtils = require("@rc-component/input/lib/utils/commonUtils");
|
||||
var _useControlledState = _interopRequireDefault(require("@rc-component/util/lib/hooks/useControlledState"));
|
||||
var _clsx = require("clsx");
|
||||
var _react = _interopRequireWildcard(require("react"));
|
||||
var _ResizableTextArea = _interopRequireDefault(require("./ResizableTextArea"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
const TextArea = /*#__PURE__*/_react.default.forwardRef(({
|
||||
defaultValue,
|
||||
value: customValue,
|
||||
onFocus,
|
||||
onBlur,
|
||||
onChange,
|
||||
allowClear,
|
||||
maxLength,
|
||||
onCompositionStart,
|
||||
onCompositionEnd,
|
||||
suffix,
|
||||
prefixCls = 'rc-textarea',
|
||||
showCount,
|
||||
count,
|
||||
className,
|
||||
style,
|
||||
disabled,
|
||||
hidden,
|
||||
classNames,
|
||||
styles,
|
||||
onResize,
|
||||
onClear,
|
||||
onPressEnter,
|
||||
readOnly,
|
||||
autoSize,
|
||||
onKeyDown,
|
||||
...rest
|
||||
}, ref) => {
|
||||
const [value, setValue] = (0, _useControlledState.default)(defaultValue, customValue);
|
||||
const formatValue = value === undefined || value === null ? '' : String(value);
|
||||
const [focused, setFocused] = _react.default.useState(false);
|
||||
const compositionRef = _react.default.useRef(false);
|
||||
const [textareaResized, setTextareaResized] = _react.default.useState(null);
|
||||
|
||||
// =============================== Ref ================================
|
||||
const holderRef = (0, _react.useRef)(null);
|
||||
const resizableTextAreaRef = (0, _react.useRef)(null);
|
||||
const getTextArea = () => resizableTextAreaRef.current?.textArea;
|
||||
const focus = () => {
|
||||
getTextArea().focus();
|
||||
};
|
||||
(0, _react.useImperativeHandle)(ref, () => ({
|
||||
resizableTextArea: resizableTextAreaRef.current,
|
||||
focus,
|
||||
blur: () => {
|
||||
getTextArea().blur();
|
||||
},
|
||||
nativeElement: holderRef.current?.nativeElement || getTextArea()
|
||||
}));
|
||||
(0, _react.useEffect)(() => {
|
||||
setFocused(prev => !disabled && prev);
|
||||
}, [disabled]);
|
||||
|
||||
// =========================== Select Range ===========================
|
||||
const [selection, setSelection] = _react.default.useState(null);
|
||||
_react.default.useEffect(() => {
|
||||
if (selection) {
|
||||
getTextArea().setSelectionRange(...selection);
|
||||
}
|
||||
}, [selection]);
|
||||
|
||||
// ============================== Count ===============================
|
||||
const countConfig = (0, _useCount.default)(count, showCount);
|
||||
const mergedMax = countConfig.max ?? maxLength;
|
||||
|
||||
// Max length value
|
||||
const hasMaxLength = Number(mergedMax) > 0;
|
||||
const valueLength = countConfig.strategy(formatValue);
|
||||
const isOutOfRange = !!mergedMax && valueLength > mergedMax;
|
||||
|
||||
// ============================== Change ==============================
|
||||
const triggerChange = (e, currentValue) => {
|
||||
let cutValue = currentValue;
|
||||
if (!compositionRef.current && countConfig.exceedFormatter && countConfig.max && countConfig.strategy(currentValue) > countConfig.max) {
|
||||
cutValue = countConfig.exceedFormatter(currentValue, {
|
||||
max: countConfig.max
|
||||
});
|
||||
if (currentValue !== cutValue) {
|
||||
setSelection([getTextArea().selectionStart || 0, getTextArea().selectionEnd || 0]);
|
||||
}
|
||||
}
|
||||
setValue(cutValue);
|
||||
(0, _commonUtils.resolveOnChange)(e.currentTarget, e, onChange, cutValue);
|
||||
};
|
||||
|
||||
// =========================== Value Update ===========================
|
||||
const onInternalCompositionStart = e => {
|
||||
compositionRef.current = true;
|
||||
onCompositionStart?.(e);
|
||||
};
|
||||
const onInternalCompositionEnd = e => {
|
||||
compositionRef.current = false;
|
||||
triggerChange(e, e.currentTarget.value);
|
||||
onCompositionEnd?.(e);
|
||||
};
|
||||
const onInternalChange = e => {
|
||||
triggerChange(e, e.target.value);
|
||||
};
|
||||
const handleKeyDown = e => {
|
||||
if (e.key === 'Enter' && onPressEnter && !e.nativeEvent.isComposing) {
|
||||
onPressEnter(e);
|
||||
}
|
||||
onKeyDown?.(e);
|
||||
};
|
||||
const handleFocus = e => {
|
||||
setFocused(true);
|
||||
onFocus?.(e);
|
||||
};
|
||||
const handleBlur = e => {
|
||||
setFocused(false);
|
||||
onBlur?.(e);
|
||||
};
|
||||
|
||||
// ============================== Reset ===============================
|
||||
const handleReset = e => {
|
||||
setValue('');
|
||||
focus();
|
||||
(0, _commonUtils.resolveOnChange)(getTextArea(), e, onChange);
|
||||
};
|
||||
let suffixNode = suffix;
|
||||
let dataCount;
|
||||
if (countConfig.show) {
|
||||
if (countConfig.showFormatter) {
|
||||
dataCount = countConfig.showFormatter({
|
||||
value: formatValue,
|
||||
count: valueLength,
|
||||
maxLength: mergedMax
|
||||
});
|
||||
} else {
|
||||
dataCount = `${valueLength}${hasMaxLength ? ` / ${mergedMax}` : ''}`;
|
||||
}
|
||||
suffixNode = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, suffixNode, /*#__PURE__*/_react.default.createElement("span", {
|
||||
className: (0, _clsx.clsx)(`${prefixCls}-data-count`, classNames?.count),
|
||||
style: styles?.count
|
||||
}, dataCount));
|
||||
}
|
||||
const handleResize = size => {
|
||||
onResize?.(size);
|
||||
if (getTextArea()?.style.height) {
|
||||
setTextareaResized(true);
|
||||
}
|
||||
};
|
||||
const isPureTextArea = !autoSize && !showCount && !allowClear;
|
||||
return /*#__PURE__*/_react.default.createElement(_input.BaseInput, {
|
||||
ref: holderRef,
|
||||
value: formatValue,
|
||||
allowClear: allowClear,
|
||||
handleReset: handleReset,
|
||||
suffix: suffixNode,
|
||||
prefixCls: prefixCls,
|
||||
classNames: {
|
||||
...classNames,
|
||||
affixWrapper: (0, _clsx.clsx)(classNames?.affixWrapper, {
|
||||
[`${prefixCls}-show-count`]: showCount,
|
||||
[`${prefixCls}-textarea-allow-clear`]: allowClear
|
||||
})
|
||||
},
|
||||
disabled: disabled,
|
||||
focused: focused,
|
||||
className: (0, _clsx.clsx)(className, isOutOfRange && `${prefixCls}-out-of-range`),
|
||||
style: {
|
||||
...style,
|
||||
...(textareaResized && !isPureTextArea ? {
|
||||
height: 'auto'
|
||||
} : {})
|
||||
},
|
||||
dataAttrs: {
|
||||
affixWrapper: {
|
||||
'data-count': typeof dataCount === 'string' ? dataCount : undefined
|
||||
}
|
||||
},
|
||||
hidden: hidden,
|
||||
readOnly: readOnly,
|
||||
onClear: onClear
|
||||
}, /*#__PURE__*/_react.default.createElement(_ResizableTextArea.default, _extends({}, rest, {
|
||||
autoSize: autoSize,
|
||||
maxLength: maxLength,
|
||||
onKeyDown: handleKeyDown,
|
||||
onChange: onInternalChange,
|
||||
onFocus: handleFocus,
|
||||
onBlur: handleBlur,
|
||||
onCompositionStart: onInternalCompositionStart,
|
||||
onCompositionEnd: onInternalCompositionEnd,
|
||||
className: (0, _clsx.clsx)(classNames?.textarea),
|
||||
style: {
|
||||
resize: style?.resize,
|
||||
...styles?.textarea
|
||||
},
|
||||
disabled: disabled,
|
||||
prefixCls: prefixCls,
|
||||
onResize: handleResize,
|
||||
ref: resizableTextAreaRef,
|
||||
readOnly: readOnly
|
||||
})));
|
||||
});
|
||||
var _default = exports.default = TextArea;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import type React from 'react';
|
||||
export interface NodeType {
|
||||
sizingStyle: string;
|
||||
paddingSize: number;
|
||||
borderSize: number;
|
||||
boxSizing: string;
|
||||
}
|
||||
export declare function calculateNodeStyling(node: HTMLElement, useCache?: boolean): NodeType;
|
||||
export default function calculateAutoSizeStyle(uiTextNode: HTMLTextAreaElement, useCache?: boolean, minRows?: number | null, maxRows?: number | null): React.CSSProperties;
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.calculateNodeStyling = calculateNodeStyling;
|
||||
exports.default = calculateAutoSizeStyle;
|
||||
// Thanks to https://github.com/andreypopp/react-textarea-autosize/
|
||||
|
||||
/**
|
||||
* calculateNodeHeight(uiTextNode, useCache = false)
|
||||
*/
|
||||
|
||||
const HIDDEN_TEXTAREA_STYLE = `
|
||||
min-height:0 !important;
|
||||
max-height:none !important;
|
||||
height:0 !important;
|
||||
visibility:hidden !important;
|
||||
overflow:hidden !important;
|
||||
position:absolute !important;
|
||||
z-index:-1000 !important;
|
||||
top:0 !important;
|
||||
right:0 !important;
|
||||
pointer-events: none !important;
|
||||
`;
|
||||
const SIZING_STYLE = ['letter-spacing', 'line-height', 'padding-top', 'padding-bottom', 'font-family', 'font-weight', 'font-size', 'font-variant', 'text-rendering', 'text-transform', 'width', 'text-indent', 'padding-left', 'padding-right', 'border-width', 'box-sizing', 'word-break', 'white-space'];
|
||||
const computedStyleCache = {};
|
||||
let hiddenTextarea;
|
||||
function calculateNodeStyling(node, useCache = false) {
|
||||
const nodeRef = node.getAttribute('id') || node.getAttribute('data-reactid') || node.getAttribute('name');
|
||||
if (useCache && computedStyleCache[nodeRef]) {
|
||||
return computedStyleCache[nodeRef];
|
||||
}
|
||||
const style = window.getComputedStyle(node);
|
||||
const boxSizing = style.getPropertyValue('box-sizing') || style.getPropertyValue('-moz-box-sizing') || style.getPropertyValue('-webkit-box-sizing');
|
||||
const paddingSize = parseFloat(style.getPropertyValue('padding-bottom')) + parseFloat(style.getPropertyValue('padding-top'));
|
||||
const borderSize = parseFloat(style.getPropertyValue('border-bottom-width')) + parseFloat(style.getPropertyValue('border-top-width'));
|
||||
const sizingStyle = SIZING_STYLE.map(name => `${name}:${style.getPropertyValue(name)}`).join(';');
|
||||
const nodeInfo = {
|
||||
sizingStyle,
|
||||
paddingSize,
|
||||
borderSize,
|
||||
boxSizing
|
||||
};
|
||||
if (useCache && nodeRef) {
|
||||
computedStyleCache[nodeRef] = nodeInfo;
|
||||
}
|
||||
return nodeInfo;
|
||||
}
|
||||
function calculateAutoSizeStyle(uiTextNode, useCache = false, minRows = null, maxRows = null) {
|
||||
if (!hiddenTextarea) {
|
||||
hiddenTextarea = document.createElement('textarea');
|
||||
hiddenTextarea.setAttribute('tab-index', '-1');
|
||||
hiddenTextarea.setAttribute('aria-hidden', 'true');
|
||||
// fix: A form field element should have an id or name attribute
|
||||
// A form field element has neither an id nor a name attribute. This might prevent the browser from correctly autofilling the form.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
|
||||
hiddenTextarea.setAttribute('name', 'hiddenTextarea');
|
||||
document.body.appendChild(hiddenTextarea);
|
||||
}
|
||||
|
||||
// Fix wrap="off" issue
|
||||
// https://github.com/ant-design/ant-design/issues/6577
|
||||
if (uiTextNode.getAttribute('wrap')) {
|
||||
hiddenTextarea.setAttribute('wrap', uiTextNode.getAttribute('wrap'));
|
||||
} else {
|
||||
hiddenTextarea.removeAttribute('wrap');
|
||||
}
|
||||
|
||||
// Copy all CSS properties that have an impact on the height of the content in
|
||||
// the textbox
|
||||
const {
|
||||
paddingSize,
|
||||
borderSize,
|
||||
boxSizing,
|
||||
sizingStyle
|
||||
} = calculateNodeStyling(uiTextNode, useCache);
|
||||
|
||||
// Need to have the overflow attribute to hide the scrollbar otherwise
|
||||
// text-lines will not calculated properly as the shadow will technically be
|
||||
// narrower for content
|
||||
hiddenTextarea.setAttribute('style', `${sizingStyle};${HIDDEN_TEXTAREA_STYLE}`);
|
||||
hiddenTextarea.value = uiTextNode.value || uiTextNode.placeholder || '';
|
||||
let minHeight = undefined;
|
||||
let maxHeight = undefined;
|
||||
let overflowY;
|
||||
let height = hiddenTextarea.scrollHeight;
|
||||
if (boxSizing === 'border-box') {
|
||||
// border-box: add border, since height = content + padding + border
|
||||
height += borderSize;
|
||||
} else if (boxSizing === 'content-box') {
|
||||
// remove padding, since height = content
|
||||
height -= paddingSize;
|
||||
}
|
||||
if (minRows !== null || maxRows !== null) {
|
||||
// measure height of a textarea with a single row
|
||||
hiddenTextarea.value = ' ';
|
||||
const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;
|
||||
if (minRows !== null) {
|
||||
minHeight = singleRowHeight * minRows;
|
||||
if (boxSizing === 'border-box') {
|
||||
minHeight = minHeight + paddingSize + borderSize;
|
||||
}
|
||||
height = Math.max(minHeight, height);
|
||||
}
|
||||
if (maxRows !== null) {
|
||||
maxHeight = singleRowHeight * maxRows;
|
||||
if (boxSizing === 'border-box') {
|
||||
maxHeight = maxHeight + paddingSize + borderSize;
|
||||
}
|
||||
overflowY = height > maxHeight ? '' : 'hidden';
|
||||
height = Math.min(maxHeight, height);
|
||||
}
|
||||
}
|
||||
const style = {
|
||||
height,
|
||||
overflowY,
|
||||
resize: 'none'
|
||||
};
|
||||
if (minHeight) {
|
||||
style.minHeight = minHeight;
|
||||
}
|
||||
if (maxHeight) {
|
||||
style.maxHeight = maxHeight;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import TextArea from './TextArea';
|
||||
export { default as ResizableTextArea } from './ResizableTextArea';
|
||||
export type { AutoSizeType, ResizableTextAreaRef, TextAreaProps, TextAreaRef, } from './interface';
|
||||
export default TextArea;
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "ResizableTextArea", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _ResizableTextArea.default;
|
||||
}
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _TextArea = _interopRequireDefault(require("./TextArea"));
|
||||
var _ResizableTextArea = _interopRequireDefault(require("./ResizableTextArea"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
var _default = exports.default = _TextArea.default;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import type { BaseInputProps, CommonInputProps, InputProps } from '@rc-component/input/lib/interface';
|
||||
import type React from 'react';
|
||||
import type { CSSProperties } from 'react';
|
||||
export interface AutoSizeType {
|
||||
minRows?: number;
|
||||
maxRows?: number;
|
||||
}
|
||||
export interface ResizableTextAreaRef {
|
||||
textArea: HTMLTextAreaElement;
|
||||
}
|
||||
export type HTMLTextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
||||
export type TextAreaProps = Omit<HTMLTextareaProps, 'onResize' | 'value'> & {
|
||||
value?: HTMLTextareaProps['value'] | bigint;
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
autoSize?: boolean | AutoSizeType;
|
||||
onPressEnter?: React.KeyboardEventHandler<HTMLTextAreaElement>;
|
||||
onResize?: (size: {
|
||||
width: number;
|
||||
height: number;
|
||||
}) => void;
|
||||
classNames?: CommonInputProps['classNames'] & {
|
||||
textarea?: string;
|
||||
count?: string;
|
||||
};
|
||||
styles?: {
|
||||
textarea?: CSSProperties;
|
||||
count?: CSSProperties;
|
||||
};
|
||||
} & Pick<BaseInputProps, 'allowClear' | 'suffix'> & Pick<InputProps, 'showCount' | 'count' | 'onClear'>;
|
||||
export type TextAreaRef = {
|
||||
resizableTextArea: ResizableTextAreaRef;
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
nativeElement: HTMLElement;
|
||||
};
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Reference in New Issue
Block a user