@douyinfe/semi-ui
Version:
A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.
280 lines • 9.75 kB
JavaScript
import _throttle from "lodash/throttle";
import _isObject from "lodash/isObject";
import _isUndefined from "lodash/isUndefined";
import _isFunction from "lodash/isFunction";
import _omit from "lodash/omit";
import _noop from "lodash/noop";
var __rest = this && this.__rest || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
}
return t;
};
import React from 'react';
import cls from 'classnames';
import PropTypes from 'prop-types';
import TextAreaFoundation from '@douyinfe/semi-foundation/lib/es/input/textareaFoundation';
import { cssClasses } from '@douyinfe/semi-foundation/lib/es/input/constants';
import BaseComponent from '../_base/baseComponent';
import '@douyinfe/semi-foundation/lib/es/input/textarea.css';
import { IconClear } from '@douyinfe/semi-icons';
import ResizeObserver from '../resizeObserver';
const prefixCls = cssClasses.PREFIX;
class TextArea extends BaseComponent {
constructor(props) {
super(props);
this.handleClear = e => {
this.foundation.handleClear(e);
};
this.setRef = node => {
this.libRef.current = node;
const {
forwardRef
} = this.props;
if (typeof forwardRef === 'function') {
forwardRef(node);
} else if (forwardRef && typeof forwardRef === 'object') {
forwardRef.current = node;
}
};
const initValue = 'value' in props ? props.value : props.defaultValue;
this.state = {
value: initValue,
isFocus: false,
isHover: false,
height: 0,
minLength: props.minLength,
cachedValue: props.value
};
this.focusing = false;
this.foundation = new TextAreaFoundation(this.adapter);
this.libRef = /*#__PURE__*/React.createRef();
this.throttledResizeTextarea = _throttle(this.foundation.resizeTextarea, 10);
}
get adapter() {
return Object.assign(Object.assign({}, super.adapter), {
setValue: value => this.setState({
value
}, () => {
if (this.props.autosize) {
this.foundation.resizeTextarea();
}
}),
getRef: () => this.libRef.current,
toggleFocusing: focusing => this.setState({
isFocus: focusing
}),
toggleHovering: hovering => this.setState({
isHover: hovering
}),
notifyChange: (val, e) => {
this.props.onChange(val, e);
},
notifyClear: e => this.props.onClear(e),
notifyBlur: (val, e) => this.props.onBlur(e),
notifyFocus: (val, e) => this.props.onFocus(e),
notifyKeyDown: e => {
this.props.onKeyDown(e);
},
notifyHeightUpdate: height => {
this.setState({
height
});
this.props.onResize({
height
});
},
notifyPressEnter: e => {
this.props.onEnterPress && this.props.onEnterPress(e);
},
setMinLength: minLength => this.setState({
minLength
})
});
}
static getDerivedStateFromProps(props, state) {
const willUpdateStates = {};
if (props.value !== state.cachedValue) {
willUpdateStates.value = props.value;
willUpdateStates.cachedValue = props.value;
}
return willUpdateStates;
}
componentWillUnmount() {
var _a, _b;
if (this.throttledResizeTextarea) {
(_b = (_a = this.throttledResizeTextarea) === null || _a === void 0 ? void 0 : _a.cancel) === null || _b === void 0 ? void 0 : _b.call(_a);
this.throttledResizeTextarea = null;
}
}
componentDidUpdate(prevProps, prevState) {
if ((this.props.value !== prevProps.value || this.props.placeholder !== prevProps.placeholder) && this.props.autosize) {
this.foundation.resizeTextarea();
}
}
renderClearBtn() {
const {
showClear
} = this.props;
const displayClearBtn = this.foundation.isAllowClear();
const clearCls = cls(`${prefixCls}-clearbtn`, {
[`${prefixCls}-clearbtn-hidden`]: !displayClearBtn
});
if (showClear) {
return (
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
React.createElement("div", {
className: clearCls,
onClick: this.handleClear
}, /*#__PURE__*/React.createElement(IconClear, null))
);
}
return null;
}
renderCounter() {
let counter, current, total, countCls;
const {
showCounter,
maxCount,
getValueLength
} = this.props;
if (showCounter || maxCount) {
const {
value
} = this.state;
// eslint-disable-next-line no-nested-ternary
current = value ? _isFunction(getValueLength) ? getValueLength(value) : value.length : 0;
total = maxCount || null;
countCls = cls(`${prefixCls}-textarea-counter`, {
[`${prefixCls}-textarea-counter-exceed`]: current > total
});
counter = /*#__PURE__*/React.createElement("div", {
className: countCls
}, current, total ? '/' : null, total);
} else {
counter = null;
}
return counter;
}
render() {
const _a = this.props,
{
autosize,
placeholder,
onEnterPress,
onResize,
// resize,
disabled,
readonly,
className,
showCounter,
validateStatus,
maxCount,
defaultValue,
style,
forwardRef,
getValueLength,
maxLength,
minLength,
showClear,
borderless,
autoFocus
} = _a,
rest = __rest(_a, ["autosize", "placeholder", "onEnterPress", "onResize", "disabled", "readonly", "className", "showCounter", "validateStatus", "maxCount", "defaultValue", "style", "forwardRef", "getValueLength", "maxLength", "minLength", "showClear", "borderless", "autoFocus"]);
const {
isFocus,
value,
minLength: stateMinLength
} = this.state;
const wrapperCls = cls(className, `${prefixCls}-textarea-wrapper`, {
[`${prefixCls}-textarea-borderless`]: borderless,
[`${prefixCls}-textarea-wrapper-disabled`]: disabled,
[`${prefixCls}-textarea-wrapper-readonly`]: readonly,
[`${prefixCls}-textarea-wrapper-${validateStatus}`]: Boolean(validateStatus),
[`${prefixCls}-textarea-wrapper-focus`]: isFocus
// [`${prefixCls}-textarea-wrapper-resize`]: !autosize && resize,
});
// const ref = this.props.forwardRef || this.textAreaRef;
const itemCls = cls(`${prefixCls}-textarea`, {
[`${prefixCls}-textarea-disabled`]: disabled,
[`${prefixCls}-textarea-readonly`]: readonly,
[`${prefixCls}-textarea-autosize`]: _isObject(autosize) ? _isUndefined(autosize === null || autosize === void 0 ? void 0 : autosize.maxRows) : autosize,
[`${prefixCls}-textarea-showClear`]: showClear
});
const itemProps = Object.assign(Object.assign({}, _omit(rest, 'insetLabel', 'insetLabelId', 'getValueLength', 'onClear', 'showClear', 'disabledEnterStartNewLine')), {
autoFocus: autoFocus || this.props['autofocus'],
className: itemCls,
disabled,
readOnly: readonly,
placeholder: !placeholder ? null : placeholder,
onChange: e => this.foundation.handleChange(e.target.value, e),
onFocus: e => this.foundation.handleFocus(e),
onBlur: e => this.foundation.handleBlur(e.nativeEvent),
onKeyDown: e => this.foundation.handleKeyDown(e),
value: value === null || value === undefined ? '' : value,
onCompositionStart: this.foundation.handleCompositionStart,
onCompositionEnd: this.foundation.handleCompositionEnd
});
if (!_isFunction(getValueLength)) {
itemProps.maxLength = maxLength;
}
if (stateMinLength) {
itemProps.minLength = stateMinLength;
}
return /*#__PURE__*/React.createElement("div", {
className: wrapperCls,
style: style,
onMouseEnter: e => this.foundation.handleMouseEnter(e),
onMouseLeave: e => this.foundation.handleMouseLeave(e)
}, autosize ? (/*#__PURE__*/React.createElement(ResizeObserver, {
onResize: this.throttledResizeTextarea
}, /*#__PURE__*/React.createElement("textarea", Object.assign({}, itemProps, {
ref: this.setRef
})))) : (/*#__PURE__*/React.createElement("textarea", Object.assign({}, itemProps, {
ref: this.setRef
}))), this.renderClearBtn(), this.renderCounter());
}
}
TextArea.propTypes = {
autosize: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
borderless: PropTypes.bool,
placeholder: PropTypes.string,
value: PropTypes.string,
rows: PropTypes.number,
cols: PropTypes.number,
maxCount: PropTypes.number,
onEnterPress: PropTypes.func,
validateStatus: PropTypes.string,
className: PropTypes.string,
style: PropTypes.object,
showClear: PropTypes.bool,
onClear: PropTypes.func,
onResize: PropTypes.func,
getValueLength: PropTypes.func,
disabledEnterStartNewLine: PropTypes.bool
// TODO
// resize: PropTypes.bool,
};
TextArea.defaultProps = {
autosize: false,
borderless: false,
rows: 4,
cols: 20,
showCounter: false,
showClear: false,
onEnterPress: _noop,
onChange: _noop,
onBlur: _noop,
onFocus: _noop,
onKeyDown: _noop,
onResize: _noop,
onClear: _noop
// resize: false,
};
const ForwardTextarea = /*#__PURE__*/React.forwardRef((props, ref) => (/*#__PURE__*/React.createElement(TextArea, Object.assign({}, props, {
forwardRef: ref
}))));
export default ForwardTextarea;