4 * Copyright 2016 RIFT.IO Inc
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 var React
= require('react');
21 var ButtonEventListenerMixin
= require('../mixins/ButtonEventListener.js');
22 var validator
= require('validator');
25 * A text input component.
26 * It's props values and a brief description below
28 * value: Holds the initial text content of the input.
29 * label: The text content of the label.
30 * requiredText: The text content of the "if required" message.
31 * errorText: The text content of the error message.
32 * placeholder: The initial placeholder text of the input
33 * ClassName: Css Classes applied to the element.
34 * size: The size of the element.
35 * minWidth: Minimum width of the element.
36 * maxWidth: Maximum width of the element.
37 * isRequired: A boolean indicating whether or not the input is required.
38 * isDisabled: A boolean indicating the disabled state of the element.
39 * isReadOnly: A boolean indicating whether or not the input is read only.
40 * pattern: A regex putting constraints on what the user input can be.
41 * maxLength: The hard limit on how many characters can be in the input.
43 module
.exports
= React
.createClass({
44 displayName
: "TextInput",
45 mixins
:[ButtonEventListenerMixin
],
47 value
: React
.PropTypes
.string
,
48 label
: React
.PropTypes
.string
,
49 requiredText
: React
.PropTypes
.string
,
50 errorText
: React
.PropTypes
.string
,
51 placeholder
: React
.PropTypes
.string
,
52 className
: React
.PropTypes
.string
,
53 size
: React
.PropTypes
.string
,
54 minWidth
: React
.PropTypes
.number
,
55 maxWidth
: React
.PropTypes
.number
,
56 isRequired
: React
.PropTypes
.bool
,
57 isDisabled
: React
.PropTypes
.bool
,
58 isReadOnly
: React
.PropTypes
.bool
,
59 pattern
: React
.PropTypes
.string
,
60 maxLength
: React
.PropTypes
.number
,
61 instructions
: React
.PropTypes
.string
66 * Sets the default input state.
67 * If there is no description for the variable, assume it's the same as it's props counterpart.
69 * value: The current text contents of the input.
70 * isActive: Boolean to indicate if input is active.
71 * isHovered: Boolean to indicate if the input is being hovered over.
72 * isFocused: Boolean to indicate if the input has been focused.
73 * isDisabled: Boolean to indicate if input has been disabled.
75 * @returns {{sizeOfButton: (*|string), isActive: boolean, isHovered: boolean, isFocused: boolean, isDisabled: (*|boolean),
76 * isReadOnly: (*|.textInput.isReadOnly|.exports.propTypes.isReadOnly|.exports.getInitialState.isReadOnly|boolean),
77 * isRequired: (*|.textInput.isRequired|.exports.propTypes.isRequired|.exports.getInitialState.isRequired|isRequired|null),
78 * isValid: null, isSuccess: null}}
80 getInitialState: function() {
82 value
: this.props
.value
|| '',
83 label
: this.props
.label
|| "",
84 requiredText
: this.props
.requiredText
|| "Required",
85 instructionsText
: this.props
.instructions
|| "",
87 size
: this.props
.size
|| '',
91 isDisabled
: this.props
.isDisabled
|| false,
92 isReadOnly
: this.props
.isReadOnly
|| false,
93 isRequired
: this.props
.isRequired
|| null,
94 isValid
: null, // Three way bool. Valid: true. Invalid: false. Not acted on: null.
95 isSuccess
: null // Three way bool. Success: true. Error: false. Not acted on: null.
100 * If any of the state variables have changed, the component should update.
101 * "nextProps" and "nextState" hold the state and property variables as they will be after the update.
102 * "this.props" and "this.state" hold the state and property variables as they were before the update.
103 * returns true if the state have changed. Otherwise returns false.
108 shouldComponentUpdate: function(nextProps
, nextState
) {
109 var currentStateString
= this.state
.isReadOnly
+ this.state
.isDisabled
+ this.state
.isActive
+ this.state
.isFocused
+
110 this.state
.isHovered
+ this.state
.isValid
+ this.state
.isSuccess
+ this.state
.value
;
111 var nextStateString
= nextState
.isReadOnly
+ nextState
.isDisabled
+ nextState
.isActive
+ nextState
.isFocused
+
112 nextState
.isHovered
+ nextState
.isValid
+ nextState
.isSuccess
+ nextState
.value
;
113 if (currentStateString
== nextStateString
) {
120 * Makes sure that when the user types new input, the contents of the input changes accordingly.
124 handleChange: function(event
) {
125 this.setState({value
:event
.target
.value
});
129 * Makes sure that when the user types new input, the contents of the input changes accordingly.
133 handleValidation: function(event
) {
134 if (this.props
.isRequired
) {
135 if (validator
.isNull(event
.target
.value
) || event
.target
.value
== '') {
137 errorText
: this.props
.errorText
,
147 if (this.props
.pattern
) {
148 if (!validator
.matches(event
.target
.value
, this.props
.pattern
)) {
150 errorText
: this.props
.errorText
,
164 * Returns a string reflecting the current state of the input.
165 * If the component state "isDisabled" is true, returns a string "disabled".
166 * If the component state "isReadOnly" is true, returns a string "readonly".
167 * Otherwise returns a string containing a word for each state that has been set to true.
168 * (ie "active focused" if the states active and focused are true, but hovered is false).
171 setComponentState: function() {
173 if (this.state
.isDisabled
) {
176 if (this.state
.isReadOnly
) {
179 if (this.state
.isActive
) {
182 if (this.state
.isHovered
) {
185 if (this.state
.isFocused
) {
192 * Renders the Text Input component.
196 var value
= this.state
.value
;
198 var input_style
= {};
199 var input_state
= this.setComponentState();
201 // The following if statements translates the min/max width from a number into a string.
202 if (this.props
.minWidth
) {
203 input_style
['min-width'] = String(this.props
.minWidth
) + 'px';
205 if (this.props
.maxWidth
) {
206 input_style
['max-width'] = String(this.props
.maxWidth
) + 'px';
209 // The input element.
210 input
= React
.createElement("input", {
212 "data-state": input_state
,
213 "data-validate": this.state
.isValid
,
215 placeholder
: this.props
.placeholder
,
216 pattern
: this.props
.pattern
,
217 maxLength
: this.props
.maxLength
,
218 required
: this.state
.isRequired
,
219 disabled
: this.state
.isDisabled
,
220 readOnly
: this.state
.isReadOnly
,
221 onChange
: this.handleChange
,
222 onClick
: this.onClick
,
223 onMouseUp
: this.onMouseUp
,
224 onMouseDown
: this.onMouseDown
,
225 onMouseOver
: this.onMouseOver
,
226 onMouseEnter
: this.onMouseEnter
,
227 onMouseLeave
: this.onMouseLeave
,
228 onMouseOut
: this.onMouseOut
,
229 onTouchCancel
: this.onTouchCancel
,
230 onTouchEnd
: this.onTouchEnd
,
231 onTouchMove
: this.onTouchMove
,
232 onTouchStart
: this.onTouchStart
,
233 onKeyDown
: this.onKeyDown
,
234 onKeyPress
: this.onKeyPress
,
235 onKeyUp
: this.handleValidation
,
236 onFocus
: this.onFocus
,
237 onBlur
: this.handleValidation
,
238 className
: (this.props
.className
|| "rw-textinput"),
244 // The "if required" element. It displays a label if the element is required.
245 if(this.props
.isRequired
== true){
246 var requiredEle
= React
.createElement("small", {className
: "rw-form__required-label"}, this.state
.requiredText
);
250 if(this.state
.isValid
== false) {
251 var validations
= React
.createElement("svg", {className
: "rw-form__icon"}, this.state
.errorText
);
253 // The label element associated with the input.
254 var label
= React
.createElement("label", {className
: "rw-form__label"}, this.state
.label
, requiredEle
, input
, validations
);
256 // The "error" element. It pops up as a message if there is an error with the input.
257 if(this.state
.errorText
!= "") {
258 var error
= React
.createElement("p", {className
: "rw-form__message-error"}, this.state
.errorText
);
262 if(this.state
.instructionsText
!= ""){
263 var instructions
= React
.createElement("p", {className
: "rw-form__instructions"}, this.state
.instructionsText
)
268 // The parent element for all.
269 var ret
= React
.createElement("div", {
270 "data-state": input_state
,
271 required
: this.state
.isRequired
,
272 disabled
: this.state
.isDisabled
,
273 readOnly
: this.state
.isReadOnly
,
274 "data-validate": this.state
.isValid
,
276 }, label
, error
, instructions
);