Слияние кода завершено, страница обновится автоматически
import React, {
ChangeEvent,
Component,
CSSProperties,
FocusEvent,
KeyboardEvent,
ReactNode,
TextareaHTMLAttributes,
} from 'react';
import { findDOMNode } from 'react-dom';
import omit from 'lodash/omit';
import classNames from 'classnames';
import ResizeObserver from 'resize-observer-polyfill';
import { AbstractInputProps } from './Input';
import calculateNodeHeight from './calculateNodeHeight';
import { InnerRowCtx } from '../rc-components/table/TableRowContext';
import ConfigContext, { ConfigContextValue } from '../config-provider/ConfigContext';
function onNextFrame(cb: () => void) {
if (window.requestAnimationFrame) {
return window.requestAnimationFrame(cb);
}
return window.setTimeout(cb, 1);
}
function clearNextFrameAction(nextFrameId: number) {
if (window.cancelAnimationFrame) {
window.cancelAnimationFrame(nextFrameId);
} else {
window.clearTimeout(nextFrameId);
}
}
export interface AutoSizeType {
minRows?: number;
maxRows?: number;
}
export interface TextAreaProps extends AbstractInputProps<HTMLTextAreaElement> {
autosize?: boolean | AutoSizeType;
autoFocus?: boolean;
border?: boolean;
}
export interface TextAreaState {
textareaStyles?: CSSProperties;
inputLength?: number;
focused?: boolean;
}
export type HTMLTextareaProps = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange' | 'prefix'>;
export default class TextArea extends Component<TextAreaProps & HTMLTextareaProps, TextAreaState> {
static displayName = 'TextArea';
static get contextType(): typeof ConfigContext {
return ConfigContext;
}
static defaultProps = {
showLengthInfo: true,
border: true,
labelLayout: 'float',
};
context: ConfigContextValue;
nextFrameActionId: number;
state = {
textareaStyles: {},
inputLength: 0,
focused: false,
};
private textAreaRef: HTMLTextAreaElement;
private resizeObserver?: ResizeObserver;
componentDidMount() {
this.resizeTextarea();
if (this.textAreaRef.value) {
this.setState({
inputLength: this.textAreaRef.value.length,
});
}
const { autoFocus } = this.props;
if (autoFocus) {
this.setState({
focused: true,
});
}
}
componentWillReceiveProps(nextProps: TextAreaProps) {
// Re-render with the new content then recalculate the height as required.
if (this.textAreaRef.value !== nextProps.value) {
const inputLength = nextProps.value && String(nextProps.value).length;
this.setState({
inputLength: inputLength || 0,
});
}
if (nextProps.autoFocus) {
this.setState({
focused: true,
});
}
const { value } = this.props;
if (value !== nextProps.value) {
if (this.nextFrameActionId) {
clearNextFrameAction(this.nextFrameActionId);
}
this.nextFrameActionId = onNextFrame(this.resizeTextarea);
}
}
componentWillUnmount() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
delete this.resizeObserver;
}
}
focus() {
this.textAreaRef.focus();
}
blur() {
this.textAreaRef.blur();
}
resizeTextarea = () => {
const { autosize } = this.props;
if (!autosize || !this.textAreaRef) {
return;
}
const minRows = autosize ? (autosize as AutoSizeType).minRows : null;
const maxRows = autosize ? (autosize as AutoSizeType).maxRows : null;
const textareaStyles = calculateNodeHeight(this.textAreaRef, false, minRows, maxRows);
this.setState({ textareaStyles });
};
getPrefixCls() {
const { prefixCls } = this.props;
const { getPrefixCls } = this.context;
return getPrefixCls('input', prefixCls);
}
getTextAreaClassName() {
const { className, disabled } = this.props;
const prefixCls = this.getPrefixCls();
return classNames(prefixCls, className, `${prefixCls}-textarea-element`, {
[`${prefixCls}-disabled`]: disabled,
});
}
handleTextareaChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
if (!('value' in this.props)) {
this.resizeTextarea();
}
const { onChange } = this.props;
if (onChange) {
onChange(e);
}
};
handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
const { onPressEnter, onKeyDown } = this.props;
if (e.keyCode === 13 && typeof onPressEnter === 'function') {
onPressEnter(e);
}
if (onKeyDown) {
onKeyDown(e);
}
};
handleInput = () => {
this.setState({
inputLength: this.textAreaRef.value.length,
});
};
saveTextAreaRef = (textArea: HTMLTextAreaElement) => {
this.textAreaRef = textArea;
};
getWrapperClassName() {
const { disabled, label, border, labelLayout } = this.props;
const { inputLength, focused } = this.state;
const prefixCls = this.getPrefixCls();
return classNames(`${prefixCls}-wrapper`, `${prefixCls}-textarea`, {
[`${prefixCls}-has-value`]: inputLength !== 0,
[`${prefixCls}-focused`]: focused,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-has-label`]: !!label,
[`${prefixCls}-has-border`]: border && labelLayout === 'float',
});
}
handleFocus = (e: FocusEvent<HTMLTextAreaElement>) => {
const { onFocus } = this.props;
this.setState({
focused: true,
});
if (onFocus) {
onFocus(e);
}
};
handleBlur = (e: FocusEvent<HTMLTextAreaElement>) => {
const { onBlur } = this.props;
this.setState({
focused: false,
});
if (onBlur) {
onBlur(e);
}
};
getLengthInfo(prefixCls) {
const { maxLength, showLengthInfo } = this.props;
const { inputLength } = this.state;
return showLengthInfo !== 'never' && ((maxLength && showLengthInfo) || (maxLength && maxLength > 0 && inputLength === maxLength)) ? (
<div className={`${prefixCls}-length-info`}>{`${inputLength}/${maxLength}`}</div>
) : null;
}
renderFloatLabel(): ReactNode {
const { label } = this.props;
if (label) {
const prefixCls = this.getPrefixCls();
return (
<div className={`${prefixCls}-label-wrapper`}>
<div className={`${prefixCls}-label`}>{label}</div>
</div>
);
}
}
render() {
const props = this.props;
const state = this.state;
const prefixCls = this.getPrefixCls();
const omits = [
'prefixCls',
'onPressEnter',
'autosize',
'focused',
'showLengthInfo',
'labelLayout',
];
const hasBorder = props.border && props.labelLayout === 'float';
const floatLabel = hasBorder && this.renderFloatLabel();
if (floatLabel && !state.focused) {
omits.push('placeholder');
}
const otherProps: TextAreaProps & HTMLTextareaProps = omit(props, omits);
const style = {
...props.style,
...state.textareaStyles,
};
// Make sure it could be reset when using form.getFieldDecorator
if ('value' in otherProps) {
otherProps.value = otherProps.value || '';
}
otherProps.onInput = this.handleInput;
return (
<InnerRowCtx.Consumer>
{(options) => {
if (options && !this.resizeObserver && this.textAreaRef) {
this.resizeObserver = new ResizeObserver(options.syncRowHeight);
const dom = findDOMNode(this.textAreaRef);
// eslint-disable-next-line no-unused-expressions
dom && this.resizeObserver.observe(dom as Element);
}
const textarea = (
<textarea
{...otherProps}
className={this.getTextAreaClassName()}
style={style}
onKeyDown={this.handleKeyDown}
onChange={this.handleTextareaChange}
ref={this.saveTextAreaRef}
onInput={this.handleInput}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
/>
);
const labeledTextArea = hasBorder ? (
<div className={`${prefixCls}-rendered-wrapper`}>
{textarea}
{floatLabel}
</div>
) : textarea;
const lengthInfo = this.getLengthInfo(prefixCls);
return lengthInfo || hasBorder ? (
<span className={this.getWrapperClassName()}>
{labeledTextArea}
{lengthInfo}
</span>
) : labeledTextArea;
}}
</InnerRowCtx.Consumer>
);
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарий ( 0 )