UNPKG

3.27 kBJavaScriptView Raw
1/* eslint react/prefer-stateless-function: 0 */
2
3import React from 'react';
4import PropTypes from 'prop-types';
5import classNames from 'classnames';
6import { mapToCssModules, warnOnce, tagPropType } from './utils';
7
8const propTypes = {
9 children: PropTypes.node,
10 type: PropTypes.string,
11 size: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
12 bsSize: PropTypes.string,
13 valid: PropTypes.bool,
14 invalid: PropTypes.bool,
15 tag: tagPropType,
16 innerRef: PropTypes.oneOfType([
17 PropTypes.object,
18 PropTypes.func,
19 PropTypes.string,
20 ]),
21 plaintext: PropTypes.bool,
22 addon: PropTypes.bool,
23 className: PropTypes.string,
24 cssModule: PropTypes.object,
25};
26
27class Input extends React.Component {
28 constructor(props) {
29 super(props);
30 this.getRef = this.getRef.bind(this);
31 this.focus = this.focus.bind(this);
32 }
33
34 getRef(ref) {
35 if (this.props.innerRef) {
36 this.props.innerRef(ref);
37 }
38 this.ref = ref;
39 }
40
41 focus() {
42 if (this.ref) {
43 this.ref.focus();
44 }
45 }
46
47 render() {
48 let {
49 className,
50 cssModule,
51 type = 'text',
52 bsSize,
53 valid,
54 invalid,
55 tag,
56 addon,
57 plaintext,
58 innerRef,
59 ...attributes
60 } = this.props;
61
62 const checkInput = ['switch', 'radio', 'checkbox'].indexOf(type) > -1;
63 const isNotaNumber = /\D/g;
64
65 const textareaInput = type === 'textarea';
66 const selectInput = type === 'select';
67 const rangeInput = type === 'range';
68 let Tag = tag || (selectInput || textareaInput ? type : 'input');
69
70 let formControlClass = 'form-control';
71
72 if (plaintext) {
73 formControlClass = `${formControlClass}-plaintext`;
74 Tag = tag || 'input';
75 } else if (rangeInput) {
76 formControlClass = 'form-range';
77 } else if (selectInput) {
78 formControlClass = 'form-select';
79 } else if (checkInput) {
80 if (addon) {
81 formControlClass = null;
82 } else {
83 formControlClass = 'form-check-input';
84 }
85 }
86
87 if (attributes.size && isNotaNumber.test(attributes.size)) {
88 warnOnce(
89 'Please use the prop "bsSize" instead of the "size" to bootstrap\'s input sizing.',
90 );
91 bsSize = attributes.size;
92 delete attributes.size;
93 }
94
95 const classes = mapToCssModules(
96 classNames(
97 className,
98 invalid && 'is-invalid',
99 valid && 'is-valid',
100 bsSize
101 ? selectInput
102 ? `form-select-${bsSize}`
103 : `form-control-${bsSize}`
104 : false,
105 formControlClass,
106 ),
107 cssModule,
108 );
109
110 if (Tag === 'input' || (tag && typeof tag === 'function')) {
111 attributes.type = type === 'switch' ? 'checkbox' : type;
112 }
113
114 if (
115 attributes.children &&
116 !(
117 plaintext ||
118 type === 'select' ||
119 typeof Tag !== 'string' ||
120 Tag === 'select'
121 )
122 ) {
123 warnOnce(
124 `Input with a type of "${type}" cannot have children. Please use "value"/"defaultValue" instead.`,
125 );
126 delete attributes.children;
127 }
128
129 return (
130 <Tag
131 {...attributes}
132 ref={innerRef}
133 className={classes}
134 aria-invalid={invalid}
135 />
136 );
137 }
138}
139
140Input.propTypes = propTypes;
141
142export default Input;