import * as React from 'react'; import RcTextArea, { TextAreaProps as RcTextAreaProps, ResizableTextArea } from 'rc-textarea'; import omit from 'omit.js'; import classNames from 'classnames'; import ClearableLabeledInput from './ClearableLabeledInput'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import { fixControlledValue, resolveOnChange } from './Input'; import SizeContext, { SizeType } from '../config-provider/SizeContext'; export interface TextAreaProps extends RcTextAreaProps { allowClear?: boolean; bordered?: boolean; showCount?: boolean; maxLength?: number; size?: SizeType; } export interface TextAreaState { value: any; /** `value` from prev props */ prevValue: any; } class TextArea extends React.Component { resizableTextArea: ResizableTextArea; clearableInput: ClearableLabeledInput; constructor(props: TextAreaProps) { super(props); const value = typeof props.value === 'undefined' ? props.defaultValue : props.value; this.state = { value, // eslint-disable-next-line react/no-unused-state prevValue: props.value, }; } static getDerivedStateFromProps(nextProps: TextAreaProps, { prevValue }: TextAreaState) { const newState: Partial = { prevValue: nextProps.value }; if (nextProps.value !== undefined || prevValue !== nextProps.value) { newState.value = nextProps.value; } return newState; } setValue(value: string, callback?: () => void) { if (this.props.value === undefined) { this.setState({ value }, callback); } } focus = () => { this.resizableTextArea.textArea.focus(); }; blur() { this.resizableTextArea.textArea.blur(); } setSelectionRange(start: number, end: number, direction?: 'forward' | 'backward' | 'none') { this.resizableTextArea.textArea.setSelectionRange(start, end, direction); } saveTextArea = (textarea: RcTextArea) => { this.resizableTextArea = textarea?.resizableTextArea; }; saveClearableInput = (clearableInput: ClearableLabeledInput) => { this.clearableInput = clearableInput; }; handleChange = (e: React.ChangeEvent) => { this.setValue(e.target.value); resolveOnChange(this.resizableTextArea.textArea, e, this.props.onChange); }; handleReset = (e: React.MouseEvent) => { this.setValue('', () => { this.focus(); }); resolveOnChange(this.resizableTextArea.textArea, e, this.props.onChange); }; renderTextArea = (prefixCls: string, bordered: boolean, size?: SizeType) => { const { showCount, className, style, size: customizeSize } = this.props; return ( ); }; renderComponent = ({ getPrefixCls, direction }: ConfigConsumerProps) => { let value = fixControlledValue(this.state?.value); const { prefixCls: customizePrefixCls, bordered = true, showCount = false, maxLength, className, style, } = this.props; const prefixCls = getPrefixCls('input', customizePrefixCls); // Max length value const hasMaxLength = Number(maxLength) > 0; value = hasMaxLength ? value.slice(0, maxLength) : value; // TextArea const textareaNode = (size?: SizeType) => ( ); // Only show text area wrapper when needed if (showCount) { const valueLength = [...value].length; const dataCount = `${valueLength}${hasMaxLength ? ` / ${maxLength}` : ''}`; return ( {(size?: SizeType) => (
{textareaNode(size)}
)}
); } return {textareaNode}; }; render() { return {this.renderComponent}; } } export default TextArea;