UNPKG

14.4 kBJavaScriptView Raw
1import _extends from 'babel-runtime/helpers/extends';
2import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
3import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
4import _inherits from 'babel-runtime/helpers/inherits';
5
6var _class, _temp;
7
8import React, { isValidElement, cloneElement } from 'react';
9import PropTypes from 'prop-types';
10import classNames from 'classnames';
11import Icon from '../icon';
12import { obj, func } from '../util';
13import Base from './base';
14import Group from './group';
15
16// preventDefault here can stop onBlur to keep focus state
17function preventDefault(e) {
18 e.preventDefault();
19}
20
21/** Input */
22var Input = (_temp = _class = function (_Base) {
23 _inherits(Input, _Base);
24
25 function Input(props) {
26 _classCallCheck(this, Input);
27
28 var _this = _possibleConstructorReturn(this, _Base.call(this, props));
29
30 _this.handleKeyDown = function (e) {
31 if (e.keyCode === 13) {
32 _this.props.onPressEnter(e);
33 }
34
35 _this.onKeyDown(e);
36 };
37
38 _this.handleKeyDownFromClear = function (e) {
39 if (e.keyCode === 13) {
40 _this.onClear(e);
41 }
42 };
43
44 var value = void 0;
45 if ('value' in props) {
46 value = props.value;
47 } else {
48 value = props.defaultValue;
49 }
50
51 _this.state = {
52 value: typeof value === 'undefined' ? '' : value
53 };
54 return _this;
55 }
56
57 // `Enter` was considered to be two chars in chrome , but one char in ie.
58 // so we make all `Enter` to be two chars
59
60
61 Input.prototype.getValueLength = function getValueLength(value) {
62 var nv = '' + value;
63 var strLen = this.props.getValueLength(nv);
64 if (typeof strLen !== 'number') {
65 strLen = nv.length;
66 }
67
68 return strLen;
69 };
70
71 Input.prototype.renderControl = function renderControl() {
72 var _this2 = this;
73
74 var _props = this.props,
75 hasClear = _props.hasClear,
76 readOnly = _props.readOnly,
77 state = _props.state,
78 prefix = _props.prefix,
79 hint = _props.hint,
80 extra = _props.extra,
81 locale = _props.locale,
82 disabled = _props.disabled,
83 hoverShowClear = _props.hoverShowClear;
84
85
86 var lenWrap = this.renderLength();
87
88 var stateWrap = null;
89 if (state === 'success') {
90 stateWrap = React.createElement(Icon, { type: 'success-filling', className: prefix + 'input-success-icon' });
91 } else if (state === 'loading') {
92 stateWrap = React.createElement(Icon, { type: 'loading', className: prefix + 'input-loading-icon' });
93 } else if (state === 'warning') {
94 stateWrap = React.createElement(Icon, { type: 'warning', className: prefix + 'input-warning-icon' });
95 }
96
97 var clearWrap = null;
98 // showClear属性应该与disable属性为互斥状态
99 var showClear = hasClear && !readOnly && !!('' + this.state.value) && !disabled;
100
101 if (hint || showClear) {
102 var hintIcon = null;
103 if (hint) {
104 if (typeof hint === 'string') {
105 hintIcon = React.createElement(Icon, { type: hint, className: prefix + 'input-hint' });
106 } else if (isValidElement(hint)) {
107 hintIcon = cloneElement(hint, {
108 className: classNames(hint.props.className, prefix + 'input-hint')
109 });
110 } else {
111 hintIcon = hint;
112 }
113 } else {
114 var _classNames;
115
116 var cls = classNames((_classNames = {}, _classNames[prefix + 'input-hint'] = true, _classNames[prefix + 'input-clear-icon'] = true, _classNames[prefix + 'input-hover-show'] = hoverShowClear, _classNames));
117 hintIcon = React.createElement(Icon, {
118 type: 'delete-filling',
119 role: 'button',
120 tabIndex: '0',
121 className: cls,
122 'aria-label': locale.clear,
123 onClick: this.onClear.bind(this),
124 onMouseDown: preventDefault,
125 onKeyDown: this.handleKeyDownFromClear
126 });
127 }
128
129 clearWrap = React.createElement(
130 'span',
131 { className: prefix + 'input-hint-wrap' },
132 hasClear && hint ? React.createElement(Icon, {
133 type: 'delete-filling',
134 role: 'button',
135 tabIndex: '0',
136 className: prefix + 'input-clear ' + prefix + 'input-clear-icon',
137 'aria-label': locale.clear,
138 onClick: this.onClear.bind(this),
139 onMouseDown: preventDefault,
140 onKeyDown: this.handleKeyDownFromClear
141 }) : null,
142 hintIcon
143 );
144 }
145
146 if (state === 'loading') {
147 clearWrap = null;
148 }
149
150 return clearWrap || lenWrap || stateWrap || extra ? React.createElement(
151 'span',
152 { onClick: function onClick() {
153 return _this2.focus();
154 }, className: prefix + 'input-control' },
155 clearWrap,
156 lenWrap,
157 stateWrap,
158 extra
159 ) : null;
160 };
161
162 Input.prototype.renderLabel = function renderLabel() {
163 var _props2 = this.props,
164 label = _props2.label,
165 prefix = _props2.prefix,
166 id = _props2.id;
167
168 return label ? React.createElement(
169 'label',
170 { className: prefix + 'input-label', htmlFor: id },
171 label
172 ) : null;
173 };
174
175 Input.prototype.renderInner = function renderInner(inner, cls) {
176 return inner ? React.createElement(
177 'span',
178 { className: cls },
179 inner
180 ) : null;
181 };
182
183 Input.prototype.onClear = function onClear(e) {
184 if (this.props.disabled) {
185 return;
186 }
187
188 // 非受控模式清空内部数据
189 if (!('value' in this.props)) {
190 this.setState({
191 value: ''
192 });
193 }
194 this.props.onChange('', e, 'clear');
195 this.focus();
196 };
197
198 Input.prototype.render = function render() {
199 var _classNames2, _classNames3, _classNames4, _classNames5, _classNames6, _classNames7, _classNames8;
200
201 var _props3 = this.props,
202 size = _props3.size,
203 htmlType = _props3.htmlType,
204 htmlSize = _props3.htmlSize,
205 autoComplete = _props3.autoComplete,
206 autoFocus = _props3.autoFocus,
207 disabled = _props3.disabled,
208 style = _props3.style,
209 innerBefore = _props3.innerBefore,
210 innerAfter = _props3.innerAfter,
211 innerBeforeClassName = _props3.innerBeforeClassName,
212 innerAfterClassName = _props3.innerAfterClassName,
213 className = _props3.className,
214 hasBorder = _props3.hasBorder,
215 prefix = _props3.prefix,
216 isPreview = _props3.isPreview,
217 renderPreview = _props3.renderPreview,
218 addonBefore = _props3.addonBefore,
219 addonAfter = _props3.addonAfter,
220 addonTextBefore = _props3.addonTextBefore,
221 addonTextAfter = _props3.addonTextAfter,
222 inputRender = _props3.inputRender,
223 rtl = _props3.rtl,
224 composition = _props3.composition;
225
226
227 var hasAddon = addonBefore || addonAfter || addonTextBefore || addonTextAfter;
228 var cls = classNames(this.getClass(), (_classNames2 = {}, _classNames2['' + prefix + size] = true, _classNames2[prefix + 'hidden'] = this.props.htmlType === 'hidden', _classNames2[prefix + 'noborder'] = !hasBorder || this.props.htmlType === 'file', _classNames2[prefix + 'input-group-auto-width'] = hasAddon, _classNames2[prefix + 'disabled'] = disabled, _classNames2[className] = !!className && !hasAddon, _classNames2));
229
230 var innerCls = prefix + 'input-inner';
231 var innerBeforeCls = classNames((_classNames3 = {}, _classNames3[innerCls] = true, _classNames3[prefix + 'before'] = true, _classNames3[innerBeforeClassName] = innerBeforeClassName, _classNames3));
232 var innerAfterCls = classNames((_classNames4 = {}, _classNames4[innerCls] = true, _classNames4[prefix + 'after'] = true, _classNames4[prefix + 'input-inner-text'] = typeof innerAfter === 'string', _classNames4[innerAfterClassName] = innerAfterClassName, _classNames4));
233 var previewCls = classNames((_classNames5 = {}, _classNames5[prefix + 'form-preview'] = true, _classNames5[className] = !!className, _classNames5));
234
235 var props = this.getProps();
236 // custom data attributes are assigned to the top parent node
237 // data-类自定义数据属性分配到顶层node节点
238 var dataProps = obj.pickAttrsWith(this.props, 'data-');
239 // Custom props are transparently transmitted to the core input node by default
240 // 自定义属性默认透传到核心node节点:input
241 var others = obj.pickOthers(_extends({}, dataProps, Input.propTypes), this.props);
242
243 if (isPreview) {
244 var value = props.value;
245 var label = this.props.label;
246
247 if (typeof renderPreview === 'function') {
248 return React.createElement(
249 'div',
250 _extends({}, others, { className: previewCls }),
251 renderPreview(value, this.props)
252 );
253 }
254 return React.createElement(
255 'div',
256 _extends({}, others, { className: previewCls }),
257 addonBefore || addonTextBefore,
258 label,
259 innerBefore,
260 value,
261 innerAfter,
262 addonAfter || addonTextAfter
263 );
264 }
265
266 var compositionProps = {};
267 if (composition) {
268 compositionProps.onCompositionStart = this.handleCompositionStart;
269 compositionProps.onCompositionEnd = this.handleCompositionEnd;
270 }
271
272 var inputEl = React.createElement('input', _extends({}, others, props, compositionProps, {
273 height: '100%',
274 type: htmlType,
275 size: htmlSize,
276 autoFocus: autoFocus,
277 autoComplete: autoComplete,
278 onKeyDown: this.handleKeyDown,
279 ref: this.saveRef
280 }));
281
282 var inputWrap = React.createElement(
283 'span',
284 _extends({}, dataProps, { dir: rtl ? 'rtl' : undefined, className: cls, style: hasAddon ? undefined : style }),
285 this.renderLabel(),
286 this.renderInner(innerBefore, innerBeforeCls),
287 inputRender(inputEl),
288 this.renderInner(innerAfter, innerAfterCls),
289 this.renderControl()
290 );
291
292 var groupCls = classNames((_classNames6 = {}, _classNames6[prefix + 'input-group-text'] = true, _classNames6['' + prefix + size] = !!size, _classNames6[prefix + 'disabled'] = disabled, _classNames6));
293
294 var addonBeforeCls = classNames((_classNames7 = {}, _classNames7[groupCls] = addonTextBefore, _classNames7));
295 var addonAfterCls = classNames((_classNames8 = {}, _classNames8[groupCls] = addonTextAfter, _classNames8));
296
297 if (hasAddon) {
298 return React.createElement(
299 Group,
300 _extends({}, dataProps, {
301 prefix: prefix,
302 className: className,
303 style: style,
304 disabled: disabled,
305 addonBefore: addonBefore || addonTextBefore,
306 addonBeforeClassName: addonBeforeCls,
307 addonAfter: addonAfter || addonTextAfter,
308 addonAfterClassName: addonAfterCls
309 }),
310 inputWrap
311 );
312 }
313
314 return inputWrap;
315 };
316
317 return Input;
318}(Base), _class.getDerivedStateFromProps = Base.getDerivedStateFromProps, _class.propTypes = _extends({}, Base.propTypes, {
319 /**
320 * label
321 */
322 label: PropTypes.node,
323 /**
324 * 是否出现clear按钮
325 */
326 hasClear: PropTypes.bool,
327 /**
328 * 是否有边框
329 */
330 hasBorder: PropTypes.bool,
331 /**
332 * 状态
333 * @enumdesc 错误, 校验中, 成功, 警告
334 */
335 state: PropTypes.oneOf(['error', 'loading', 'success', 'warning']),
336 /**
337 * 按下回车的回调
338 */
339 onPressEnter: PropTypes.func,
340
341 onClear: PropTypes.func,
342 /**
343 * 原生type
344 */
345 htmlType: PropTypes.string,
346 htmlSize: PropTypes.string,
347 /**
348 * 水印 (Icon的type类型,和hasClear占用一个地方)
349 */
350 hint: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
351 /**
352 * 文字前附加内容
353 */
354 innerBefore: PropTypes.node,
355 /**
356 * 文字后附加内容
357 */
358 innerAfter: PropTypes.node,
359 /**
360 * 输入框前附加内容
361 */
362 addonBefore: PropTypes.node,
363 /**
364 * 输入框后附加内容
365 */
366 addonAfter: PropTypes.node,
367 /**
368 * 输入框前附加文字
369 */
370 addonTextBefore: PropTypes.node,
371 /**
372 * 输入框后附加文字
373 */
374 addonTextAfter: PropTypes.node,
375 /**
376 * (原生input支持)
377 */
378 autoComplete: PropTypes.string,
379 /**
380 * 自动聚焦(原生input支持)
381 */
382 autoFocus: PropTypes.bool,
383 inputRender: PropTypes.func,
384 extra: PropTypes.node,
385 innerBeforeClassName: PropTypes.string,
386 innerAfterClassName: PropTypes.string,
387 /**
388 * 是否为预览态
389 */
390 isPreview: PropTypes.bool,
391 /**
392 * 预览态模式下渲染的内容
393 * @param {number} value 评分值
394 */
395 renderPreview: PropTypes.func,
396 /**
397 * hover展示clear (配合 hasClear=true使用)
398 * @version 1.24
399 */
400 hoverShowClear: PropTypes.bool
401}), _class.defaultProps = _extends({}, Base.defaultProps, {
402 autoComplete: 'off',
403 hasBorder: true,
404 isPreview: false,
405 hoverShowClear: false,
406 onPressEnter: func.noop,
407 inputRender: function inputRender(el) {
408 return el;
409 }
410}), _temp);
411export { Input as default };
\No newline at end of file