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.
19 import './button.scss';
20 import Loader
from '../loading-indicator/loadingIndicator.jsx';
21 var React
= require('react');
22 var ButtonEventListenerMixin
= require('../mixins/ButtonEventListener.js');
26 * A generic button component.
27 * It's props values and a brief description below
29 * Label: The label of the button. What it displays at any given time.
30 * Icon: A url for an icon that will be displayed on the button. Leave blank if no icon required.
31 * Class: Css Classes applied to the element.
32 * sizeOfButton: The preset sizes for the button (small, default, large, xlarge, expand).
33 * minWidth: Minimum Width of the button.
34 * maxWidth: Maximum Width of the button.
36 module
.exports
= React
.createClass({
37 displayName
: "Button",
38 mixins
:[ButtonEventListenerMixin
],
40 label
: React
.PropTypes
.string
,
41 icon
: React
.PropTypes
.array
,
42 className
: React
.PropTypes
.string
,
43 //sizeOfButton: React.PropTypes.string,
44 minWidth
: React
.PropTypes
.string
,
45 maxWidth
: React
.PropTypes
.string
,
46 //isActive: React.PropTypes.bool,
47 //isFocused: React.PropTypes.bool,
48 //isHovered: React.PropTypes.bool,
49 isDisabled
: React
.PropTypes
.bool
54 * Defines default state.
55 * sizeOfButton: See Prop type definitions.
56 * class: See Prop type definitions.
57 * label: See Prop type definitions.
58 * isActive: Boolean to indicate if button is active.
59 * isHovered: Boolean to indicate if the button is being hovered over.
60 * isFocused: Boolean to indicate if the button has been focused.
61 * isDisabled: Boolean to indicate if button has been disabled.
62 * @returns {{sizeOfButton: (*|string), class: *, isActive: boolean, isHovered: boolean,
63 * isFocused: boolean, isDisabled: (*|boolean), label: *}}
65 getInitialState: function() {
67 //sizeOfButton: this.props.size || '', //There is no Medium value in CSS, default size is the absence of a value
68 className
: this.props
.className
|| 'rw-button-primary', //Default value is 'rw-button-primary' which is the primary one
69 label
: this.props
.label
,
73 isLoading
: this.props
.isLoading
|| false,
74 isDisabled
: this.props
.isDisabled
|| false
80 * If any of the state variables have changed, the component should update.
81 * "nextProps" and "nextState" hold the state and property variables as they will be after the update.
82 * "this.props" and "this.state" hold the state and property variables as they were before the update.
83 * returns true if the state have changed. Otherwise returns false.
88 shouldComponentUpdate: function(nextProps
, nextState
) {
89 var currentStateString
= this.state
.label
+ this.state
.isDisabled
+ this.state
.isActive
+ this.state
.isFocused
+
90 this.state
.isHovered
+ this.props
.isLoading
;
91 var nextStateString
= nextState
.label
+ nextState
.isDisabled
+ nextState
.isActive
+ nextState
.isFocused
+
92 nextState
.isHovered
+ nextProps
.isLoading
;
94 if (currentStateString
== nextStateString
) {
102 * Returns a string reflecting the current state of the button.
103 * If the button state "isDisabled" is true, returns a string "disabled".
104 * Otherwise returns a string containing a word for each state that has been set to true.
105 * (ie "active focused" if the states active and focused are true, but hovered is false).
108 setButtonState: function() {
110 if (this.state
.isDisabled
) {
113 if (this.state
.isActive
) {
116 if (this.state
.isHovered
) {
119 if (this.state
.isFocused
) {
128 * Track the width if set and write into markup using Style attribute
129 * Returns the minWidth and maxWidth prop in a string
132 setButtonWidth:function(){
135 if (this.props
.minWidth
) {
136 width
.minWidth
= String(this.props
.minWidth
);
138 if (this.props
.maxWidth
) {
139 width
.maxWidth
= String(this.props
.maxWidth
);
148 * Apply the size of the button to the icon directly
149 * Returns a string indicating the icon size.
153 setIconSize:function(){
155 var iconClass = "rw-icon";
158 iconClass += "-" + this.props.size;
167 * Builds the list of classes.
168 * Returns a string holding each class seperated by a space.
172 setButtonClass:function() {
173 var buttonClass = "";
174 var buttonClassType = "rw-button-primary";
175 // If the size is declared, add it in
176 if (this.state.sizeOfButton) {
177 buttonClass += this.state.sizeOfButton;
180 if (typeof(this.props.className) != "undefined") {
181 this.props.className.push("rw-button-secondary");
183 // Run through the array and check all the values
184 for (var i = 0; i < this.props.className.length; i++) {
186 if (this.props.className[i].indexOf("secondary") > -1) {
187 buttonClassType = "rw-button-secondary"; // If the value of the array is equal to the string "secondary", add a predefined string
189 buttonClass += " " + this.props.className[i]; // Else just write the value of the array
193 buttonClass += " " + buttonClassType; //Add the button style type either primary or secondary
199 * Builds an array of html elements for the icons and returns them.
202 setIconElement: function() {
203 var button_icon
= [];
205 if (typeof(this.props
.icon
) != "undefined") {
206 for (var i
= 0; i
< this.props
.icon
.length
; i
++) {
207 button_icon
.push(React
.createElement('svg', {
208 className
: "rw-button__icon",
210 dangerouslySetInnerHTML
: {__html
: '<use xlink:href="#' + this.props
.icon
[i
] + '" />'} //Using a React method to drop in a hack since React does not support xlink:href yet
218 * Renders the Button Component
219 * Returns a react component that constructs the html that houses the button component.
224 var button_style
= this.setButtonWidth();
225 var button_state
= this.setButtonState();
226 var button_class
= this.state
.className
;
227 var button_icon
= this.setIconElement();
228 var display
= this.state
.label
;
229 if (this.props
.isLoading
) {
230 display
= React
.createElement(Loader
, {show
: true, size
: '1rem', color
: this.props
.loadingColor
});
233 button
= React
.createElement("button", {
234 className
: button_class
,
235 "data-state": button_state
,
238 // onClick: this.onClick,
239 onClick
: this.props
.onClick
,
240 onMouseUp
: this.onMouseUp
,
241 onMouseDown
: this.onMouseDown
,
242 onMouseOver
: this.onMouseOver
,
243 onMouseEnter
: this.onMouseEnter
,
244 onMouseLeave
: this.onMouseLeave
,
245 onMouseOut
: this.onMouseOut
,
246 onTouchCancel
: this.onTouchCancel
,
247 onTouchEnd
: this.onTouchEnd
,
248 onTouchMove
: this.onTouchMove
,
249 onTouchStart
: this.onTouchStart
,
250 onKeyDown
: this.onKeyDown
,
251 onKeyPress
: this.onKeyPress
,
252 onKeyUp
: this.onKeyUp
,
253 onFocus
: this.onFocus
,
257 React
.createElement("span", {className
: "rw-button__label"}, display
)