ant-design/components/input/TextArea.tsx

160 lines
4.4 KiB
TypeScript
Raw Normal View History

import * as React from 'react';
2017-05-22 14:44:58 +08:00
import omit from 'omit.js';
import classNames from 'classnames';
import { polyfill } from 'react-lifecycles-compat';
import ResizeObserver from 'rc-resize-observer';
2017-05-22 14:44:58 +08:00
import calculateNodeHeight from './calculateNodeHeight';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import raf from '../_util/raf';
2019-10-11 18:12:28 +08:00
import warning from '../_util/warning';
2017-05-22 14:44:58 +08:00
export interface AutoSizeType {
minRows?: number;
maxRows?: number;
}
export type HTMLTextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
export interface TextAreaProps extends HTMLTextareaProps {
prefixCls?: string;
2019-10-11 18:12:28 +08:00
/* deprecated, use autoSize instead */
2017-05-22 14:44:58 +08:00
autosize?: boolean | AutoSizeType;
2019-10-11 18:12:28 +08:00
autoSize?: boolean | AutoSizeType;
onPressEnter?: React.KeyboardEventHandler<HTMLTextAreaElement>;
2017-05-22 14:44:58 +08:00
}
export interface TextAreaState {
textareaStyles?: React.CSSProperties;
/** We need add process style to disable scroll first and then add back to avoid unexpected scrollbar */
resizing?: boolean;
}
class TextArea extends React.Component<TextAreaProps, TextAreaState> {
2017-05-22 14:44:58 +08:00
nextFrameActionId: number;
2019-08-05 18:38:10 +08:00
resizeFrameId: number;
2017-09-17 15:48:44 +08:00
2017-05-22 14:44:58 +08:00
state = {
textareaStyles: {},
resizing: false,
2017-05-22 14:44:58 +08:00
};
2017-09-17 15:48:44 +08:00
private textAreaRef: HTMLTextAreaElement;
2017-05-22 14:44:58 +08:00
componentDidMount() {
this.resizeTextarea();
}
componentDidUpdate(prevProps: TextAreaProps) {
2017-05-22 14:44:58 +08:00
// Re-render with the new content then recalculate the height as required.
if (prevProps.value !== this.props.value) {
this.resizeTextarea();
}
}
componentWillUnmount() {
raf.cancel(this.nextFrameActionId);
raf.cancel(this.resizeFrameId);
}
2019-08-05 18:38:10 +08:00
saveTextAreaRef = (textArea: HTMLTextAreaElement) => {
this.textAreaRef = textArea;
2018-12-07 20:02:01 +08:00
};
2017-05-22 14:44:58 +08:00
2017-11-21 19:51:31 +08:00
handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
2017-05-22 14:44:58 +08:00
if (!('value' in this.props)) {
this.resizeTextarea();
}
const { onChange } = this.props;
if (onChange) {
onChange(e);
}
2018-12-07 20:02:01 +08:00
};
2017-05-22 14:44:58 +08:00
2017-11-21 19:51:31 +08:00
handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
2017-05-22 14:44:58 +08:00
const { onPressEnter, onKeyDown } = this.props;
if (e.keyCode === 13 && onPressEnter) {
onPressEnter(e);
}
if (onKeyDown) {
onKeyDown(e);
}
2018-12-07 20:02:01 +08:00
};
2017-05-22 14:44:58 +08:00
2019-08-05 18:38:10 +08:00
resizeOnNextFrame = () => {
raf.cancel(this.nextFrameActionId);
this.nextFrameActionId = raf(this.resizeTextarea);
};
resizeTextarea = () => {
2019-10-11 18:12:28 +08:00
const autoSize = this.props.autoSize || this.props.autosize;
if (!autoSize || !this.textAreaRef) {
2019-08-05 18:38:10 +08:00
return;
}
2019-10-11 18:12:28 +08:00
const { minRows, maxRows } = autoSize as AutoSizeType;
2019-08-05 18:38:10 +08:00
const textareaStyles = calculateNodeHeight(this.textAreaRef, false, minRows, maxRows);
this.setState({ textareaStyles, resizing: true }, () => {
raf.cancel(this.resizeFrameId);
this.resizeFrameId = raf(() => {
this.setState({ resizing: false });
});
});
2018-12-07 20:02:01 +08:00
};
2017-05-22 14:44:58 +08:00
2019-08-05 18:38:10 +08:00
focus() {
this.textAreaRef.focus();
}
blur() {
this.textAreaRef.blur();
}
renderTextArea = ({ getPrefixCls }: ConfigConsumerProps) => {
const { textareaStyles, resizing } = this.state;
2019-10-11 18:12:28 +08:00
const { prefixCls: customizePrefixCls, className, disabled, autoSize, autosize } = this.props;
const { ...props } = this.props;
2019-10-11 18:12:28 +08:00
const otherProps = omit(props, ['prefixCls', 'onPressEnter', 'autoSize', 'autosize']);
const prefixCls = getPrefixCls('input', customizePrefixCls);
const cls = classNames(prefixCls, className, {
[`${prefixCls}-disabled`]: disabled,
});
2019-10-11 18:12:28 +08:00
warning(
autosize === undefined,
'Input.TextArea',
'autosize is deprecated, please use autoSize instead.',
);
2017-05-22 14:44:58 +08:00
const style = {
...props.style,
...textareaStyles,
...(resizing ? { overflow: 'hidden' } : null),
2017-05-22 14:44:58 +08:00
};
// Fix https://github.com/ant-design/ant-design/issues/6776
// Make sure it could be reset when using form.getFieldDecorator
if ('value' in otherProps) {
otherProps.value = otherProps.value || '';
}
2017-05-22 14:44:58 +08:00
return (
2019-10-11 18:12:28 +08:00
<ResizeObserver onResize={this.resizeOnNextFrame} disabled={!(autoSize || autosize)}>
New Component: Typography (#14250) * text with prefix * add edit style * support editable * enhance accessibility & type experience * optimize IME case * support copy * add locale * add secondary & disabled * add ellipsis shadow text * split to 3 components * update snapshot * update desc * change lines also need update ellipsis * skip aria when is in ellipsis * add ResizeObserver in _util * update snapshot * move TestBase into test file * update test case * update doc * fix typo * important => level * use rows * update demo cols to 1 * fix cssText not work in firefox * update doc * add miss point * support extendable * update snapshot * fix doc * copyable support string * update snapshot * update doc * update doc desc * adjust style * full test * reset after test * rename * update snapshot * fix compile * adjust style * update desc * update prefixCls * update margin * adjust * nest wrap of tag content * adjust style * update comment * rm % * one more thing * tmp of measure * merge string as children * update snapshot * update testcase * remove comment * use internal variable for configProvider passing * update snapshot * use expandable instead of extendable * less variable it * update demo * update less * adjust code & mark style * remove mark padding * update measure logic * support nest element style * use childNode.textContent to fix react 15 error * update css * popout Typography * add link style * adjust doc * use ellipsis instead of rows & expandable * update doc * update doc * update doc & style * fix typo * add css ellipsis support * client render * update snapshot * enhance copyable * support onExpand * update test case * add test of css ellipsis * fix logic in react 15 * rename onChange -> onSave * use tagName of article * fix lint
2019-02-19 11:42:05 +08:00
<textarea
{...otherProps}
className={cls}
style={style}
onKeyDown={this.handleKeyDown}
onChange={this.handleTextareaChange}
ref={this.saveTextAreaRef}
/>
</ResizeObserver>
2017-05-22 14:44:58 +08:00
);
2018-12-07 20:02:01 +08:00
};
render() {
2018-12-07 20:02:01 +08:00
return <ConfigConsumer>{this.renderTextArea}</ConfigConsumer>;
}
2017-05-22 14:44:58 +08:00
}
polyfill(TextArea);
export default TextArea;