@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.
502 lines (501 loc) • 17.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.Input = void 0;
var _isUndefined2 = _interopRequireDefault(require("lodash/isUndefined"));
var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
var _noop2 = _interopRequireDefault(require("lodash/noop"));
var _isString2 = _interopRequireDefault(require("lodash/isString"));
var _react = _interopRequireDefault(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _foundation = _interopRequireDefault(require("@douyinfe/semi-foundation/lib/cjs/input/foundation"));
var _constants = require("@douyinfe/semi-foundation/lib/cjs/input/constants");
var _utils = require("../_utils");
var _baseComponent = _interopRequireDefault(require("../_base/baseComponent"));
require("@douyinfe/semi-foundation/lib/cjs/input/input.css");
var _semiIcons = require("@douyinfe/semi-icons");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
var __rest = void 0 && (void 0).__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;
};
const prefixCls = _constants.cssClasses.PREFIX;
const sizeSet = _constants.strings.SIZE;
const statusSet = _constants.strings.STATUS;
const modeSet = _constants.strings.MODE;
class Input extends _baseComponent.default {
constructor(props) {
super(props);
this.handleClear = e => {
this.foundation.handleClear(e);
};
this.handleClick = e => {
this.foundation.handleClick(e);
};
this.handleMouseOver = e => {
this.setState({
isHovering: true
});
};
this.handleMouseLeave = e => {
this.setState({
isHovering: false
});
};
this.handleModeChange = mode => {
this.foundation.handleModeChange(mode);
};
this.handleClickEye = e => {
this.foundation.handleClickEye(e);
};
this.handleMouseDown = e => {
this.foundation.handleMouseDown(e);
};
this.handleMouseUp = e => {
this.foundation.handleMouseUp(e);
};
this.handleModeEnterPress = e => {
this.foundation.handleModeEnterPress(e);
};
this.handleClickPrefixOrSuffix = e => {
this.foundation.handleClickPrefixOrSuffix(e);
};
this.handlePreventMouseDown = e => {
this.foundation.handlePreventMouseDown(e);
};
const initValue = 'value' in props ? props.value : props.defaultValue;
this.state = {
value: initValue,
cachedValue: props.value,
disabled: false,
props: {},
isFocus: false,
isHovering: false,
eyeClosed: props.mode === 'password',
minLength: props.minLength
};
this.inputRef = /*#__PURE__*/_react.default.createRef();
this.prefixRef = /*#__PURE__*/_react.default.createRef();
this.suffixRef = /*#__PURE__*/_react.default.createRef();
this.foundation = new _foundation.default(this.adapter);
}
get adapter() {
return Object.assign(Object.assign({}, super.adapter), {
setValue: value => this.setState({
value
}),
setEyeClosed: value => this.setState({
eyeClosed: value
}),
toggleFocusing: isFocus => {
this.setState({
isFocus
});
},
focusInput: () => {
const {
preventScroll
} = this.props;
const input = this.inputRef && this.inputRef.current;
input && input.focus({
preventScroll
});
},
toggleHovering: isHovering => this.setState({
isHovering
}),
getIfFocusing: () => this.state.isFocus,
notifyChange: (cbValue, e) => this.props.onChange(cbValue, e),
notifyBlur: (val, e) => this.props.onBlur(e),
notifyFocus: (val, e) => this.props.onFocus(e),
notifyInput: e => this.props.onInput(e),
notifyKeyPress: e => this.props.onKeyPress(e),
notifyKeyDown: e => this.props.onKeyDown(e),
notifyKeyUp: e => this.props.onKeyUp(e),
notifyEnterPress: e => this.props.onEnterPress(e),
notifyClear: e => this.props.onClear(e),
setMinLength: minLength => this.setState({
minLength
}),
isEventTarget: e => e && e.target === e.currentTarget
});
}
static getDerivedStateFromProps(props, state) {
const willUpdateStates = {};
if (props.value !== state.cachedValue) {
willUpdateStates.value = props.value;
willUpdateStates.cachedValue = props.value;
}
return willUpdateStates;
}
componentDidUpdate(prevProps) {
const {
mode
} = this.props;
if (prevProps.mode !== mode) {
this.handleModeChange(mode);
}
}
componentDidMount() {
// autofocus is changed from the original support of input to the support of manually calling the focus method,
// so that preventScroll can still take effect under the setting of autofocus
const {
disabled,
autoFocus,
preventScroll
} = this.props;
if (!disabled && (autoFocus || this.props['autofocus'])) {
this.inputRef.current.focus({
preventScroll
});
}
}
renderPrepend() {
const {
addonBefore
} = this.props;
if (addonBefore) {
const prefixWrapperCls = (0, _classnames.default)({
[`${prefixCls}-prepend`]: true,
[`${prefixCls}-prepend-text`]: addonBefore && (0, _isString2.default)(addonBefore),
[`${prefixCls}-prepend-icon`]: (0, _utils.isSemiIcon)(addonBefore)
});
return /*#__PURE__*/_react.default.createElement("div", {
className: prefixWrapperCls,
"x-semi-prop": "addonBefore"
}, addonBefore);
}
return null;
}
renderAppend() {
const {
addonAfter
} = this.props;
if (addonAfter) {
const prefixWrapperCls = (0, _classnames.default)({
[`${prefixCls}-append`]: true,
[`${prefixCls}-append-text`]: addonAfter && (0, _isString2.default)(addonAfter),
[`${prefixCls}-append-icon`]: (0, _utils.isSemiIcon)(addonAfter)
});
return /*#__PURE__*/_react.default.createElement("div", {
className: prefixWrapperCls,
"x-semi-prop": "addonAfter"
}, addonAfter);
}
return null;
}
renderClearBtn() {
const clearCls = (0, _classnames.default)(`${prefixCls}-clearbtn`);
const {
clearIcon
} = this.props;
const allowClear = this.foundation.isAllowClear();
// use onMouseDown to fix issue 1203
if (allowClear) {
return (
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
_react.default.createElement("div", {
className: clearCls,
onMouseDown: this.handleClear
}, clearIcon ? clearIcon : /*#__PURE__*/_react.default.createElement(_semiIcons.IconClear, null))
);
}
return null;
}
renderModeBtn() {
const {
eyeClosed
} = this.state;
const {
mode,
disabled
} = this.props;
const modeCls = (0, _classnames.default)(`${prefixCls}-modebtn`);
const modeIcon = eyeClosed ? /*#__PURE__*/_react.default.createElement(_semiIcons.IconEyeClosedSolid, null) : /*#__PURE__*/_react.default.createElement(_semiIcons.IconEyeOpened, null);
// alway show password button for a11y
const showModeBtn = mode === 'password' && !disabled;
const ariaLabel = eyeClosed ? 'Show password' : 'Hidden password';
if (showModeBtn) {
return /*#__PURE__*/_react.default.createElement("div", {
role: "button",
tabIndex: 0,
"aria-label": ariaLabel,
className: modeCls,
onClick: this.handleClickEye,
onMouseDown: this.handleMouseDown,
onMouseUp: this.handleMouseUp,
onKeyPress: this.handleModeEnterPress
}, modeIcon);
}
return null;
}
renderPrefix() {
const {
prefix,
insetLabel,
insetLabelId
} = this.props;
const labelNode = prefix || insetLabel;
if (!labelNode) {
return null;
}
const prefixWrapperCls = (0, _classnames.default)({
[`${prefixCls}-prefix`]: true,
[`${prefixCls}-inset-label`]: insetLabel,
[`${prefixCls}-prefix-text`]: labelNode && (0, _isString2.default)(labelNode),
[`${prefixCls}-prefix-icon`]: (0, _utils.isSemiIcon)(labelNode)
});
return (
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
_react.default.createElement("div", {
className: prefixWrapperCls,
onMouseDown: this.handlePreventMouseDown,
onClick: this.handleClickPrefixOrSuffix,
id: insetLabelId,
"x-semi-prop": "prefix,insetLabel"
}, labelNode)
);
}
renderSuffix(suffixAllowClear) {
const {
suffix,
hideSuffix
} = this.props;
if (!suffix) {
return null;
}
const suffixWrapperCls = (0, _classnames.default)({
[`${prefixCls}-suffix`]: true,
[`${prefixCls}-suffix-text`]: suffix && (0, _isString2.default)(suffix),
[`${prefixCls}-suffix-icon`]: (0, _utils.isSemiIcon)(suffix),
[`${prefixCls}-suffix-hidden`]: suffixAllowClear && Boolean(hideSuffix)
});
return (
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
_react.default.createElement("div", {
className: suffixWrapperCls,
onMouseDown: this.handlePreventMouseDown,
onClick: this.handleClickPrefixOrSuffix,
"x-semi-prop": "suffix"
}, suffix)
);
}
getInputRef() {
const {
forwardRef
} = this.props;
if (!(0, _isUndefined2.default)(forwardRef)) {
if (typeof forwardRef === 'function') {
return node => {
forwardRef(node);
this.inputRef = {
current: node
};
};
} else if (Object.prototype.toString.call(forwardRef) === '[object Object]') {
this.inputRef = forwardRef;
return forwardRef;
}
}
return this.inputRef;
}
render() {
const _a = this.props,
{
addonAfter,
addonBefore,
autoFocus,
clearIcon,
className,
disabled,
defaultValue,
placeholder,
prefix,
mode,
insetLabel,
insetLabelId,
validateStatus,
type,
readonly,
size,
suffix,
style,
showClear,
onEnterPress,
onClear,
hideSuffix,
inputStyle,
forwardRef,
maxLength,
getValueLength,
preventScroll,
borderless,
showClearIgnoreDisabled,
onlyBorder
} = _a,
rest = __rest(_a, ["addonAfter", "addonBefore", "autoFocus", "clearIcon", "className", "disabled", "defaultValue", "placeholder", "prefix", "mode", "insetLabel", "insetLabelId", "validateStatus", "type", "readonly", "size", "suffix", "style", "showClear", "onEnterPress", "onClear", "hideSuffix", "inputStyle", "forwardRef", "maxLength", "getValueLength", "preventScroll", "borderless", "showClearIgnoreDisabled", "onlyBorder"]);
const {
value,
isFocus,
minLength: stateMinLength
} = this.state;
const suffixAllowClear = this.foundation.isAllowClear();
const suffixIsIcon = (0, _utils.isSemiIcon)(suffix);
const ref = this.getInputRef();
const wrapperPrefix = `${prefixCls}-wrapper`;
const wrapperCls = (0, _classnames.default)(wrapperPrefix, className, {
[`${prefixCls}-wrapper__with-prefix`]: prefix || insetLabel,
[`${prefixCls}-wrapper__with-suffix`]: suffix,
[`${prefixCls}-wrapper__with-suffix-hidden`]: suffixAllowClear && Boolean(hideSuffix),
[`${prefixCls}-wrapper__with-suffix-icon`]: suffixIsIcon,
[`${prefixCls}-wrapper__with-append`]: addonBefore,
[`${prefixCls}-wrapper__with-prepend`]: addonAfter,
[`${prefixCls}-wrapper__with-append-only`]: addonBefore && !addonAfter,
[`${prefixCls}-wrapper__with-prepend-only`]: !addonBefore && addonAfter,
[`${wrapperPrefix}-readonly`]: readonly,
[`${wrapperPrefix}-disabled`]: disabled,
[`${wrapperPrefix}-warning`]: validateStatus === 'warning',
[`${wrapperPrefix}-error`]: validateStatus === 'error',
[`${wrapperPrefix}-focus`]: isFocus,
[`${wrapperPrefix}-clearable`]: showClear,
[`${wrapperPrefix}-modebtn`]: mode === 'password',
[`${wrapperPrefix}-hidden`]: type === 'hidden',
[`${wrapperPrefix}-${size}`]: size,
[`${prefixCls}-borderless`]: borderless,
[`${prefixCls}-only_border`]: onlyBorder !== undefined && onlyBorder !== null
});
const inputCls = (0, _classnames.default)(prefixCls, {
[`${prefixCls}-${size}`]: size,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-sibling-clearbtn`]: this.foundation.isAllowClear(),
[`${prefixCls}-sibling-modebtn`]: mode === 'password'
});
const inputValue = value === null || value === undefined ? '' : value;
const inputProps = Object.assign(Object.assign({}, rest), {
style: inputStyle,
className: inputCls,
disabled,
readOnly: readonly,
type: this.foundation.handleInputType(type),
placeholder: placeholder,
onInput: e => this.foundation.handleInput(e),
onChange: e => this.foundation.handleChange(e.target.value, e),
onFocus: e => this.foundation.handleFocus(e),
onBlur: e => this.foundation.handleBlur(e),
onKeyUp: e => this.foundation.handleKeyUp(e),
onKeyDown: e => this.foundation.handleKeyDown(e),
onKeyPress: e => this.foundation.handleKeyPress(e),
onCompositionStart: this.foundation.handleCompositionStart,
onCompositionEnd: this.foundation.handleCompositionEnd,
value: inputValue
});
if (!(0, _isFunction2.default)(getValueLength)) {
inputProps.maxLength = maxLength;
}
if (stateMinLength) {
inputProps.minLength = stateMinLength;
}
if (validateStatus === 'error') {
inputProps['aria-invalid'] = 'true';
}
let wrapperStyle = Object.assign({}, style);
if (onlyBorder !== undefined) {
wrapperStyle = Object.assign({
borderWidth: onlyBorder
}, style);
}
return (
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
_react.default.createElement("div", {
className: wrapperCls,
style: wrapperStyle,
onMouseEnter: e => this.handleMouseOver(e),
onMouseLeave: e => this.handleMouseLeave(e),
onClick: e => this.handleClick(e)
}, this.renderPrepend(), this.renderPrefix(), /*#__PURE__*/_react.default.createElement("input", Object.assign({}, inputProps, {
ref: ref
})), this.renderClearBtn(), this.renderSuffix(suffixAllowClear), this.renderModeBtn(), this.renderAppend())
);
}
}
exports.Input = Input;
Input.propTypes = {
'aria-label': _propTypes.default.string,
'aria-labelledby': _propTypes.default.string,
'aria-invalid': _propTypes.default.bool,
'aria-errormessage': _propTypes.default.string,
'aria-describedby': _propTypes.default.string,
'aria-required': _propTypes.default.bool,
addonBefore: _propTypes.default.node,
addonAfter: _propTypes.default.node,
clearIcon: _propTypes.default.node,
prefix: _propTypes.default.node,
suffix: _propTypes.default.node,
mode: _propTypes.default.oneOf(modeSet),
value: _propTypes.default.any,
defaultValue: _propTypes.default.any,
disabled: _propTypes.default.bool,
readonly: _propTypes.default.bool,
autoFocus: _propTypes.default.bool,
type: _propTypes.default.string,
showClear: _propTypes.default.bool,
hideSuffix: _propTypes.default.bool,
placeholder: _propTypes.default.any,
size: _propTypes.default.oneOf(sizeSet),
className: _propTypes.default.string,
style: _propTypes.default.object,
validateStatus: _propTypes.default.oneOf(statusSet),
onClear: _propTypes.default.func,
onChange: _propTypes.default.func,
onBlur: _propTypes.default.func,
onFocus: _propTypes.default.func,
onInput: _propTypes.default.func,
onKeyDown: _propTypes.default.func,
onKeyUp: _propTypes.default.func,
onKeyPress: _propTypes.default.func,
onEnterPress: _propTypes.default.func,
insetLabel: _propTypes.default.node,
insetLabelId: _propTypes.default.string,
inputStyle: _propTypes.default.object,
getValueLength: _propTypes.default.func,
preventScroll: _propTypes.default.bool,
borderless: _propTypes.default.bool
};
Input.defaultProps = {
addonBefore: '',
addonAfter: '',
prefix: '',
suffix: '',
readonly: false,
type: 'text',
showClear: false,
hideSuffix: false,
placeholder: '',
size: 'default',
className: '',
onClear: _noop2.default,
onChange: _noop2.default,
onBlur: _noop2.default,
onFocus: _noop2.default,
onInput: _noop2.default,
onKeyDown: _noop2.default,
onKeyUp: _noop2.default,
onKeyPress: _noop2.default,
onEnterPress: _noop2.default,
validateStatus: 'default',
borderless: false
};
const ForwardInput = /*#__PURE__*/_react.default.forwardRef((props, ref) => /*#__PURE__*/_react.default.createElement(Input, Object.assign({}, props, {
forwardRef: ref
})));
var _default = exports.default = ForwardInput;