UNPKG

@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
"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;