Merge pull request #19 from react-toolbox/ideal-react-dev

Move to ES6 classes with ES7 class properties
old
Javi Velasco 2015-10-22 09:53:12 +02:00
commit 91bf9bc1f4
70 changed files with 1433 additions and 1682 deletions

4
.babelrc Normal file
View File

@ -0,0 +1,4 @@
{
"stage": 2,
"optional": ["es7.classProperties"]
}

View File

@ -1,4 +1,5 @@
{
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true,
@ -10,7 +11,7 @@
"jsx": true,
"templateStrings": true,
"superInFunctions": false,
"classes": false,
"classes": true,
"modules": [2]
},

View File

@ -1,16 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import utils from '../utils';
import Input from '../input';
import style from './style';
import utils from '../utils';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Autocomplete',
propTypes: {
class Autocomplete extends React.Component {
static propTypes = {
className: React.PropTypes.string,
dataSource: React.PropTypes.any,
disabled: React.PropTypes.bool,
@ -20,52 +15,48 @@ export default React.createClass({
onChange: React.PropTypes.func,
required: React.PropTypes.bool,
value: React.PropTypes.any
},
};
getDefaultProps () {
return {
static defaultProps = {
className: '',
dataSource: {},
multiple: true
};
},
};
getInitialState () {
return {
dataSource: this._indexDataSource(this.props.dataSource),
focus: false,
query: '',
up: false,
values: new Map(),
width: undefined
};
},
state = {
dataSource: this._indexDataSource(this.props.dataSource),
focus: false,
query: '',
up: false,
values: new Map(),
width: undefined
};
componentDidMount () {
if (this.props.value) this.setValue(this.props.value);
this.setState({
width: ReactDOM.findDOMNode(this).getBoundingClientRect().width
});
},
}
componentWillReceiveProps (props) {
if (props.dataSource) {
this.setState({dataSource: this._indexDataSource(props.dataSource)});
}
},
}
componentWillUpdate (props, state) {
this.refs.input.setValue(state.query);
},
}
handleQueryChange () {
handleQueryChange = () => {
const query = this.refs.input.getValue();
if (this.state.query !== query) {
this.setState({query: query});
}
},
};
handleKeyPress (event) {
handleKeyPress = (event) => {
if (event.which === 13 && this.state.active) {
this._selectOption(this.state.active);
}
@ -77,9 +68,9 @@ export default React.createClass({
if (index >= suggestionsKeys.length) index = 0;
this.setState({active: suggestionsKeys[index]});
}
},
};
handleFocus () {
handleFocus = () => {
let client = event.target.getBoundingClientRect();
let screen_height = window.innerHeight || document.documentElement.offsetHeight;
@ -89,85 +80,24 @@ export default React.createClass({
up: client.top > ((screen_height / 2) + client.height),
focus: true
});
},
};
handleBlur () {
handleBlur = () => {
if (this.state.focus) this.setState({focus: false});
},
};
handleHover (event) {
handleHover = (event) => {
this.setState({active: event.target.getAttribute('id')});
},
};
handleSelect (event) {
handleSelect = (event) => {
utils.events.pauseEvent(event);
this._selectOption(event.target.getAttribute('id'));
},
};
handleUnselect (event) {
handleUnselect = (event) => {
this._unselectOption(event.target.getAttribute('id'));
},
_indexDataSource (data = {}) {
if (data.length) {
return new Map(data.map((item) => [item, item]));
} else {
return new Map(Object.keys(data).map((key) => [key, data[key]]));
}
},
_getSuggestions () {
let query = this.state.query.toLowerCase().trim() || '';
let suggestions = new Map();
for (let [key, value] of this.state.dataSource) {
if (!this.state.values.has(key) && value.toLowerCase().trim().startsWith(query)) {
suggestions.set(key, value);
}
}
return suggestions;
},
_selectOption (key) {
let { values, dataSource } = this.state;
let query = !this.props.multiple ? dataSource.get(key) : '';
values = new Map(values);
if (!this.props.multiple) values.clear();
values.set(key, dataSource.get(key));
this.setState({focus: false, query: query, values: values}, () => {
this.refs.input.blur();
if (this.props.onChange) this.props.onChange(this);
});
},
_unselectOption (key) {
if (key) {
let values = new Map(this.state.values);
values.delete(key);
this.setState({focus: false, values: values}, () => {
if (this.props.onChange) this.props.onChange(this);
});
}
},
getValue () {
let values = [...this.state.values.keys()];
return this.props.multiple ? values : (values.length > 0 ? values[0] : null);
},
setValue (dataParam = []) {
let values = new Map();
let data = (typeof dataParam === 'string') ? [dataParam] : dataParam;
for (let [key, value] of this.state.dataSource) {
if (data.indexOf(key) !== -1) values.set(key, value);
}
this.setState({values: values, query: this.props.multiple ? '' : values.get(data[0])});
},
setError (data) {
this.input.setError(data);
},
};
renderSelected () {
if (this.props.multiple) {
@ -179,7 +109,7 @@ export default React.createClass({
</ul>
);
}
},
}
renderSuggestions () {
return [...this._getSuggestions()].map(([key, value]) => {
@ -187,7 +117,7 @@ export default React.createClass({
if (this.state.active === key) className += ` ${style.active}`;
return <li id={key} key={key} className={className}>{value}</li>;
});
},
}
render () {
let className = style.root;
@ -224,4 +154,67 @@ export default React.createClass({
</div>
);
}
});
_indexDataSource (data = {}) {
if (data.length) {
return new Map(data.map((item) => [item, item]));
} else {
return new Map(Object.keys(data).map((key) => [key, data[key]]));
}
}
_getSuggestions () {
let query = this.state.query.toLowerCase().trim() || '';
let suggestions = new Map();
for (let [key, value] of this.state.dataSource) {
if (!this.state.values.has(key) && value.toLowerCase().trim().startsWith(query)) {
suggestions.set(key, value);
}
}
return suggestions;
}
_selectOption (key) {
let { values, dataSource } = this.state;
let query = !this.props.multiple ? dataSource.get(key) : '';
values = new Map(values);
if (!this.props.multiple) values.clear();
values.set(key, dataSource.get(key));
this.setState({focus: false, query: query, values: values}, () => {
this.refs.input.blur();
if (this.props.onChange) this.props.onChange(this);
});
}
_unselectOption (key) {
if (key) {
let values = new Map(this.state.values);
values.delete(key);
this.setState({focus: false, values: values}, () => {
if (this.props.onChange) this.props.onChange(this);
});
}
}
getValue () {
let values = [...this.state.values.keys()];
return this.props.multiple ? values : (values.length > 0 ? values[0] : null);
}
setValue (dataParam = []) {
let values = new Map();
let data = (typeof dataParam === 'string') ? [dataParam] : dataParam;
for (let [key, value] of this.state.dataSource) {
if (data.indexOf(key) !== -1) values.set(key, value);
}
this.setState({values: values, query: this.props.multiple ? '' : values.get(data[0])});
}
setError (data) {
this.input.setError(data);
}
}
export default Autocomplete;

View File

@ -1,14 +1,11 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import FontIcon from '../font_icon';
import Ripple from '../ripple';
import style from './style.scss';
import events from '../utils/events';
const Button = React.createClass({
mixins: [PureRenderMixin],
propTypes: {
class Button extends React.Component {
static propTypes = {
accent: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
@ -20,24 +17,22 @@ const Button = React.createClass({
primary: React.PropTypes.bool,
ripple: React.PropTypes.bool,
type: React.PropTypes.string
},
};
getDefaultProps () {
return {
accent: false,
className: '',
kind: 'flat',
loading: false,
mini: false,
primary: false,
ripple: true
};
},
static defaultProps = {
accent: false,
className: '',
kind: 'flat',
loading: false,
mini: false,
primary: false,
ripple: true
};
handleMouseDown (event) {
handleMouseDown = (event) => {
events.pauseEvent(event);
this.refs.ripple.start(event);
},
}
render () {
let className = style[this.props.kind];
@ -62,6 +57,6 @@ const Button = React.createClass({
</button>
);
}
});
}
export default Button;

View File

@ -1,15 +1,10 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Navigation from '../navigation';
import Ripple from '../ripple';
import style from './style.scss';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Card',
propTypes: {
class Card extends React.Component {
static propTypes = {
className: React.PropTypes.string,
color: React.PropTypes.string,
image: React.PropTypes.string,
@ -18,29 +13,21 @@ export default React.createClass({
onClick: React.PropTypes.func,
title: React.PropTypes.string,
type: React.PropTypes.string
},
};
getDefaultProps () {
return {
className: '',
loading: false,
type: 'default'
};
},
static defaultProps = {
className: '',
loading: false,
type: 'default'
};
getInitialState () {
return {
loading: this.props.loading
};
},
handleMouseDown (event) {
handleMouseDown = (event) => {
if (this.props.onClick) {
event.preventDefault();
this.refs.ripple.start(event);
this.props.onClick(event, this);
}
},
};
renderTitle () {
let styleFigure = {}, styleOverflow = {};
@ -59,7 +46,7 @@ export default React.createClass({
</figure>
);
}
},
}
renderActions () {
if (this.props.actions) {
@ -67,7 +54,7 @@ export default React.createClass({
<Navigation className={style.navigation} actions={this.props.actions} />
);
}
},
}
render () {
let className = style.root;
@ -75,7 +62,7 @@ export default React.createClass({
if (this.props.onClick) className += ` ${style.touch}`;
if (this.props.image || this.props.color) className += ` ${style.contrast}`;
if (this.props.color) className += ` ${style.color}`;
if (this.state.loading) className += ` ${style.loading}`;
if (this.props.loading) className += ` ${style.loading}`;
if (this.props.className) className += ` ${this.props.className}`;
return (
@ -90,14 +77,12 @@ export default React.createClass({
<Ripple
ref='ripple'
className={style.ripple}
loading={this.state.loading}
loading={this.props.loading}
spread={2.5}
/>
</div>
);
},
loading (value) {
this.setState({loading: value});
}
});
}
export default Card;

View File

@ -1,15 +1,10 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Ripple from '../ripple';
import style from './style';
import events from '../utils/events';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Checkbox',
propTypes: {
class Checkbox extends React.Component {
static propTypes = {
checked: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
@ -18,45 +13,43 @@ export default React.createClass({
onBlur: React.PropTypes.func,
onChange: React.PropTypes.func,
onFocus: React.PropTypes.func
},
};
getDefaultProps () {
return {
checked: false,
className: '',
disabled: false
};
},
static defaultProps = {
checked: false,
className: '',
disabled: false
};
getInitialState () {
return { checked: this.props.checked };
},
state = {
checked: this.props.checked
};
handleChange (event) {
handleChange = (event) => {
this.setState({checked: !this.state.checked}, () => {
if (this.props.onChange) this.props.onChange(event, this);
});
},
};
handleClick (event) {
handleClick = (event) => {
events.pauseEvent(event);
if (!this.props.disabled) this.handleChange(event);
},
};
handleMouseDown (event) {
handleMouseDown = (event) => {
if (!this.props.disabled) this.refs.ripple.start(event);
},
};
handleInputClick (event) {
handleInputClick = (event) => {
events.pauseEvent(event);
},
};
render () {
let fieldClassName = style.field;
let checkboxClassName = style.check;
if (this.state.checked) checkboxClassName += ` ${style.checked}`;
if (this.props.disabled) fieldClassName += ` ${style.disabled}`;
if (this.props.className) fieldClassName += ` ${this.props.className}`;
if (this.state.checked) checkboxClassName += ` ${style.checked}`;
return (
<label
@ -68,8 +61,8 @@ export default React.createClass({
{...this.props}
ref='input'
type='checkbox'
checked={this.state.checked}
className={style.input}
checked={this.state.checked}
onChange={this.handleChange}
onClick={this.handleInputClick}
/>
@ -79,21 +72,23 @@ export default React.createClass({
{ this.props.label ? <span role='label' className={style.text}>{this.props.label}</span> : null }
</label>
);
},
}
blur () {
this.refs.input.blur();
},
}
focus () {
this.refs.input.focus();
},
}
getValue () {
return this.state.checked;
},
}
setValue (value) {
this.setState({checked: value});
}
});
}
export default Checkbox;

View File

@ -1,19 +1,14 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import time from '../../utils/time';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Day',
propTypes: {
class Day extends React.Component {
static propTypes = {
day: React.PropTypes.number,
onClick: React.PropTypes.func,
selectedDate: React.PropTypes.object,
viewDate: React.PropTypes.object
},
};
dayStyle () {
if (this.props.day === 1) {
@ -21,20 +16,25 @@ export default React.createClass({
marginLeft: `${time.getFirstWeekDay(this.props.viewDate) * 100 / 7}%`
};
}
},
}
isSelected () {
const sameYear = this.props.viewDate.getFullYear() === this.props.selectedDate.getFullYear();
const sameMonth = this.props.viewDate.getMonth() === this.props.selectedDate.getMonth();
const sameDay = this.props.day === this.props.selectedDate.getDate();
return sameYear && sameMonth && sameDay;
},
}
render () {
const className = this.isSelected() ? `${style.day} ${style.active}` : style.day;
return (
<div className={this.isSelected() ? `${style.day} ${style.active}` : style.day} style={this.dayStyle()}>
<span onClick={this.props.onClick}>{this.props.day}</span>
<div className={className} style={this.dayStyle()}>
<span onClick={this.props.onClick}>
{this.props.day}
</span>
</div>
);
}
});
}
export default Day;

View File

@ -1,101 +1,92 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import CSSTransitionGroup from 'react-addons-css-transition-group';
import { SlideLeft, SlideRight } from '../../animations';
import FontIcon from '../../font_icon';
import Ripple from '../../ripple';
import utils from '../../utils';
import Month from './month';
import utils from '../../utils';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Calendar',
propTypes: {
class Calendar extends React.Component {
static propTypes = {
display: React.PropTypes.oneOf(['months', 'years']),
onChange: React.PropTypes.func,
selectedDate: React.PropTypes.object,
viewDate: React.PropTypes.object
},
};
getDefaultProps () {
return {
display: 'months',
selectedDate: new Date()
};
},
static defaultProps = {
display: 'months',
selectedDate: new Date()
};
getInitialState () {
return {
selectedDate: this.props.selectedDate,
viewDate: this.props.selectedDate
};
},
state = {
selectedDate: this.props.selectedDate,
viewDate: this.props.selectedDate
};
componentDidUpdate () {
if (this.refs.activeYear) {
this.scrollToActive();
}
},
onDayClick (day) {
let newDate = utils.time.setDay(this.state.viewDate, day);
this.setState({selectedDate: newDate});
if (this.props.onChange) this.props.onChange(newDate);
},
onYearClick (year) {
let newDate = utils.time.setYear(this.state.selectedDate, year);
this.setState({selectedDate: newDate, viewDate: newDate});
if (this.props.onChange) this.props.onChange(newDate);
},
}
scrollToActive () {
this.refs.years.scrollTop =
this.refs.activeYear.offsetTop -
this.refs.years.offsetHeight / 2 +
this.refs.activeYear.offsetHeight / 2;
},
}
incrementViewMonth () {
handleDayClick = (day) => {
let newDate = utils.time.setDay(this.state.viewDate, day);
this.setState({selectedDate: newDate});
if (this.props.onChange) this.props.onChange(newDate);
};
handleYearClick = (year) => {
let newDate = utils.time.setYear(this.state.selectedDate, year);
this.setState({selectedDate: newDate, viewDate: newDate});
if (this.props.onChange) this.props.onChange(newDate);
};
incrementViewMonth = () => {
this.refs.rippleRight.start(event);
this.setState({
direction: 'right',
viewDate: utils.time.addMonths(this.state.viewDate, 1)
});
},
};
decrementViewMonth () {
decrementViewMonth = () => {
this.refs.rippleLeft.start(event);
this.setState({
direction: 'left',
viewDate: utils.time.addMonths(this.state.viewDate, -1)
});
},
}
renderYear (year) {
let props = {
className: year === this.state.viewDate.getFullYear() ? style.active : '',
key: year,
onClick: this.onYearClick.bind(this, year)
onClick: this.handleYearClick.bind(this, year)
};
if (year === this.state.viewDate.getFullYear()) {
props.ref = 'activeYear';
}
return (<li {...props}>{ year }</li>);
},
return <li {...props}>{ year }</li>;
}
renderYears () {
return (
<ul ref="years" className={style.years}>
{ utils.range(1900, 2100).map(i => { return this.renderYear(i); })}
{ utils.range(1900, 2100).map((i) => { return this.renderYear(i); })}
</ul>
);
},
}
renderMonths () {
let animation = this.state.direction === 'left' ? SlideLeft : SlideRight;
@ -112,11 +103,11 @@ export default React.createClass({
key={this.state.viewDate.getMonth()}
viewDate={this.state.viewDate}
selectedDate={this.state.selectedDate}
onDayClick={this.onDayClick} />
onDayClick={this.handleDayClick} />
</CSSTransitionGroup>
</div>
);
},
}
render () {
return (
@ -125,4 +116,6 @@ export default React.createClass({
</div>
);
}
});
}
export default Calendar;

View File

@ -1,29 +1,24 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import utils from '../../utils';
import Day from './day';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Month',
propTypes: {
class Month extends React.Component {
static propTypes = {
onDayClick: React.PropTypes.func,
selectedDate: React.PropTypes.object,
viewDate: React.PropTypes.object
},
};
handleDayClick (day) {
handleDayClick = (day) => {
if (this.props.onDayClick) this.props.onDayClick(day);
},
};
renderWeeks () {
return utils.range(0, 7).map(i => {
return <span key={i}>{ utils.time.getFullDayOfWeek(i).charAt(0) }</span>;
});
},
}
renderDays () {
return utils.range(1, utils.time.getDaysInMonth(this.props.viewDate) + 1).map(i => {
@ -37,17 +32,20 @@ export default React.createClass({
/>
);
});
},
}
render () {
return (
<div className={style.month}>
<span className={style.title}>
{ utils.time.getFullMonth(this.props.viewDate)} {this.props.viewDate.getFullYear() }
{ utils.time.getFullMonth(this.props.viewDate)}
{ this.props.viewDate.getFullYear() }
</span>
<div className={style.week}>{ this.renderWeeks() }</div>
<div className={style.days}>{ this.renderDays() }</div>
</div>
);
}
});
}
export default Month;

View File

@ -1,61 +1,52 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import time from '../utils/time';
import Calendar from './calendar';
import Dialog from '../dialog';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'CalendarDialog',
propTypes: {
class CalendarDialog extends React.Component {
static propTypes = {
initialDate: React.PropTypes.object,
onDateSelected: React.PropTypes.func
},
};
getDefaultProps () {
return {
initialDate: new Date()
};
},
static defaultProps = {
initialDate: new Date()
};
getInitialState () {
return {
date: this.props.initialDate,
display: 'months',
actions: [
{ label: 'Cancel', className: style.button, onClick: this.onDateCancel },
{ label: 'Ok', className: style.button, onClick: this.onDateSelected }
]
};
},
state = {
date: this.props.initialDate,
display: 'months',
actions: [
{ label: 'Cancel', className: style.button, onClick: this.onDateCancel.bind(this) },
{ label: 'Ok', className: style.button, onClick: this.onDateSelected.bind(this) }
]
};
onCalendarChange (date) {
handleCalendarChange = (date) => {
this.setState({date: date, display: 'months'});
},
};
displayMonths = () => {
this.setState({display: 'months'});
};
displayYears = () => {
this.setState({display: 'years'});
};
onDateCancel () {
this.refs.dialog.hide();
},
}
onDateSelected () {
if (this.props.onDateSelected) this.props.onDateSelected(this.state.date);
this.refs.dialog.hide();
},
}
show () {
this.refs.dialog.show();
},
displayMonths () {
this.setState({display: 'months'});
},
displayYears () {
this.setState({display: 'years'});
},
}
render () {
const display = `display-${this.state.display}`;
@ -80,10 +71,12 @@ export default React.createClass({
<Calendar
ref="calendar"
display={this.state.display}
onChange={this.onCalendarChange}
onChange={this.handleCalendarChange}
selectedDate={this.state.date} />
</div>
</Dialog>
);
}
});
}
export default CalendarDialog;

View File

@ -1,46 +1,37 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import time from '../utils/time';
import events from '../utils/events';
import CalendarDialog from './dialog';
import Input from '../input';
import events from '../utils/events';
import time from '../utils/time';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'DatePicker',
propTypes: {
class DatePicker extends React.Component {
static propTypes = {
className: React.PropTypes.string,
value: React.PropTypes.object
},
};
getDefaultProps () {
return {
className: ''
};
},
static defaultProps = {
className: ''
};
getInitialState () {
return {
value: this.props.value
};
},
state = {
value: this.props.value
};
openCalendarDialog (event) {
handleMouseDown = (event) => {
events.pauseEvent(event);
this.refs.dialog.show();
},
};
onDateSelected (value) {
handleDateSelected = (value) => {
this.refs.input.setValue(this.formatDate(value));
this.setState({value: value});
},
};
formatDate (date) {
return `${date.getDate()} ${time.getFullMonth(date)} ${date.getFullYear()}`;
},
}
render () {
return (
@ -50,24 +41,26 @@ export default React.createClass({
type='text'
readOnly={true}
className={style.input}
onMouseDown={this.openCalendarDialog}
onMouseDown={this.handleMouseDown}
placeholder='Pick up date'
value={this.state.value ? this.formatDate(this.state.value) : null}
/>
<CalendarDialog
ref='dialog'
initialDate={this.state.value}
onDateSelected={this.onDateSelected}
onDateSelected={this.handleDateSelected}
/>
</div>
);
},
}
getValue () {
return this.state.value;
},
}
setValue (value) {
this.setState({value: value});
}
});
}
export default DatePicker;

View File

@ -1,31 +1,24 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Button from '../button';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Dialog',
propTypes: {
class Dialog extends React.Component {
static propTypes = {
actions: React.PropTypes.array,
active: React.PropTypes.bool,
className: React.PropTypes.string,
title: React.PropTypes.string,
type: React.PropTypes.string
},
};
getDefaultProps () {
return {
actions: [],
type: 'normal'
};
},
static defaultProps = {
actions: [],
type: 'normal'
};
getInitialState () {
return { active: this.props.active };
},
state = {
active: this.props.active
};
renderActions () {
return this.props.actions.map((action, idx) => {
@ -33,7 +26,7 @@ export default React.createClass({
if (action.className) className += ` ${action.className}`;
return <Button key={idx} {...action} className={className} />;
});
},
}
render () {
let className = `${style.root} ${style[this.props.type]}`;
@ -54,13 +47,15 @@ export default React.createClass({
</div>
</div>
);
},
}
show () {
this.setState({active: true});
},
}
hide () {
this.setState({active: false});
}
});
}
export default Dialog;

View File

@ -1,35 +1,28 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style.scss';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Drawer',
propTypes: {
class Drawer extends React.Component {
static propTypes = {
active: React.PropTypes.bool,
className: React.PropTypes.string,
hideable: React.PropTypes.bool,
type: React.PropTypes.string
},
};
getDefaultProps () {
return {
className: '',
type: 'left'
};
},
static defaultProps = {
className: '',
type: 'left'
};
getInitialState () {
return { active: this.props.active };
},
state = {
active: this.props.active
};
handleOverlayClick () {
handleOverlayClick = () => {
if (this.props.hideable) {
this.setState({active: false});
}
},
};
render () {
let className = `${style.drawer} ${style[this.props.type]}`;
@ -44,13 +37,15 @@ export default React.createClass({
</aside>
</div>
);
},
}
show () {
this.setState({active: true});
},
}
hide () {
this.setState({active: false});
}
});
}
export default Drawer;

View File

@ -1,10 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Ripple from '../ripple';
import style from './style';
function _selectValue (value, dataSource) {
const _selectValue = (value, dataSource) => {
let item;
if (value) {
for (item of dataSource) {
@ -14,14 +13,10 @@ function _selectValue (value, dataSource) {
} else {
return dataSource[0];
}
}
};
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Dropdown',
propTypes: {
class Dropdown extends React.Component {
static propTypes = {
className: React.PropTypes.string,
dataSource: React.PropTypes.array,
disabled: React.PropTypes.bool,
@ -29,37 +24,33 @@ export default React.createClass({
onChange: React.PropTypes.func,
template: React.PropTypes.func,
value: React.PropTypes.string
},
};
getDefaultProps () {
return {
className: '',
dataSource: [],
up: false
};
},
static defaultProps = {
className: '',
dataSource: [],
up: false
};
getInitialState () {
return {
active: false,
selected: _selectValue(this.props.value, this.props.dataSource),
width: undefined
};
},
state = {
active: false,
selected: _selectValue(this.props.value, this.props.dataSource),
width: undefined
};
componentDidMount () {
this.setState({
width: ReactDOM.findDOMNode(this).getBoundingClientRect().width
});
},
}
componentDidUpdate (prev_props, prev_state) {
if (this.props.onChange && prev_state.selected !== this.state.selected && prev_state.active) {
this.props.onChange(this);
}
},
}
handleClick (event) {
handleClick = (event) => {
let client = event.target.getBoundingClientRect();
let screen_height = window.innerHeight || document.documentElement.offsetHeight;
@ -67,22 +58,19 @@ export default React.createClass({
active: true,
up: client.top > ((screen_height / 2) + client.height)
});
},
};
handleClickValue (id) {
handleClickValue = (id) => {
if (!this.props.disabled) {
let value = id.toString();
for (let item of this.props.dataSource) {
if (item.value.toString() === value) {
this.setState({
active: false,
selected: item
});
this.setState({active: false, selected: item});
break;
}
}
}
},
};
renderValues () {
let items = this.props.dataSource.map((item, index) => {
@ -107,7 +95,7 @@ export default React.createClass({
let valuesStyle = {width: this.state.width};
return <ul ref='values' className={className} style={valuesStyle}>{ items }</ul>;
},
}
render () {
let className = style.root;
@ -124,13 +112,15 @@ export default React.createClass({
</div>
</div>
);
},
}
getValue () {
return this.state.selected.value;
},
}
setValue (data) {
this.setState({selected: data});
}
});
}
export default Dropdown;

View File

@ -1,30 +1,23 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
const FontIcon = props => {
let className = style[props.value];
if (props.className) className += ` ${props.className}`;
return (
<span data-react-toolbox='icon' {...props} className={className}>
{props.children}
</span>
);
};
displayName: 'FontIcon',
FontIcon.propTypes = {
className: React.PropTypes.string,
value: React.PropTypes.string
};
propTypes: {
className: React.PropTypes.string,
value: React.PropTypes.string
},
FontIcon.defaultProps = {
className: ''
};
getDefaultProps () {
return {
className: ''
};
},
render () {
let className = style[this.props.value];
if (this.props.className) className += ` ${this.props.className}`;
return (
<span data-react-toolbox='icon' {...this.props} className={className}>
{this.props.children}
</span>
);
}
});
export default FontIcon;

View File

@ -1,6 +1,4 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import Autocomplete from '../autocomplete';
import Button from '../button';
@ -13,12 +11,8 @@ import Slider from '../slider';
import Switch from '../switch';
import TimePicker from '../time_picker';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Form',
propTypes: {
class Form extends React.Component {
static propTypes = {
attributes: React.PropTypes.array,
className: React.PropTypes.string,
onChange: React.PropTypes.func,
@ -26,20 +20,16 @@ export default React.createClass({
onSubmit: React.PropTypes.func,
onValid: React.PropTypes.func,
storage: React.PropTypes.string
},
};
getDefaultProps () {
return {
attributes: [],
className: ''
};
},
static defaultProps = {
attributes: [],
className: ''
};
getInitialState () {
return {
attributes: this.storage(this.props)
};
},
state = {
attributes: this.storage(this.props)
};
componentWillReceiveProps (next_props) {
if (next_props.attributes) {
@ -47,16 +37,16 @@ export default React.createClass({
this.setState({attributes: attributes});
this.setValue(attributes.map((item) => { return item; }));
}
},
}
onSubmit (event) {
onSubmit = (event) => {
event.preventDefault();
if (this.props.onSubmit) {
this.props.onSubmit(event, this);
}
},
};
onChange (event) {
onChange = (event) => {
let is_valid = true;
let value = this.getValue();
for (let attr of this.state.attributes) {
@ -78,7 +68,7 @@ export default React.createClass({
if (this.refs.submit) this.refs.submit.getDOMNode().setAttribute('disabled', true);
if (this.props.onError) this.props.onError(event, this);
}
},
};
render () {
let className = `${style.root} ${this.props.className}`;
@ -117,7 +107,7 @@ export default React.createClass({
{ this.props.children }
</form>
);
},
}
storage (props, value) {
let key = `react-toolbox-form-${props.storage}`;
@ -137,7 +127,7 @@ export default React.createClass({
}
return props.attributes;
},
}
getValue () {
let value = {};
@ -162,7 +152,7 @@ export default React.createClass({
}
return value;
},
}
setValue (data = {}) {
for (let field of data) {
@ -171,4 +161,6 @@ export default React.createClass({
}
}
}
});
}
export default Form;

View File

@ -1,14 +1,9 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style.scss';
import FontIcon from '../font_icon';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Input',
propTypes: {
class Input extends React.Component {
static propTypes = {
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
error: React.PropTypes.string,
@ -23,28 +18,26 @@ export default React.createClass({
required: React.PropTypes.bool,
type: React.PropTypes.string,
value: React.PropTypes.any
},
};
getDefaultProps () {
return {
className: '',
disabled: false,
floating: true,
multiline: false,
required: false,
type: 'text'
};
},
static defaultProps = {
className: '',
disabled: false,
floating: true,
multiline: false,
required: false,
type: 'text'
};
getInitialState () {
return { value: this.props.value };
},
state = {
value: this.props.value
};
onChange (event) {
onChange = (event) => {
this.setState({value: event.target.value}, () => {
if (this.props.onChange) this.props.onChange(event, this);
});
},
};
renderInput () {
let className = style.input;
@ -71,7 +64,7 @@ export default React.createClass({
onChange={this.onChange} />
);
}
},
}
render () {
let className = style.root;
@ -92,21 +85,23 @@ export default React.createClass({
{ this.props.error ? <span className={style.error}>{this.props.error}</span> : null }
</div>
);
},
}
blur () {
this.refs.input.blur();
},
}
focus () {
this.refs.input.focus();
},
}
getValue () {
return this.state.value;
},
}
setValue (value) {
this.setState({value: value});
}
});
}
export default Input;

View File

@ -1,43 +1,34 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import FontIcon from '../font_icon';
export default React.createClass({
mixins: [PureRenderMixin],
const Link = (props) => {
let className = style.root;
if (props.className) className += ` ${props.className}`;
return (
<a
{...props}
data-react-toolbox='link'
href={props.route}
className={className}
>
{ props.icon ? <FontIcon className={style.icon} value={props.icon} /> : null }
{ props.label ? <abbr>{props.label}</abbr> : null }
{ props.count && parseInt(props.count) !== 0 ? <small>{props.count}</small> : null}
</a>
);
};
displayName: 'Link',
Link.propTypes = {
label: React.PropTypes.string,
className: React.PropTypes.string,
count: React.PropTypes.number,
icon: React.PropTypes.string,
onClick: React.PropTypes.func,
route: React.PropTypes.string
};
propTypes: {
label: React.PropTypes.string,
className: React.PropTypes.string,
count: React.PropTypes.number,
icon: React.PropTypes.string,
onClick: React.PropTypes.func,
route: React.PropTypes.string
},
getDefaultProps () {
return {
attributes: '',
className: ''
};
},
render () {
let className = style.root;
if (this.props.className) className += ` ${this.props.className}`;
return (
<a
{...this.props}
data-react-toolbox='link'
href={this.props.route}
className={className}
>
{ this.props.icon ? <FontIcon className={style.icon} value={this.props.icon} /> : null }
{ this.props.label ? <abbr>{this.props.label}</abbr> : null }
{ this.props.count && parseInt(this.props.count) !== 0 ? <small>{this.props.count}</small> : null}
</a>
);
}
});
Link.defaultProps = {
attributes: '',
className: ''
};

View File

@ -1,51 +1,44 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Checkbox from '../checkbox';
import ListItemContent from './content';
import style from './style';
const ListCheckbox = React.createClass({
mixins: [PureRenderMixin],
const ListCheckbox = props => {
let className = `${style.item} ${style['checkbox-item']}`;
if (props.legend) className += ` ${style['with-legend']}`;
if (props.disabled) className += ` ${style.disabled}`;
if (props.className) className += ` ${props.className}`;
propTypes: {
caption: React.PropTypes.string.isRequired,
checked: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
legend: React.PropTypes.string,
name: React.PropTypes.string,
onBlur: React.PropTypes.func,
onChange: React.PropTypes.func,
onFocus: React.PropTypes.func
},
return (
<li className={className}>
<Checkbox
checked={props.checked}
className={style.checkbox}
disabled={props.disabled}
label={<ListItemContent caption={props.caption} legend={props.legend} />}
name={props.name}
onBlur={props.onBlur}
onChange={props.onChange}
onFocus={props.onFocus}
/>
</li>
);
};
getDefaultProps () {
return {
disabled: false
};
},
ListCheckbox.propTypes = {
caption: React.PropTypes.string.isRequired,
checked: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
legend: React.PropTypes.string,
name: React.PropTypes.string,
onBlur: React.PropTypes.func,
onChange: React.PropTypes.func,
onFocus: React.PropTypes.func
};
render () {
let className = `${style.item} ${style['checkbox-item']}`;
if (this.props.legend) className += ` ${style['with-legend']}`;
if (this.props.disabled) className += ` ${style.disabled}`;
if (this.props.className) className += ` ${this.props.className}`;
return (
<li className={className}>
<Checkbox
checked={this.props.checked}
className={style.checkbox}
disabled={this.props.disabled}
label={<ListItemContent caption={this.props.caption} legend={this.props.legend} />}
name={this.props.name}
onBlur={this.props.onBlur}
onChange={this.props.onChange}
onFocus={this.props.onFocus}
/>
</li>
);
}
});
ListCheckbox.defaultProps = {
disabled: false
};
export default ListCheckbox;

View File

@ -1,14 +1,12 @@
import React from 'react';
import style from './style';
const ListItemContent = ({ caption, legend }) => {
return (
<span className={style.text}>
<span className={style.caption}>{caption}</span>
<span className={style.legend}>{legend}</span>
</span>
);
};
const ListItemContent = ({ caption, legend }) => (
<span className={style.text}>
<span className={style.caption}>{caption}</span>
<span className={style.legend}>{legend}</span>
</span>
);
ListItemContent.propTypes = {
caption: React.PropTypes.string.isRequired,

View File

@ -1,14 +1,11 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import FontIcon from '../font_icon';
import ListItemContent from './content';
import Ripple from '../ripple';
import style from './style';
const ListItem = React.createClass({
mixins: [PureRenderMixin],
propTypes: {
class ListItem extends React.Component {
static propTypes = {
avatar: React.PropTypes.string,
caption: React.PropTypes.string.isRequired,
disabled: React.PropTypes.bool,
@ -17,27 +14,25 @@ const ListItem = React.createClass({
rightIcon: React.PropTypes.string,
ripple: React.PropTypes.bool,
selectable: React.PropTypes.bool
},
};
getDefaultProps () {
return {
disabled: false,
ripple: false,
selectable: false
};
},
static defaultProps = {
disabled: false,
ripple: false,
selectable: false
};
handleClick (event) {
handleClick = (event) => {
if (this.props.onClick && !this.props.disabled) {
this.props.onClick(event);
}
},
};
handleMouseDown (event) {
handleMouseDown = (event) => {
if (this.refs.ripple && !this.props.disabled) {
this.refs.ripple.start(event);
}
},
};
render () {
let className = style.item;
@ -60,6 +55,6 @@ const ListItem = React.createClass({
</li>
);
}
});
}
export default ListItem;

View File

@ -1,25 +1,20 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ListItem from './item';
import style from './style';
const List = React.createClass({
mixins: [PureRenderMixin],
propTypes: {
class List extends React.Component {
static propTypes = {
className: React.PropTypes.string,
onClick: React.PropTypes.func,
ripple: React.PropTypes.bool,
selectable: React.PropTypes.bool
},
};
getDefaultProps () {
return {
className: '',
ripple: false,
selectable: false
};
},
static defaultProps = {
className: '',
ripple: false,
selectable: false
};
renderItems () {
return React.Children.map(this.props.children, (item) => {
@ -32,7 +27,7 @@ const List = React.createClass({
return React.cloneElement(item);
}
});
},
}
render () {
let className = style.list;
@ -43,6 +38,6 @@ const List = React.createClass({
</ul>
);
}
});
}
export default List;

View File

@ -1,13 +1,11 @@
import React from 'react';
import style from './style';
const ListSubHeader = ({ caption }) => {
return (
<h5 className={style.subheader}>
{ caption }
</h5>
);
};
const ListSubHeader = ({ caption }) => (
<h5 className={style.subheader}>
{ caption }
</h5>
);
ListSubHeader.propTypes = {
caption: React.PropTypes.string

View File

@ -4,10 +4,8 @@ import Menu from './menu';
import Ripple from '../ripple';
import style from './style.icon_menu';
export default React.createClass({
displayName: 'IconMenu',
propTypes: {
class IconMenu extends React.Component {
static propTypes = {
className: React.PropTypes.string,
icon: React.PropTypes.string,
iconRipple: React.PropTypes.bool,
@ -16,29 +14,27 @@ export default React.createClass({
onSelect: React.PropTypes.func,
position: React.PropTypes.string,
selectable: React.PropTypes.bool
},
};
getDefaultProps () {
return {
className: '',
icon: 'more-vert',
iconRipple: true,
menuRipple: true,
position: 'auto',
selectable: false
};
},
static defaultProps = {
className: '',
icon: 'more-vert',
iconRipple: true,
menuRipple: true,
position: 'auto',
selectable: false
};
handleButtonClick () {
handleButtonClick = () => {
this.refs.menu.show();
if (this.props.onClick) this.props.onClick();
},
};
handleMouseDown (event) {
handleMouseDown = (event) => {
if (this.props.iconRipple) {
this.refs.ripple.start(event);
}
},
};
render () {
let className = style.root;
@ -67,4 +63,6 @@ export default React.createClass({
</div>
);
}
});
}
export default IconMenu;

View File

@ -13,10 +13,8 @@ const POSITION = {
BOTTOM_RIGHT: 'bottom-right'
};
export default React.createClass({
displayName: 'Menu',
propTypes: {
class Menu extends React.Component {
static propTypes = {
active: React.PropTypes.bool,
className: React.PropTypes.string,
onHide: React.PropTypes.func,
@ -27,38 +25,34 @@ export default React.createClass({
ripple: React.PropTypes.bool,
selectable: React.PropTypes.bool,
value: React.PropTypes.any
},
};
getDefaultProps () {
return {
active: false,
outline: true,
position: POSITION.STATIC,
ripple: true,
selectable: true
};
},
static defaultProps = {
active: false,
outline: true,
position: POSITION.STATIC,
ripple: true,
selectable: true
};
getInitialState () {
return {
active: this.props.active,
rippled: false,
value: this.props.value
};
},
state = {
active: this.props.active,
rippled: false,
value: this.props.value
};
componentDidMount () {
const { width, height } = this.refs.menu.getBoundingClientRect();
const position = this.props.position === POSITION.AUTO ? this.calculatePosition() : this.props.position;
this.setState({position: position, width: width, height: height});
},
}
componentWillReceiveProps (nextProps) {
if (this.props.position !== nextProps.position) {
const position = nextProps.position === POSITION.AUTO ? this.calculatePosition() : nextProps.position;
this.setState({ position: position });
}
},
}
shouldComponentUpdate (nextProps, nextState) {
if (!this.state.active && nextState.active && this.props.position === POSITION.AUTO) {
@ -71,13 +65,13 @@ export default React.createClass({
}
}
return true;
},
}
componentWillUpdate (prevState, nextState) {
if (!prevState.active && nextState.active) {
utils.events.addEventsToDocument({click: this.handleDocumentClick});
}
},
}
componentDidUpdate (prevProps, prevState) {
if (prevState.active && !this.state.active) {
@ -86,13 +80,21 @@ export default React.createClass({
} else if (!prevState.active && this.state.active && this.props.onShow) {
this.props.onShow();
}
},
}
handleDocumentClick (event) {
handleDocumentClick = (event) => {
if (this.state.active && !utils.events.targetIsDescendant(event, ReactDOM.findDOMNode(this))) {
this.setState({active: false, rippled: false});
}
},
};
handleSelect = (item) => {
let { value, onClick } = item.props;
this.setState({value: value, active: false, rippled: this.props.ripple}, () => {
if (onClick) onClick();
if (this.props.onSelect) this.props.onSelect(value, this);
});
};
calculatePosition () {
const {top, left, height, width} = ReactDOM.findDOMNode(this).parentNode.getBoundingClientRect();
@ -100,13 +102,13 @@ export default React.createClass({
const toTop = top < ((wh / 2) - height / 2);
const toLeft = left < ((ww / 2) - width / 2);
return `${toTop ? 'top' : 'bottom'}-${toLeft ? 'left' : 'right'}`;
},
}
getRootStyle () {
if (this.state.position !== POSITION.STATIC) {
return { width: this.state.width, height: this.state.height };
}
},
}
getMenuStyle () {
const { width, height, position } = this.state;
@ -123,15 +125,7 @@ export default React.createClass({
return { clip: `rect(0 0 0 0)` };
}
}
},
handleSelect (item) {
let { value, onClick } = item.props;
this.setState({value: value, active: false, rippled: this.props.ripple}, () => {
if (onClick) onClick();
if (this.props.onSelect) this.props.onSelect(value, this);
});
},
}
renderItems () {
return React.Children.map(this.props.children, (item) => {
@ -145,7 +139,7 @@ export default React.createClass({
return React.cloneElement(item);
}
});
},
}
render () {
const outlineStyle = { width: this.state.width, height: this.state.height };
@ -162,17 +156,19 @@ export default React.createClass({
</ul>
</div>
);
},
}
getValue () {
return this.state.value;
},
}
show () {
this.setState({active: true});
},
}
hide () {
this.setState({active: false});
}
});
}
export default Menu;

View File

@ -1,13 +1,9 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import style from './style.menu_divider';
export default React.createClass({
const MenuDivider = () => (
<hr data-react-toolbox='menu-divider' className={style.root}/>
);
displayName: 'MenuDivider',
render () {
return (
<hr data-react-toolbox='menu-divider' className={style.root}/>
);
}
});
export default MenuDivider;

View File

@ -1,43 +1,35 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import FontIcon from '../font_icon';
import Ripple from '../ripple';
import style from './style.menu_item';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'MenuItem',
propTypes: {
class MenuItem extends React.Component {
static propTypes = {
caption: React.PropTypes.string,
disabled: React.PropTypes.bool,
icon: React.PropTypes.string,
ripple: React.PropTypes.bool,
shortcut: React.PropTypes.string,
selected: React.PropTypes.bool
},
};
getDefaultProps () {
return {
disabled: false,
ripple: false,
selected: false
};
},
static defaultProps = {
disabled: false,
ripple: false,
selected: false
};
handleClick (event) {
handleClick = (event) => {
if (this.props.onClick && !this.props.disabled) {
this.props.onClick(event, this);
}
},
};
handleMouseDown (event) {
handleMouseDown = (event) => {
if (this.props.ripple && !this.props.disabled) {
this.refs.ripple.start(event);
}
},
};
render () {
let className = style.root;
@ -59,4 +51,6 @@ export default React.createClass({
</li>
);
}
});
}
export default MenuItem;

View File

@ -1,48 +1,41 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import Button from '../button';
import Link from '../link';
export default React.createClass({
mixins: [PureRenderMixin],
const Navigation = props => {
let className = `${style[props.type]}`;
if (props.className) className += ` ${props.className}`;
displayName: 'Navigation',
const buttons = props.actions.map((action, index) => {
return <Button key={index} {...action} />;
});
propTypes: {
actions: React.PropTypes.array,
className: React.PropTypes.string,
routes: React.PropTypes.array,
type: React.PropTypes.string
},
const links = props.routes.map((route, index) => {
return <Link key={index} {...route} />;
});
getDefaultProps () {
return {
actions: [],
className: '',
type: 'default',
routes: []
};
},
return (
<nav data-react-toolbox='navigation' className={className}>
{ links }
{ buttons }
{ props.children }
</nav>
);
};
render () {
let className = `${style[this.props.type]}`;
if (this.props.className) className += ` ${this.props.className}`;
Navigation.propTypes = {
actions: React.PropTypes.array,
className: React.PropTypes.string,
routes: React.PropTypes.array,
type: React.PropTypes.string
};
const buttons = this.props.actions.map((action, index) => {
return <Button key={index} {...action} />;
});
Navigation.defaultProps = {
actions: [],
className: '',
type: 'default',
routes: []
};
const links = this.props.routes.map((route, index) => {
return <Link key={index} {...route} />;
});
return (
<nav data-react-toolbox='navigation' className={className}>
{ links }
{ buttons }
{ this.props.children }
</nav>
);
}
});
export default Navigation;

View File

@ -1,15 +1,9 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import prefixer from '../utils/prefixer';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'ProgressBar',
propTypes: {
class ProgressBar extends React.Component {
static propTypes = {
buffer: React.PropTypes.number,
className: React.PropTypes.string,
max: React.PropTypes.number,
@ -18,32 +12,30 @@ export default React.createClass({
multicolor: React.PropTypes.bool,
type: React.PropTypes.string,
value: React.PropTypes.number
},
};
getDefaultProps () {
return {
buffer: 0,
className: '',
max: 100,
min: 0,
mode: 'indeterminate',
multicolor: false,
type: 'linear',
value: 0
};
},
static defaultProps = {
buffer: 0,
className: '',
max: 100,
min: 0,
mode: 'indeterminate',
multicolor: false,
type: 'linear',
value: 0
};
calculateRatio (value) {
if (value < this.props.min) return 0;
if (value > this.props.max) return 1;
return (value - this.props.min) / (this.props.max - this.props.min);
},
}
circularStyle () {
if (this.props.mode !== 'indeterminate') {
return {strokeDasharray: `${2 * Math.PI * 25 * this.calculateRatio(this.props.value)}, 400`};
}
},
}
renderCircular () {
return (
@ -51,7 +43,7 @@ export default React.createClass({
<circle className={style.path} style={this.circularStyle()} cx='30' cy='30' r='25' />
</svg>
);
},
}
linearStyle () {
if (this.props.mode !== 'indeterminate') {
@ -62,7 +54,7 @@ export default React.createClass({
} else {
return {};
}
},
}
renderLinear () {
const {buffer, value} = this.linearStyle();
@ -72,7 +64,7 @@ export default React.createClass({
<span ref='value' data-ref='value' className={style.value} style={value}></span>
</div>
);
},
}
render () {
let className = this.props.type === 'linear' ? style.linear : style.circular;
@ -92,4 +84,6 @@ export default React.createClass({
</div>
);
}
});
}
export default ProgressBar;

View File

@ -1,15 +1,10 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Ripple from '../ripple';
import style from './style';
import events from '../utils/events';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'RadioButton',
propTypes: {
class RadioButton extends React.Component {
static propTypes = {
checked: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
@ -19,34 +14,32 @@ export default React.createClass({
onChange: React.PropTypes.func,
onFocus: React.PropTypes.func,
value: React.PropTypes.any
},
};
getDefaultProps () {
return {
checked: false,
className: '',
disabled: false
};
},
static defaultProps = {
checked: false,
className: '',
disabled: false
};
handleClick (event) {
handleClick = (event) => {
events.pauseEvent(event);
if (!this.props.disabled) this.handleChange(event);
},
};
handleChange (event) {
handleChange = (event) => {
if (!this.props.checked && this.props.onChange) {
this.props.onChange(event, this);
}
},
};
handleMouseDown (event) {
handleMouseDown = (event) => {
if (!this.props.disabled) this.refs.ripple.start(event);
},
};
handleInputClick (event) {
handleInputClick = (event) => {
events.pauseEvent(event);
},
};
render () {
let labelClassName = style[this.props.disabled ? 'disabled' : 'field'];
@ -69,13 +62,15 @@ export default React.createClass({
{ this.props.label ? <span className={style.text}>{this.props.label}</span> : null }
</label>
);
},
}
blur () {
this.refs.input.blur();
},
}
focus () {
this.refs.input.focus();
}
});
}
export default RadioButton;

View File

@ -1,36 +1,29 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import RadioButton from './radio_button';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'RadioGroup',
propTypes: {
class RadioGroup extends React.Component {
static propTypes = {
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
name: React.PropTypes.string,
onChange: React.PropTypes.func,
value: React.PropTypes.any
},
};
getDefaultProps () {
return {
className: '',
disabled: false
};
},
static defaultProps = {
className: '',
disabled: false
};
getInitialState () {
return { value: this.props.value };
},
state = {
value: this.props.value
};
handleChange (value, event) {
handleChange = (value, event) => {
this.setState({value: value}, () => {
if (this.props.onChange) this.props.onChange(event, this);
});
},
};
renderRadioButtons () {
return React.Children.map(this.props.children, (radio, idx) => {
@ -46,7 +39,7 @@ export default React.createClass({
/>
);
});
},
}
render () {
return (
@ -54,13 +47,15 @@ export default React.createClass({
{this.renderRadioButtons()}
</div>
);
},
}
getValue () {
return this.state.value;
},
}
setValue (value) {
this.setState({value: value});
}
});
}
export default RadioGroup;

View File

@ -1,52 +1,43 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style.scss';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Ripple',
propTypes: {
class Ripple extends React.Component {
static propTypes = {
centered: React.PropTypes.bool,
className: React.PropTypes.string,
loading: React.PropTypes.bool,
spread: React.PropTypes.number
},
};
getDefaultProps () {
return {
centered: false,
className: '',
loading: false,
spread: 2
};
},
static defaultProps = {
centered: false,
className: '',
loading: false,
spread: 2
};
getInitialState () {
return {
active: false,
restarting: false,
top: null,
left: null,
width: null
};
},
state = {
active: false,
restarting: false,
top: null,
left: null,
width: null
};
start ({ pageX, pageY }) {
document.addEventListener('mouseup', this.end);
start = ({ pageX, pageY }) => {
document.addEventListener('mouseup', this.handleEnd);
const {top, left, width} = this._getDescriptor(pageX, pageY);
this.setState({active: false, restarting: true, width: 0}, () => {
this.refs.ripple.offsetWidth; //eslint-disable-line no-unused-expressions
this.setState({active: true, restarting: false, top: top, left: left, width: width});
});
},
};
end () {
document.removeEventListener('mouseup', this.end);
handleEnd = () => {
document.removeEventListener('mouseup', this.handleEnd);
this.setState({active: false});
},
};
_getDescriptor (pageX, pageY) {
let { left, top, height, width } = ReactDOM.findDOMNode(this).getBoundingClientRect();
@ -55,7 +46,7 @@ export default React.createClass({
top: this.props.centered ? height / 2 : pageY - top,
width: width * this.props.spread
};
},
}
render () {
let { left, top, width } = this.state;
@ -71,4 +62,6 @@ export default React.createClass({
</span>
);
}
});
}
export default Ripple;

View File

@ -5,10 +5,8 @@ import utils from '../utils';
import ProgressBar from '../progress_bar';
import Input from '../input';
export default React.createClass({
displayName: 'Slider',
propTypes: {
class Slider extends React.Component {
static propTypes = {
className: React.PropTypes.string,
editable: React.PropTypes.bool,
max: React.PropTypes.number,
@ -18,160 +16,156 @@ export default React.createClass({
snaps: React.PropTypes.bool,
step: React.PropTypes.number,
value: React.PropTypes.number
},
};
getDefaultProps () {
return {
className: '',
editable: false,
max: 100,
min: 0,
pinned: false,
snaps: false,
step: 0.01,
value: 0
};
},
static defaultProps = {
className: '',
editable: false,
max: 100,
min: 0,
pinned: false,
snaps: false,
step: 0.01,
value: 0
};
getInitialState () {
return {
sliderStart: 0,
sliderLength: 0,
value: this.props.value
};
},
state = {
sliderStart: 0,
sliderLength: 0,
value: this.props.value
};
componentDidMount () {
window.addEventListener('resize', this.onResize);
this.onResize();
},
window.addEventListener('resize', this.handleResize);
this.handleResize();
}
componentWillUnmount () {
window.removeEventListener('resize', this.onResize);
},
window.removeEventListener('resize', this.handleResize);
}
componentDidUpdate (prevProps, prevState) {
if (prevState.value !== this.state.value) {
if (this.props.onChange) this.props.onChange(this);
if (this.refs.input) this.refs.input.setValue(this.valueForInput(this.state.value));
}
},
}
onResize () {
handleResize = () => {
const {left, right} = ReactDOM.findDOMNode(this.refs.progressbar).getBoundingClientRect();
this.setState({sliderStart: left, sliderLength: right - left});
},
};
onSliderFocus () {
handleSliderFocus = () => {
utils.events.addEventsToDocument(this.getKeyboardEvents());
},
};
onSliderBlur () {
handleSliderBlur = () => {
utils.events.removeEventsFromDocument(this.getKeyboardEvents());
},
};
onInputChange () {
handleInputChange = () => {
this.setState({value: this.trimValue(this.refs.input.getValue()) });
},
};
onKeyDown (event) {
handleKeyDown = (event) => {
if ([13, 27].indexOf(event.keyCode) !== -1) ReactDOM.findDOMNode(this).blur();
if (event.keyCode === 38) this.addToValue(this.props.step);
if (event.keyCode === 40) this.addToValue(-this.props.step);
if (event.keyCode !== 9) utils.events.pauseEvent(event);
},
};
onMouseDown (event) {
handleMouseDown = (event) => {
utils.events.addEventsToDocument(this.getMouseEventMap());
this.start(utils.events.getMousePosition(event));
utils.events.pauseEvent(event);
},
};
onTouchStart (event) {
handleTouchStart = (event) => {
this.start(utils.events.getTouchPosition(event));
utils.events.addEventsToDocument(this.getTouchEventMap());
utils.events.pauseEvent(event);
},
};
onMouseMove (event) {
handleMouseMove = (event) => {
utils.events.pauseEvent(event);
this.move(utils.events.getMousePosition(event));
},
};
onTouchMove (event) {
handleTouchMove = (event) => {
this.move(utils.events.getTouchPosition(event));
},
};
onMouseUp () {
handleMouseUp = () => {
this.end(this.getMouseEventMap());
},
};
onTouchEnd () {
handleTouchEnd = () => {
this.end(this.getTouchEventMap());
},
};
getMouseEventMap () {
return {
mousemove: this.onMouseMove,
mouseup: this.onMouseUp
mousemove: this.handleMouseMove,
mouseup: this.handleMouseUp
};
},
}
getTouchEventMap () {
return {
touchmove: this.onTouchMove,
touchend: this.onTouchEnd
touchmove: this.handleTouchMove,
touchend: this.handleTouchEnd
};
},
}
getKeyboardEvents () {
return {
keydown: this.onKeyDown
keydown: this.handleKeyDown
};
},
}
start (position) {
this.setState({pressed: true, value: this.positionToValue(position)});
},
}
move (position) {
this.setState({value: this.positionToValue(position)});
},
}
end (revents) {
utils.events.removeEventsFromDocument(revents);
this.setState({pressed: false});
},
}
positionToValue (position) {
let { sliderStart: start, sliderLength: length } = this.state;
let { max, min } = this.props;
return this.trimValue((position.x - start) / length * (max - min) + min);
},
}
trimValue (value) {
if (value < this.props.min) return this.props.min;
if (value > this.props.max) return this.props.max;
return utils.round(value, this.stepDecimals());
},
}
stepDecimals () {
return (this.props.step.toString().split('.')[1] || []).length;
},
}
addToValue (value) {
this.setState({value: this.trimValue(this.state.value + value)});
},
}
valueForInput (value) {
const decimals = this.stepDecimals();
return decimals > 0 ? value.toFixed(decimals) : value.toString();
},
}
knobOffset () {
let { max, min } = this.props;
return this.state.sliderLength * (this.state.value - min) / (max - min);
},
}
renderSnaps () {
if (this.props.snaps) {
@ -185,7 +179,7 @@ export default React.createClass({
</div>
);
}
},
}
renderInput () {
if (this.props.editable) {
@ -193,11 +187,11 @@ export default React.createClass({
<Input
ref='input'
className={style.input}
onChange={this.onInputChange}
onChange={this.handleInputChange}
value={this.valueForInput(this.state.value)} />
);
}
},
}
render () {
let knobStyles = utils.prefixer({transform: `translateX(${this.knobOffset()}px)`});
@ -212,21 +206,21 @@ export default React.createClass({
data-react-toolbox='slider'
className={style.root + className}
tabIndex='0'
onFocus={this.onSliderFocus}
onBlur={this.onSliderBlur} >
onFocus={this.handleSliderFocus}
onBlur={this.handleSliderBlur} >
<div
ref='slider'
className={style.container}
onTouchStart={this.onTouchStart}
onMouseDown={this.onMouseDown} >
onTouchStart={this.handleTouchStart}
onMouseDown={this.handleMouseDown} >
<div
ref='knob'
className={style.knob}
style={knobStyles}
onMouseDown={this.onMouseDown}
onTouchStart={this.onTouchStart} >
onMouseDown={this.handleMouseDown}
onTouchStart={this.handleTouchStart} >
<div className={style.innerknob} data-value={parseInt(this.state.value)}></div>
</div>
@ -245,13 +239,15 @@ export default React.createClass({
{ this.renderInput() }
</div>
);
},
}
getValue () {
return this.state.value;
},
}
setValue (value) {
this.setState({value: value});
}
});
}
export default Slider;

View File

@ -3,30 +3,26 @@ import style from './style';
import Button from '../button';
import FontIcon from '../font_icon';
export default React.createClass({
displayName: 'Slider',
propTypes: {
class Snackbar extends React.Component {
static propTypes = {
action: React.PropTypes.string,
icon: React.PropTypes.string,
label: React.PropTypes.string,
onClick: React.PropTypes.func,
timeout: React.PropTypes.number,
type: React.PropTypes.string
},
};
getInitialState () {
return {
active: false
};
},
state = {
active: false
};
handleClick (event) {
handleClick = (event) => {
this.setState({active: false});
if (this.props.onClick) {
this.props.onClick(event, this);
}
},
};
renderButton () {
if (this.props.action) {
@ -39,7 +35,7 @@ export default React.createClass({
/>
);
}
},
}
render () {
let className = `${style.root} ${style[this.props.type]}`;
@ -53,12 +49,11 @@ export default React.createClass({
{ this.renderButton() }
</div>
);
},
}
// -- Extends
hide () {
this.setState({active: false});
},
}
show () {
this.setState({active: true});
@ -68,4 +63,6 @@ export default React.createClass({
}, this.props.timeout * 1000);
}
}
});
}
export default Snackbar;

View File

@ -2,6 +2,7 @@
@import "./config";
.root {
z-index: $z-index-higher;
position: fixed;
bottom: 0;
left: $snackbar-horizontal-offset;

View File

@ -1,15 +1,10 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Ripple from '../ripple';
import style from './style';
import events from '../utils/events';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Switch',
propTypes: {
class Switch extends React.Component {
static propTypes = {
checked: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
@ -18,38 +13,36 @@ export default React.createClass({
onBlur: React.PropTypes.func,
onChange: React.PropTypes.func,
onFocus: React.PropTypes.func
},
};
getDefaultProps () {
return {
checked: false,
className: '',
disabled: false
};
},
static defaultProps = {
checked: false,
className: '',
disabled: false
};
getInitialState () {
return { checked: this.props.checked };
},
state = {
checked: this.props.checked
};
handleChange (event) {
handleChange = (event) => {
this.setState({checked: !this.state.checked}, () => {
if (this.props.onChange) this.props.onChange(event, this);
});
},
};
handleClick (event) {
handleClick = (event) => {
events.pauseEvent(event);
if (!this.props.disabled) this.handleChange(event);
},
};
handleInputClick (event) {
handleInputClick = (event) => {
events.pauseEvent(event);
},
};
handleMouseDown (event) {
handleMouseDown = (event) => {
if (!this.props.disabled) this.refs.ripple.start(event);
},
};
render () {
let labelClassName = style[this.props.disabled ? 'disabled' : 'field'];
@ -79,21 +72,23 @@ export default React.createClass({
{ this.props.label ? <span className={style.text}>{this.props.label}</span> : null }
</label>
);
},
}
blur () {
this.refs.input.blur();
},
}
focus () {
this.refs.input.focus();
},
}
getValue () {
return this.state.checked;
},
}
setValue (value) {
this.setState({checked: value});
}
});
}
export default Switch;

View File

@ -1,11 +1,8 @@
import React from 'react';
import style from './style';
export default React.createClass({
displayName: 'Tab',
propTypes: {
class Tab extends React.Component {
static propTypes = {
active: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
@ -13,21 +10,19 @@ export default React.createClass({
label: React.PropTypes.string.isRequired,
onActive: React.PropTypes.func,
tabIndex: React.PropTypes.number
},
};
getDefaultProps () {
return {
className: ''
};
},
static defaultProps = {
className: ''
};
componentDidMount () {
this.active(this.props.active);
},
}
componentWillReceiveProps (next_props) {
if (next_props.active) this.active(next_props.active);
},
}
render () {
let className = `${style.tab} ${this.props.className}`;
@ -44,7 +39,7 @@ export default React.createClass({
{ this.props.children }
</section>
);
},
}
active (value) {
this.setState({active: value});
@ -52,4 +47,6 @@ export default React.createClass({
this.props.onActive(this);
}
}
});
}
export default Tab;

View File

@ -1,37 +1,28 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Tabs',
propTypes: {
class Tabs extends React.Component {
static propTypes = {
className: React.PropTypes.string,
index: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func
},
};
getDefaultProps () {
return {
className: '',
index: 0
};
},
static defaultProps = {
className: '',
index: 0
};
getInitialState () {
return {
index: this.props.index,
pointer: {}
};
},
state = {
index: this.props.index,
pointer: {}
};
componentDidMount () {
this.setState({
pointer: this._pointerPosition(this.state.index, this.refs.navigation)
});
},
}
componentWillReceiveProps (next_props) {
const index = next_props.index || this.state.index;
@ -39,7 +30,7 @@ export default React.createClass({
index: index,
pointer: this._pointerPosition(index, this.refs.navigation)
});
},
}
_pointerPosition (index = 0, navigation) {
const startPoint = this.refs.tabs.getBoundingClientRect().left;
@ -50,21 +41,21 @@ export default React.createClass({
left: `${label.left - startPoint}px`,
width: `${label.width}px`
};
},
}
onClick (index) {
handleClick = (index) => {
this.setState({
index: index,
pointer: this._pointerPosition(index, this.refs.navigation)
});
if (this.props.onChange) this.props.onChange(this);
},
};
renderLabels (labels) {
return labels.map((props) => {
return <label {...props}>{ props.label }</label>;
});
},
}
render () {
let labels = [];
@ -81,7 +72,7 @@ export default React.createClass({
className: className,
label: tab.props.label,
key: index,
onClick: !tab.props.disabled ? this.onClick.bind(null, index) : null
onClick: !tab.props.disabled ? this.handleClick.bind(this, index) : null
});
return React.cloneElement(tab, {active: active, key: index, tabIndex: index });
@ -99,7 +90,7 @@ export default React.createClass({
{ tabs }
</div>
);
},
}
active (value) {
this.setState({active: value});
@ -107,4 +98,6 @@ export default React.createClass({
this.props.onActive(this);
}
}
});
}
export default Tabs;

View File

@ -1,20 +1,13 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Face',
getDefaultProps () {
return {
active: null,
numbers: [],
radius: 0,
twoDigits: false
};
},
class Face extends React.Component {
static defaultProps = {
active: null,
numbers: [],
radius: 0,
twoDigits: false
};
numberStyle (rad, num) {
return {
@ -22,14 +15,14 @@ export default React.createClass({
left: (rad + rad * Math.sin(360 * (Math.PI / 180) / 12 * (num - 1)) + this.props.spacing),
top: (rad - rad * Math.cos(360 * (Math.PI / 180) / 12 * (num - 1)) + this.props.spacing)
};
},
}
faceStyle () {
return {
height: this.props.radius * 2,
width: this.props.radius * 2
};
},
}
renderNumber (number, idx) {
let className = style.number;
@ -43,7 +36,7 @@ export default React.createClass({
{ this.props.twoDigits ? ('0' + number).slice(-2) : number }
</span>
);
},
}
render () {
return (
@ -54,8 +47,10 @@ export default React.createClass({
onMouseDown={this.props.onMouseDown}
style={this.faceStyle()}
>
{ this.props.numbers.map(this.renderNumber)}
{ this.props.numbers.map(this.renderNumber.bind(this))}
</div>
);
}
});
}
export default Face;

View File

@ -1,102 +1,95 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import utils from '../../utils';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Hand',
propTypes: {
class Hand extends React.Component {
static propTypes = {
className: React.PropTypes.string,
angle: React.PropTypes.number,
onMove: React.PropTypes.func,
onMoved: React.PropTypes.func
},
};
getDefaultProps () {
return {
className: '',
angle: 0,
length: 0,
origin: {}
};
},
static defaultProps = {
className: '',
angle: 0,
length: 0,
origin: {}
};
getInitialState () {
return { knobWidth: 0 };
},
state = {
knobWidth: 0
};
componentDidMount () {
this.setState({knobWidth: this.refs.knob.offsetWidth});
},
}
getMouseEventMap () {
return {
mousemove: this.onMouseMove,
mouseup: this.onMouseUp
mousemove: this.handleMouseMove,
mouseup: this.handleMouseUp
};
},
}
getTouchEventMap () {
return {
touchmove: this.onTouchMove,
touchend: this.onTouchEnd
touchmove: this.handleTouchMove,
touchend: this.handleTouchEnd
};
},
}
onMouseMove (event) {
handleMouseMove = (event) => {
this.move(utils.events.getMousePosition(event));
},
};
onTouchMove (event) {
handleTouchMove = (event) => {
this.move(utils.events.getTouchPosition(event));
},
};
onMouseUp () {
handleMouseUp = () => {
this.end(this.getMouseEventMap());
},
};
onTouchEnd () {
handleTouchEnd = () => {
this.end(this.getTouchEventMap());
},
};
mouseStart (event) {
utils.events.addEventsToDocument(this.getMouseEventMap());
this.move(utils.events.getMousePosition(event));
},
}
touchStart (event) {
utils.events.addEventsToDocument(this.getTouchEventMap());
this.move(utils.events.getTouchPosition(event));
utils.events.pauseEvent(event);
},
}
getPositionRadius (position) {
let x = this.props.origin.x - position.x;
let y = this.props.origin.y - position.y;
return Math.sqrt(x * x + y * y);
},
}
trimAngleToValue (angle) {
return this.props.step * Math.round(angle / this.props.step);
},
}
positionToAngle (position) {
return utils.angle360FromPositions(this.props.origin.x, this.props.origin.y, position.x, position.y);
},
}
end (events) {
if (this.props.onMoved) this.props.onMoved();
utils.events.removeEventsFromDocument(events);
},
}
move (position) {
let degrees = this.trimAngleToValue(this.positionToAngle(position));
let radius = this.getPositionRadius(position);
if (this.props.onMove) this.props.onMove(degrees === 360 ? 0 : degrees, radius);
},
}
render () {
const className = `${style.hand} ${this.props.className}`;
@ -111,4 +104,6 @@ export default React.createClass({
</div>
);
}
});
}
export default Hand;

View File

@ -1,5 +1,4 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import utils from '../../utils';
import Face from './face';
import Hand from './hand';
@ -9,25 +8,19 @@ const innerNumbers = [12, ...utils.range(1, 12)];
const innerSpacing = 1.7;
const step = 360 / 12;
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Hours',
propTypes: {
class Hours extends React.Component {
static propTypes = {
format: React.PropTypes.oneOf(['24hr', 'ampm']),
onChange: React.PropTypes.func,
onHandMoved: React.PropTypes.func,
selected: React.PropTypes.number
},
};
getInitialState () {
return {
inner: this.props.format === '24hr' && this.props.selected > 0 && this.props.selected <= 12
};
},
state = {
inner: this.props.format === '24hr' && this.props.selected > 0 && this.props.selected <= 12
};
onHandMove (degrees, radius) {
handleHandMove = (degrees, radius) => {
let currentInner = radius < this.props.radius - this.props.spacing * innerSpacing;
if (this.props.format === '24hr' && this.state.inner !== currentInner) {
this.setState({inner: currentInner}, () => {
@ -36,15 +29,15 @@ export default React.createClass({
} else {
this.props.onChange(this.valueFromDegrees(degrees));
}
},
};
onMouseDown (event) {
handleMouseDown = (event) => {
this.refs.hand.mouseStart(event);
},
};
onTouchStart (event) {
handleTouchStart = (event) => {
this.refs.hand.touchStart(event);
},
};
valueFromDegrees (degrees) {
if (this.props.format === 'ampm' || this.props.format === '24hr' && this.state.inner) {
@ -52,14 +45,14 @@ export default React.createClass({
} else {
return outerNumbers[degrees / step];
}
},
}
renderInnerFace (innerRadius) {
if (this.props.format === '24hr') {
return (
<Face
onTouchStart={this.onTouchStart}
onMouseDown={this.onMouseDown}
onTouchStart={this.handleTouchStart}
onMouseDown={this.handleMouseDown}
numbers={innerNumbers}
spacing={this.props.spacing}
radius={innerRadius}
@ -67,7 +60,7 @@ export default React.createClass({
/>
);
}
},
}
render () {
const { format, selected, radius, spacing, center, onHandMoved } = this.props;
@ -76,8 +69,8 @@ export default React.createClass({
return (
<div>
<Face
onTouchStart={this.onTouchStart}
onMouseDown={this.onMouseDown}
onTouchStart={this.handleTouchStart}
onMouseDown={this.handleMouseDown}
numbers={is24hr ? outerNumbers : innerNumbers}
spacing={spacing}
radius={radius}
@ -88,7 +81,7 @@ export default React.createClass({
<Hand ref='hand'
angle={selected * step}
length={(this.state.inner ? radius - spacing * innerSpacing : radius) - spacing}
onMove={this.onHandMove}
onMove={this.handleHandMove}
onMoved={onHandMoved}
origin={center}
step={step}
@ -96,4 +89,6 @@ export default React.createClass({
</div>
);
}
});
}
export default Hours;

View File

@ -1,70 +1,69 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import time from '../../utils/time';
import Hours from './hours';
import Minutes from './minutes';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Clock',
propTypes: {
class Clock extends React.Component {
static propTypes = {
className: React.PropTypes.string,
display: React.PropTypes.oneOf(['hours', 'minutes']),
format: React.PropTypes.oneOf(['24hr', 'ampm']),
initialTime: React.PropTypes.object,
onChange: React.PropTypes.func
},
};
getDefaultProps () {
return {
className: '',
display: 'hours',
format: '24hr',
initialTime: new Date()
};
},
static defaultProps = {
className: '',
display: 'hours',
format: '24hr',
initialTime: new Date()
};
getInitialState () {
return {
center: {x: null, y: null},
radius: 0,
time: this.props.initialTime
};
},
state = {
center: {x: null, y: null},
radius: 0,
time: this.props.initialTime
};
componentDidMount () {
window.addEventListener('resize', this.calculateShape);
this.calculateShape();
},
window.addEventListener('resize', this.handleCalculateShape);
this.handleCalculateShape();
}
componentWillUnmount () {
window.removeEventListener('resize', this.calculateShape);
},
window.removeEventListener('resize', this.handleCalculateShape);
}
onHourChange (hours) {
handleHourChange = (hours) => {
if (this.state.time.getHours() !== hours) {
const newTime = time.setHours(this.state.time, this.adaptHourToFormat(hours));
this.setState({time: newTime});
if (this.props.onChange) this.props.onChange(newTime);
}
},
};
onMinuteChange (minutes) {
handleMinuteChange = (minutes) => {
if (this.state.time.getMinutes() !== minutes) {
const newTime = time.setMinutes(this.state.time, minutes);
this.setState({time: newTime});
if (this.props.onChange) this.props.onChange(newTime);
}
},
};
handleCalculateShape = () => {
let { top, left, width } = this.refs.wrapper.getBoundingClientRect();
this.setState({
center: { x: left + width / 2, y: top + width / 2 },
radius: width / 2
});
};
toggleTimeMode () {
const newTime = time.toggleTimeMode(this.state.time);
this.setState({time: newTime});
if (this.props.onChange) this.props.onChange(newTime);
},
}
adaptHourToFormat (hour) {
if (this.props.format === 'ampm') {
@ -76,40 +75,32 @@ export default React.createClass({
} else {
return hour;
}
},
calculateShape () {
let { top, left, width } = this.refs.wrapper.getBoundingClientRect();
this.setState({
center: { x: left + width / 2, y: top + width / 2 },
radius: width / 2
});
},
}
renderHours () {
return (
<Hours
center={this.state.center}
format={this.props.format}
onChange={this.onHourChange}
onChange={this.handleHourChange}
radius={this.state.radius}
selected={this.state.time.getHours()}
spacing={this.state.radius * 0.18}
/>
);
},
}
renderMinutes () {
return (
<Minutes
center={this.state.center}
onChange={this.onMinuteChange}
onChange={this.handleMinuteChange}
radius={this.state.radius}
selected={this.state.time.getMinutes()}
spacing={this.state.radius * 0.18}
/>
);
},
}
render () {
return (
@ -121,4 +112,6 @@ export default React.createClass({
</div>
);
}
});
}
export default Clock;

View File

@ -1,5 +1,4 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import utils from '../../utils';
import style from './style';
import Face from './face';
@ -8,41 +7,35 @@ import Hand from './hand';
const minutes = utils.range(0, 60, 5);
const step = 360 / 60;
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'Minutes',
propTypes: {
class Minutes extends React.Component {
static propTypes = {
selected: React.PropTypes.number,
onChange: React.PropTypes.func
},
};
getDefaultProps () {
return {
selected: 0,
onChange: null
};
},
static defaultProps = {
selected: 0,
onChange: null
};
onHandMove (degrees) {
handleHandMove = (degrees) => {
this.props.onChange(degrees / step);
},
};
onMouseDown (event) {
handleMouseDown = (event) => {
this.refs.hand.mouseStart(event);
},
};
onTouchStart (event) {
handleTouchStart = (event) => {
this.refs.hand.touchStart(event);
},
};
render () {
return (
<div>
<Face
onTouchStart={this.onTouchStart}
onMouseDown={this.onMouseDown}
onTouchStart={this.handleTouchStart}
onMouseDown={this.handleMouseDown}
numbers={minutes}
spacing={this.props.spacing}
radius={this.props.radius}
@ -53,11 +46,13 @@ export default React.createClass({
className={minutes.indexOf(this.props.selected) === -1 ? style.small : ''}
angle={this.props.selected * step}
length={this.props.radius - this.props.spacing}
onMove={this.onHandMove}
onMove={this.handleHandMove}
origin={this.props.center}
step={step}
/>
</div>
);
}
});
}
export default Minutes;

View File

@ -1,70 +1,61 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import style from './style';
import time from '../utils/time';
import Clock from './clock';
import Dialog from '../dialog';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'TimePickerDialog',
propTypes: {
class TimePickerDialog extends React.Component {
static propTypes = {
className: React.PropTypes.string,
initialTime: React.PropTypes.object,
format: React.PropTypes.oneOf(['24hr', 'ampm']),
onTimeSelected: React.PropTypes.func
},
};
getDefaultProps () {
return {
static defaultProps = {
className: '',
initialTime: new Date(),
format: '24hr'
};
},
};
getInitialState () {
return {
display: 'hours',
time: this.props.initialTime,
actions: [
{ label: 'Cancel', className: style.button, onClick: this.onTimeCancel },
{ label: 'Ok', className: style.button, onClick: this.onTimeSelected }
]
};
},
state = {
display: 'hours',
time: this.props.initialTime,
actions: [
{ label: 'Cancel', className: style.button, onClick: this.onTimeCancel.bind(this) },
{ label: 'Ok', className: style.button, onClick: this.onTimeSelected.bind(this) }
]
};
onClockChange (newTime) {
handleClockChange = (newTime) => {
this.setState({time: newTime});
},
};
displayMinutes = () => {
this.setState({display: 'minutes'});
};
displayHours = () => {
this.setState({display: 'hours'});
};
toggleTimeMode = () => {
this.refs.clock.toggleTimeMode();
};
onTimeCancel () {
this.refs.dialog.hide();
},
}
onTimeSelected () {
if (this.props.onTimeSelected) this.props.onTimeSelected(this.state.time);
this.refs.dialog.hide();
},
displayMinutes () {
this.setState({display: 'minutes'});
},
displayHours () {
this.setState({display: 'hours'});
},
toggleTimeMode () {
this.refs.clock.toggleTimeMode();
},
}
show () {
this.refs.dialog.show();
setTimeout(this.refs.clock.calculateShape, 1000);
},
setTimeout(this.refs.clock.handleCalculateShape, 1000);
}
formatHours () {
if (this.props.format === 'ampm') {
@ -72,7 +63,7 @@ export default React.createClass({
} else {
return this.state.time.getHours();
}
},
}
renderAMPMLabels () {
if (this.props.format === 'ampm') {
@ -83,7 +74,7 @@ export default React.createClass({
</div>
);
}
},
}
render () {
const display = `display-${this.state.display}`;
@ -107,9 +98,11 @@ export default React.createClass({
display={this.state.display}
format={this.props.format}
initialTime={this.props.initialTime}
onChange={this.onClockChange}
onChange={this.handleClockChange}
/>
</Dialog>
);
}
});
}
export default TimePickerDialog;

View File

@ -1,48 +1,39 @@
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import time from '../utils/time';
import style from './style';
import events from '../utils/events';
import Input from '../input';
import TimeDialog from './dialog';
export default React.createClass({
mixins: [PureRenderMixin],
displayName: 'TimePicker',
propTypes: {
class TimePicker extends React.Component {
static propTypes = {
format: React.PropTypes.oneOf(['24hr', 'ampm']),
value: React.PropTypes.object
},
};
getDefaultProps () {
return {
format: '24hr'
};
},
static defaultProps = {
format: '24hr'
};
getInitialState () {
return {
value: this.props.value
};
},
state = {
value: this.props.value
};
onTimeSelected (newTime) {
onTimeSelected = (newTime) => {
this.refs.input.setValue(time.formatTime(newTime, this.props.format));
this.setState({value: newTime});
},
};
openTimeDialog (event) {
openTimeDialog = (event) => {
events.pauseEvent(event);
this.refs.dialog.show();
},
};
formatTime () {
if (this.state.value) {
return time.formatTime(this.state.value, this.props.format);
}
},
}
render () {
return (
@ -64,13 +55,15 @@ export default React.createClass({
/>
</div>
);
},
}
getValue () {
return this.state.value;
},
}
setValue (value) {
this.setState({value: value});
}
});
}
export default TimePicker;

View File

@ -7,16 +7,14 @@ import React from 'react';
import Button from 'react-toolbox/components/button';
import Form from 'react-toolbox/components/form';
const App = React.createClass({
getInitialState () {
return {
fields: [
{ ref: 'username', label: 'Your username', required: true},
{ ref: 'password', type: 'password', label: 'Your password', required: true},
{ type: 'submit', label: 'Login', disabled: true}
]
};
},
class App extends React.Component {
state = {
fields: [
{ ref: 'username', label: 'Your username', required: true},
{ ref: 'password', type: 'password', label: 'Your password', required: true},
{ type: 'submit', label: 'Login', disabled: true}
]
};
render () {
return (
@ -28,6 +26,6 @@ const App = React.createClass({
</app>
);
}
});
}
React.render(<App />, document.body);

View File

@ -26,7 +26,7 @@ module.exports = {
module: {
noParse: [node_modules + '/react/dist/*.js'],
loaders: [
{ test: /(\.js|\.jsx)$/, exclude: /(node_modules)/, loader: 'babel?optional=runtime'},
{ test: /(\.js|\.jsx)$/, exclude: /(node_modules)/, loader: 'babel?optional=runtime&stage=0&loose=all'},
{ test: /\.cjsx$/, loader: 'coffee-jsx-loader'},
{ test: /\.coffee$/, loader: 'coffee-jsx-loader'},
{ test: /\.styl$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader!stylus-loader!')}

View File

@ -3,11 +3,18 @@
"version": "0.10.20",
"description": "A set of complementary tools to ReactJS.",
"homepage": "http://zetapath.com",
"author": " <hi@soyjavi.com> ()",
"author": "React Toolbox Team (http://github.com/react-toolbox)",
"contributors": [
{"name": "Javi Jimenez Villar", "url": "http://soyjavi.com/", "email": "hi@soyjavi.com"},
{"name": "Javi Velasco Arjona", "url": "http://javivelasco.com/", "email": "javier.velasco86@gmail.com"}
{
"name": "Javi Jimenez Villar",
"url": "http://soyjavi.com/",
"email": "hi@soyjavi.com"
},
{
"name": "Javi Velasco Arjona",
"url": "http://javivelasco.com/",
"email": "javier.velasco86@gmail.com"
}
],
"main": "./components",
"directories": {
@ -17,6 +24,7 @@
"start": "npm run build & webpack-dev-server --hot",
"build": "webpack",
"watch": "webpack --watch",
"lint": "eslint ./components/**/*.jsx",
"deploy": "NODE_ENV=production webpack -p",
"test": "karma start",
"test:watch": "karma start --no-single-run"
@ -35,13 +43,13 @@
"license": "MIT",
"dependencies": {
"react": "^0.14",
"react-addons-pure-render-mixin": "^0.14.0",
"react-addons-css-transition-group": "^0.14.0",
"react-dom": "^0.14.0"
},
"devDependencies": {
"autoprefixer-core": "^5.1.11",
"babel-core": "^5.8.23",
"babel-eslint": "^4.1.3",
"babel-loader": "^5.3.2",
"babel-runtime": "^5.8.20",
"css-loader": "^0.16.0",
@ -55,6 +63,7 @@
"karma-mocha": "^0.2.0",
"karma-phantomjs-launcher": "~0.1",
"karma-webpack": "^1.7.0",
"mocha": "^2.3.3",
"node-libs-browser": "^0.5.2",
"node-sass": "^3.3.3",
"normalize.css": "^3.0.3",
@ -66,7 +75,7 @@
"sinon": "git://github.com/cjohansen/Sinon.JS#sinon-2.0",
"style-loader": "^0.12.3",
"webpack": "^1.12.0",
"webpack-dev-server": "*"
"webpack-dev-server": "^1.12.1"
},
"repository": "github:react-toolbox/react-toolbox"
}

View File

@ -1,25 +1,21 @@
import React from 'react';
import Autocomplete from '../../components/autocomplete';
export default React.createClass({
displayName: 'AutocompleteTest',
class AutocompleteTest extends React.Component {
state = {
countries: ['Spain', 'England', 'USA', 'Thailand', 'Tongo', 'Slovenia'],
countries_obj: {
'ES-es': 'Spain',
'TH-th': 'Thailand',
'EN-gb': 'England',
'EN-en': 'USA'
}
};
getInitialState () {
return {
countries: ['Spain', 'England', 'USA', 'Thailand', 'Tongo', 'Slovenia'],
countries_obj: {
'ES-es': 'Spain',
'TH-th': 'Thailand',
'EN-gb': 'England',
'EN-en': 'USA'
}
};
},
onAutocompleteValues () {
onAutocompleteValues = () => {
console.log(this.refs.autocomplete_multiple.getValue());
console.log(this.refs.autocomplete_simple.getValue());
},
};
render () {
const countries_selected = ['USA', 'Tongo'];
@ -47,4 +43,6 @@ export default React.createClass({
</section>
);
}
});
}
export default AutocompleteTest;

View File

@ -1,23 +1,20 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import Button from '../../components/button';
export default React.createClass({
displayName: 'ButtonTest',
const ButtonTest = () => (
<section>
<h5>Buttons</h5>
<p>lorem ipsum...</p>
<Button kind="raised" primary label="Bookmark" icon="bookmark" />
<Button kind="flat" accent label="Inbox" icon="inbox" />
<Button kind="floating" primary icon="add" />
<Button kind="floating" primary disabled icon="add" />
<Button kind="floating" accent mini icon="add" />
<Button kind="flat" primary icon="add" label="Add this" />
<Button kind="raised" primary label="Bookmark" icon="bookmark" loading />
<Button kind="flat" disabled icon="add" label="Add this" />
</section>
);
render () {
return (
<section>
<h5>Buttons</h5>
<p>lorem ipsum...</p>
<Button kind="raised" primary label="Bookmark" icon="bookmark" />
<Button kind="flat" accent label="Inbox" icon="inbox" />
<Button kind="floating" primary icon="add" />
<Button kind="floating" primary disabled icon="add" />
<Button kind="floating" accent mini icon="add" />
<Button kind="flat" primary icon="add" label="Add this" />
<Button kind="raised" primary label="Bookmark" icon="bookmark" loading />
<Button kind="flat" disabled icon="add" label="Add this" />
</section>
);
}
});
export default ButtonTest;

View File

@ -1,22 +1,20 @@
import React from 'react';
import Card from '../../components/card';
export default React.createClass({
displayName: 'CardTest',
onClick () {
class CardTest extends React.Component {
onClick = () => {
console.log('onClick', arguments);
},
};
onActionClick () {
console.log('onClick', arguments);
},
}
render () {
const text = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.';
const actions = [
{ label: 'Save', icon: 'add', className: 'flat accent', onClick: this.onActionClick },
{ label: 'Close', className: 'flat', onClick: this.onActionClick }];
{ label: 'Save', icon: 'add', className: 'flat accent', onClick: this.onActionClick.bind(this) },
{ label: 'Close', className: 'flat', onClick: this.onActionClick.bind(this) }];
return (
<section>
@ -36,4 +34,6 @@ export default React.createClass({
</section>
);
}
});
}
export default CardTest;

View File

@ -1,18 +1,18 @@
import React from 'react';
import Checkbox from '../../components/checkbox';
export default React.createClass({
handleChange (event, instance) {
class CheckboxTest extends React.Component {
handleChange = (event, instance) => {
console.log('Changed!', instance.getValue());
},
};
handleFocus () {
handleFocus = () => {
console.log('Focused');
},
};
handleBlur () {
handleBlur = () => {
console.log('Blur');
},
};
render () {
return (
@ -44,4 +44,6 @@ export default React.createClass({
</section>
);
}
});
}
export default CheckboxTest;

View File

@ -2,36 +2,34 @@ import React from 'react';
import Button from '../../components/button';
import Dialog from '../../components/dialog';
export default React.createClass({
displayName: 'DialogTest',
getInitialState () {
return {
title: 'Use Google\'s location service?',
actions: [
{ label: 'Disagree', type: 'flat', className: 'primary', onClick: this.onClose },
{ label: 'Agree', type: 'flat', className: 'primary', onClick: this.onClose }]
};
},
class DialogTest extends React.Component {
state = {
title: 'Use Google\'s location service?',
actions: [
{ label: 'Disagree', type: 'flat', className: 'primary', onClick: this.onClose.bind(this) },
{ label: 'Agree', type: 'flat', className: 'primary', onClick: this.onClose.bind(this) }]
};
onClose () {
this.refs.dialog.hide();
},
}
onShow () {
this.refs.dialog.show();
},
}
render () {
return (
<section>
<h5>Dialog</h5>
<p>lorem ipsum...</p>
<Button kind='raised' label='Show Dialog' onClick={this.onShow} />
<Button kind='raised' label='Show Dialog' onClick={this.onShow.bind(this)} />
<Dialog ref='dialog' type='small' title={this.state.title} actions={this.state.actions}>
<p>Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.</p>
</Dialog>
</section>
);
}
});
}
export default DialogTest;

View File

@ -2,12 +2,10 @@ import React from 'react';
import Button from '../../components/button';
import Drawer from '../../components/drawer';
export default React.createClass({
displayName: 'DrawerTest',
onClick (ref, method) {
class DrawerTest extends React.Component {
handleClick = (ref, method) => {
this.refs[ref][method]();
},
};
render () {
return (
@ -22,14 +20,16 @@ export default React.createClass({
</Drawer>
<Drawer ref='right' type='right'>
<Button label='Close' onClick={this.onClick.bind(null, 'right', 'hide')} />
<Button label='Close' onClick={this.handleClick.bind(this, 'right', 'hide')} />
</Drawer>
<nav>
<Button accent label='Drawer left hideable' kind='raised' onClick={this.onClick.bind(null, 'left', 'show')} />
<Button primary label='Drawer right' kind='raised' onClick={this.onClick.bind(null, 'right', 'show')} />
<Button accent label='Drawer left hideable' kind='raised' onClick={this.handleClick.bind(this, 'left', 'show')} />
<Button primary label='Drawer right' kind='raised' onClick={this.handleClick.bind(this, 'right', 'show')} />
</nav>
</section>
);
}
});
}
export default DrawerTest;

View File

@ -1,25 +1,21 @@
import React from 'react';
import Dropdown from '../../components/dropdown';
export default React.createClass({
displayName: 'DropdownTest',
class DropdownTest extends React.Component {
state = {
countries: [
{ value: 'ES-es', label: 'Spain', img: 'http://' },
{ value: 'TH-th', label: 'Thailand', img: 'http://' },
{ value: 'EN-gb', label: 'England', img: 'http://' },
{ value: 'EN-en', label: 'USA', img: 'http://' },
{ value: 'FR-fr', label: 'France', img: 'http://' }
],
selected: 'TH-th'
};
getInitialState () {
return {
countries: [
{ value: 'ES-es', label: 'Spain', img: 'http://' },
{ value: 'TH-th', label: 'Thailand', img: 'http://' },
{ value: 'EN-gb', label: 'England', img: 'http://' },
{ value: 'EN-en', label: 'USA', img: 'http://' },
{ value: 'FR-fr', label: 'France', img: 'http://' }
],
selected: 'TH-th'
};
},
onChange (dropdown) {
handleChange = (dropdown) => {
console.log('[DROPDOWN]', dropdown.getValue());
},
};
customDropdownItem (data) {
const style = {
@ -38,18 +34,20 @@ export default React.createClass({
</div>
</div>
);
},
}
render () {
return (
<section>
<h5>Dropdown</h5>
<p>lorem ipsum...</p>
<Dropdown dataSource={this.state.countries} label="Countries" onChange={this.onChange}/>
<Dropdown dataSource={this.state.countries} disabled={true} onChange={this.onChange}/>
<Dropdown dataSource={this.state.countries} value={this.state.selected} onChange={this.onChange}/>
<Dropdown dataSource={this.state.countries} value={this.state.selected} template={this.customDropdownItem} onChange={this.onChange}/>
<Dropdown dataSource={this.state.countries} label="Countries" onChange={this.handleChange}/>
<Dropdown dataSource={this.state.countries} disabled={true} onChange={this.handleChange}/>
<Dropdown dataSource={this.state.countries} value={this.state.selected} onChange={this.handleChange}/>
<Dropdown dataSource={this.state.countries} value={this.state.selected} template={this.customDropdownItem} onChange={this.handleChange}/>
</section>
);
}
});
}
export default DropdownTest;

View File

@ -1,21 +1,18 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import FontIcon from '../../components/font_icon';
export default React.createClass({
displayName: 'FontIconTest',
const FontIconTest = () => (
<section>
<h2>Font Icon</h2>
<p>lorem ipsum...</p>
render () {
return (
<section>
<h2>Font Icon</h2>
<p>lorem ipsum...</p>
<FontIcon value="add"/>
<FontIcon value="access_alarm"/>
<FontIcon value="explore"/>
<FontIcon value="zoom_in"/>
<FontIcon value="input"/>
</section>
);
<FontIcon value="add"/>
<FontIcon value="access_alarm"/>
<FontIcon value="explore"/>
<FontIcon value="zoom_in"/>
<FontIcon value="input"/>
</section>
);
}
});
export default FontIconTest;

View File

@ -1,32 +1,28 @@
import React from 'react';
import Form from '../../components/form';
export default React.createClass({
displayName: 'FormTest',
class FormTest extends React.Component {
state = {
attributes: [
{ ref: 'name', label: 'Your Name', required: true, storage: true},
{ ref: 'description', multiline: true, label: 'Description', value: 'Doer'},
{ ref: 'birthdate', type: 'date', label: 'Birthdate'},
{ ref: 'years', type: 'number', label: 'Years'},
{ ref: 'twitter', label: 'Nickname', disabled: true},
{ ref: 'nomad', type: 'checkbox', label: 'Are you a nomad?', value: true},
{ ref: 'cow', type: 'checkbox', label: 'Are you a cow?', value: false},
{ ref: 'girl', type: 'checkbox', label: 'Are you a girl?', value: false, disabled: true},
{ ref: 'nomad_2', type: 'radio', label: 'Are you a nomad_2?', value: true},
{ ref: 'cow_2', type: 'radio', label: 'Are you a cow_2?', value: false},
{ ref: 'girl_2', type: 'radio', label: 'Are you a girl_2?', value: false, disabled: true},
{ ref: 'type_user', type: 'dropdown', label: 'Type of user', dataSource: [{value: 1, label: 'Normal'}, {value: 2, label: 'Root'}]},
{ type: 'submit', label: 'Send', style: 'primary anchor', disabled: true}
]
};
getInitialState () {
return {
attributes: [
{ ref: 'name', label: 'Your Name', required: true, storage: true},
{ ref: 'description', multiline: true, label: 'Description', value: 'Doer'},
{ ref: 'birthdate', type: 'date', label: 'Birthdate'},
{ ref: 'years', type: 'number', label: 'Years'},
{ ref: 'twitter', label: 'Nickname', disabled: true},
{ ref: 'nomad', type: 'checkbox', label: 'Are you a nomad?', value: true},
{ ref: 'cow', type: 'checkbox', label: 'Are you a cow?', value: false},
{ ref: 'girl', type: 'checkbox', label: 'Are you a girl?', value: false, disabled: true},
{ ref: 'nomad_2', type: 'radio', label: 'Are you a nomad_2?', value: true},
{ ref: 'cow_2', type: 'radio', label: 'Are you a cow_2?', value: false},
{ ref: 'girl_2', type: 'radio', label: 'Are you a girl_2?', value: false, disabled: true},
{ ref: 'type_user', type: 'dropdown', label: 'Type of user', dataSource: [{value: 1, label: 'Normal'}, {value: 2, label: 'Root'}]},
{ type: 'submit', label: 'Send', style: 'primary anchor', disabled: true}
]
};
},
onEvent (type, event, form) {
handleEvent = (type, event, form) => {
console.log(`[FORM.${type}]`, form.getValue());
},
};
render () {
return (
@ -37,11 +33,13 @@ export default React.createClass({
<Form
attributes={this.state.attributes}
storage="example-form"
onChange={this.onEvent.bind(null, 'change')}
onError={this.onEvent.bind(null, 'error')}
onValid={this.onEvent.bind(null, 'valid')}
onSubmit={this.onEvent.bind(null, 'submit')} />
onChange={this.handleEvent.bind(this, 'change')}
onError={this.handleEvent.bind(this, 'error')}
onValid={this.handleEvent.bind(this, 'valid')}
onSubmit={this.handleEvent.bind(this, 'submit')} />
</section>
);
}
});
}
export default FormTest;

View File

@ -1,24 +1,22 @@
import React from 'react';
import { MenuItem, IconMenu } from '../../components/menu';
export default React.createClass({
displayName: 'IconMenuTest',
handleShow () {
class IconMenuTest extends React.Component {
handleShow = () => {
console.log('Showing menu...');
},
};
handleHide () {
handleHide = () => {
console.log('Hiding menu...');
},
};
handleSelect (value, instance) {
handleSelect = (value, instance) => {
console.log('Option selected', value, instance);
},
};
handleItem () {
handleItem = () => {
console.log('Refresh clicked');
},
};
render () {
return (
@ -43,4 +41,6 @@ export default React.createClass({
</div>
);
}
});
}
export default IconMenuTest;

View File

@ -1,21 +1,18 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import Input from '../../components/input';
export default React.createClass({
displayName: 'InputTest',
const InputTest = () => (
<section>
<h5>Inputs</h5>
<p>lorem ipsum...</p>
<Input type='text' label='Firstname' />
<Input type='email' label='Label fixed' floating={false} />
<Input type='text' label='Phone Number' />
<Input type='text' label='Disabled field' disabled />
<Input type='tel' label='With icon' icon='phone' />
<Input type='email' label='With icon' icon='email' />
</section>
);
render () {
return (
<section>
<h5>Inputs</h5>
<p>lorem ipsum...</p>
<Input type='text' label='Firstname' />
<Input type='email' label='Label fixed' floating={false} />
<Input type='text' label='Phone Number' />
<Input type='text' label='Disabled field' disabled />
<Input type='tel' label='With icon' icon='phone' />
<Input type='email' label='With icon' icon='email' />
</section>
);
}
});
export default InputTest;

View File

@ -1,17 +1,14 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import Link from '../../components/link';
export default React.createClass({
displayName: 'LinkTest',
const LinkTest = () => (
<section>
<h5>Links</h5>
<p>lorem ipsum...</p>
<Link label="Github" route="http://www.github.com" icon="bookmark" />
<Link label="Inbox" route="http://mail.google.com" icon="inbox" />
</section>
);
render () {
return (
<section>
<h5>Links</h5>
<p>lorem ipsum...</p>
<Link label="Github" route="http://www.github.com" icon="bookmark" />
<Link label="Inbox" route="http://mail.google.com" icon="inbox" />
</section>
);
}
});
export default LinkTest;

View File

@ -8,111 +8,109 @@ const listStyle = {
minWidth: 340
};
const ListTest = () => {
return (
<section>
<h5>With simple text and icons</h5>
<p>This list can be used inside a Drawer for a list of options or as navigation.</p>
<div style={listStyle}>
<List selectable ripple>
<ListSubHeader caption='Contacts' />
<ListItem caption='Inbox' leftIcon='inbox' />
<ListItem caption='Outbox' leftIcon='send' />
<ListItem caption='Trash' leftIcon='delete' />
<ListItem caption='Spam' leftIcon='report' />
</List>
</div>
const ListTest = () => (
<section>
<h5>With simple text and icons</h5>
<p>This list can be used inside a Drawer for a list of options or as navigation.</p>
<div style={listStyle}>
<List selectable ripple>
<ListSubHeader caption='Contacts' />
<ListItem caption='Inbox' leftIcon='inbox' />
<ListItem caption='Outbox' leftIcon='send' />
<ListItem caption='Trash' leftIcon='delete' />
<ListItem caption='Spam' leftIcon='report' />
</List>
</div>
<h5>Two text lines, avatar and right icon</h5>
<p>Useful for a list of contacts or similar.</p>
<div style={listStyle}>
<List selectable ripple>
<ListSubHeader caption='Contacts' />
<ListItem
avatar='https://pbs.twimg.com/profile_images/614407428/s6pTalMzZs-nusCGWqoV.0_400x400.jpeg'
caption='Alfonso Rocha'
legend='Product Manager at Fon'
rightIcon='star'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/459485216499720192/ufS4YGOY_400x400.png'
caption='Javi Velasco'
legend='Frontend engineer at Socialbro'
rightIcon='star'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/651611834131222528/rKYHs2bd_400x400.jpg'
caption='Javi Jiménez'
legend='Frontend engineer at MediaSmart'
rightIcon='star'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/477103691506282499/bsIaPEiM_400x400.jpeg'
caption='Tobias Van Schneider'
legend='Designer at Spotify'
rightIcon='star'
/>
</List>
</div>
<h5>Two text lines, avatar and right icon</h5>
<p>Useful for a list of contacts or similar.</p>
<div style={listStyle}>
<List selectable ripple>
<ListSubHeader caption='Contacts' />
<ListItem
avatar='https://pbs.twimg.com/profile_images/614407428/s6pTalMzZs-nusCGWqoV.0_400x400.jpeg'
caption='Alfonso Rocha'
legend='Product Manager at Fon'
rightIcon='star'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/459485216499720192/ufS4YGOY_400x400.png'
caption='Javi Velasco'
legend='Frontend engineer at Socialbro'
rightIcon='star'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/651611834131222528/rKYHs2bd_400x400.jpg'
caption='Javi Jiménez'
legend='Frontend engineer at MediaSmart'
rightIcon='star'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/477103691506282499/bsIaPEiM_400x400.jpeg'
caption='Tobias Van Schneider'
legend='Designer at Spotify'
rightIcon='star'
/>
</List>
</div>
<h5>Two line options and checkbox items</h5>
<p>It can be used to embed little checkboxes in the list. These behave as checkboxes.</p>
<div style={listStyle}>
<List>
<ListSubHeader caption='General' />
<ListItem caption='Profile Photo' legend='Change your Google+ profile photo' />
<ListItem disabled caption='Show your status' legend='Your status is visible to everyone you use with' />
</List>
<h5>Two line options and checkbox items</h5>
<p>It can be used to embed little checkboxes in the list. These behave as checkboxes.</p>
<div style={listStyle}>
<List>
<ListSubHeader caption='General' />
<ListItem caption='Profile Photo' legend='Change your Google+ profile photo' />
<ListItem disabled caption='Show your status' legend='Your status is visible to everyone you use with' />
</List>
<ListDivider />
<List>
<ListSubHeader caption='Hangout notifications' />
<ListCheckbox caption='Notifications' legend='Allow notifications' />
<ListCheckbox checked caption='Sound' legend='Hangouts message' />
<ListCheckbox disabled caption='Video sounds' legend='Hangouts video call' />
</List>
</div>
<h5>Avatar, sinle text and icon</h5>
<p>Similar to a previous one but only with one text line</p>
<div style={listStyle}>
<List>
<ListItem
avatar='https://pbs.twimg.com/profile_images/614407428/s6pTalMzZs-nusCGWqoV.0_400x400.jpeg'
caption='Alfonso Rocha'
rightIcon='mail'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/459485216499720192/ufS4YGOY_400x400.png'
caption='Javi Velasco'
rightIcon='mail'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/651611834131222528/rKYHs2bd_400x400.jpg'
caption='Javi Jiménez'
rightIcon='mail'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/477103691506282499/bsIaPEiM_400x400.jpeg'
caption='Tobias Van Schneider'
rightIcon='mail'
/>
</List>
</div>
<h5>Simple with just one text line</h5>
<p>The most simple list.</p>
<div style={listStyle}>
<List>
<ListItem caption='Alfonso Rocha' />
<ListItem caption='Javi Velasco' />
<ListItem caption='Javi Jiménez' />
<ListItem caption='Tobias Van Schneider' />
<ListDivider />
<List>
<ListSubHeader caption='Hangout notifications' />
<ListCheckbox caption='Notifications' legend='Allow notifications' />
<ListCheckbox checked caption='Sound' legend='Hangouts message' />
<ListCheckbox disabled caption='Video sounds' legend='Hangouts video call' />
</List>
</div>
<h5>Avatar, sinle text and icon</h5>
<p>Similar to a previous one but only with one text line</p>
<div style={listStyle}>
<List>
<ListItem
avatar='https://pbs.twimg.com/profile_images/614407428/s6pTalMzZs-nusCGWqoV.0_400x400.jpeg'
caption='Alfonso Rocha'
rightIcon='mail'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/459485216499720192/ufS4YGOY_400x400.png'
caption='Javi Velasco'
rightIcon='mail'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/651611834131222528/rKYHs2bd_400x400.jpg'
caption='Javi Jiménez'
rightIcon='mail'
/>
<ListItem
avatar='https://pbs.twimg.com/profile_images/477103691506282499/bsIaPEiM_400x400.jpeg'
caption='Tobias Van Schneider'
rightIcon='mail'
/>
</List>
</div>
<h5>Simple with just one text line</h5>
<p>The most simple list.</p>
<div style={listStyle}>
<List>
<ListItem caption='Alfonso Rocha' />
<ListItem caption='Javi Velasco' />
<ListItem caption='Javi Jiménez' />
<ListItem caption='Tobias Van Schneider' />
<ListDivider />
<ListItem caption='Other people' />
</List>
</div>
</section>
);
};
<ListItem caption='Other people' />
</List>
</div>
</section>
);
export default ListTest;

View File

@ -1,16 +1,14 @@
import React from 'react';
import { Menu, MenuItem, MenuDivider } from '../../components/menu';
export default React.createClass({
displayName: 'MenuTest',
handleSelect (e, instance) {
class MenuTest extends React.Component {
handleSelect = (e, instance) => {
console.log('Menu selection changed!!, now its', instance.getValue());
},
};
handleItemClick () {
handleItemClick = () => {
console.log('This item is so special that has a special handler');
},
};
render () {
return (
@ -30,4 +28,6 @@ export default React.createClass({
</section>
);
}
});
}
export default MenuTest;

View File

@ -1,17 +1,13 @@
import React from 'react';
import Navigation from '../../components/navigation';
export default React.createClass({
displayName: 'NavigationTest',
getInitialState () {
return {
routes: [
{ label: 'Github', route: 'http://www.github.com', icon: 'bookmark' },
{ label: 'Mail', route: 'http://mail.google.com', icon: 'inbox' }
]
};
},
class NavigationTest extends React.Component {
state = {
routes: [
{ label: 'Github', route: 'http://www.github.com', icon: 'bookmark' },
{ label: 'Mail', route: 'http://mail.google.com', icon: 'inbox' }
]
};
render () {
return (
@ -23,4 +19,6 @@ export default React.createClass({
</section>
);
}
});
}
export default NavigationTest;

View File

@ -1,26 +1,25 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import DatePicker from '../../components/date_picker';
import TimePicker from '../../components/time_picker';
export default React.createClass({
displayName: 'PickersTest',
const PickersTest = () => {
let datetime = new Date(1995, 11, 17);
datetime.setHours(17);
datetime.setMinutes(28);
render () {
let datetime = new Date(1995, 11, 17);
datetime.setHours(17);
datetime.setMinutes(28);
return (
<section>
<h5>Pickers</h5>
<p>Date pickers and time pickers with Material flavour.</p>
return (
<section>
<h5>Pickers</h5>
<p>Date pickers and time pickers with Material flavour.</p>
<DatePicker />
<DatePicker value={datetime} />
<DatePicker />
<DatePicker value={datetime} />
<TimePicker />
<TimePicker value={datetime} format='ampm' />
</section>
);
};
<TimePicker />
<TimePicker value={datetime} format='ampm' />
</section>
);
}
});
export default PickersTest;

View File

@ -1,19 +1,17 @@
import React from 'react';
import ProgressBar from '../../components/progress_bar';
export default React.createClass({
displayName: 'ProgressBarTest',
const initialState = {
progress: 0,
buffer: 10
};
getInitialState () {
return {
progress: 0,
buffer: 10
};
},
class ProgressBarTest extends React.Component {
state = initialState;
componentWillMount () {
this.simulateProgress();
},
}
simulateProgress () {
setTimeout(() => {
@ -21,23 +19,23 @@ export default React.createClass({
this.increaseProgress();
if (this.state.progress > this.state.buffer) this.increaseBuffer();
} else {
this.replaceState(this.getInitialState());
this.setState(initialState);
}
this.simulateProgress();
}, (Math.random() * 1 + 1) * 1000);
},
}
increaseProgress () {
this.setState({
progress: Math.random() * 30 + this.state.progress
});
},
}
increaseBuffer () {
this.setState({
buffer: Math.random() * (100 - this.state.progress) + this.state.progress
});
},
}
render () {
return (
@ -52,4 +50,6 @@ export default React.createClass({
</section>
);
}
});
}
export default ProgressBarTest;

View File

@ -1,18 +1,18 @@
import React from 'react';
import { RadioGroup, RadioButton } from '../../components/radio';
export default React.createClass({
handleChange (event, instance) {
class RadioGroupTest extends React.Component {
handleChange = (event, instance) => {
console.log('Changed!', { comic: instance.getValue()});
},
};
handleFocus () {
handleFocus = () => {
console.log('Focused V for a Vendetta');
},
};
handleBlur () {
handleBlur = () => {
console.log('Blurred Watchmen');
},
};
render () {
return (
@ -29,4 +29,6 @@ export default React.createClass({
</section>
);
}
});
}
export default RadioGroupTest;

View File

@ -1,20 +1,17 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import Slider from '../../components/slider';
export default React.createClass({
displayName: 'SliderTest',
const SliderTest = () => (
<section>
<h5>Sliders</h5>
<p>Normal slider</p>
<Slider />
<p>With steps, initial value and editable</p>
<Slider value={5} min={0} max={10} editable />
<p>Pinned and with snaps</p>
<Slider pinned snaps value={1} min={0} max={10} step={1} editable />
</section>
);
render () {
return (
<section>
<h5>Sliders</h5>
<p>Normal slider</p>
<Slider />
<p>With steps, initial value and editable</p>
<Slider value={5} min={0} max={10} editable />
<p>Pinned and with snaps</p>
<Slider pinned snaps value={1} min={0} max={10} step={1} editable />
</section>
);
}
});
export default SliderTest;

View File

@ -2,17 +2,14 @@ import React from 'react';
import Button from '../../components/button';
import Snackbar from '../../components/snackbar';
export default React.createClass({
displayName: 'SnackbarTest',
handleClick (event, snackbar) {
class SnackbarTest extends React.Component {
handleClick = (event, snackbar) => {
console.log('handleClick', event, snackbar);
},
};
handleSnackbar () {
handleSnackbar = () => {
this.refs.snackbar.show();
},
};
render () {
return (
@ -31,4 +28,6 @@ export default React.createClass({
</section>
);
}
});
}
export default SnackbarTest;

View File

@ -1,12 +1,10 @@
import React from 'react';
import Switch from '../../components/switch';
export default React.createClass({
displayName: 'SwitchTest',
onChange (event, instance) {
class SwitchTest extends React.Component {
handleChange = (event, instance) => {
console.log('[Switch] Changed', instance.getValue());
},
};
render () {
return (
@ -14,9 +12,11 @@ export default React.createClass({
<h5>Switches</h5>
<p style={{marginBottom: '10px'}}>This is more beautiful than the old fashion checkboxes...</p>
<Switch label="Push notifications" />
<Switch checked label="Mail notifications" onChange={this.onChange} />
<Switch checked label="Mail notifications" onChange={this.handleChange} />
<Switch disabled label="Nothing, thanks"/>
</section>
);
}
});
}
export default SwitchTest;

View File

@ -1,23 +1,20 @@
/*eslint-disable no-unused-vars*/
import React from 'react';
import { Tabs, Tab } from '../../components/tabs';
export default React.createClass({
displayName: 'TabsTest',
const TabsTest = () => (
<section>
<h5>Tabs</h5>
<p>This tabs can be disabled or hidden</p>
render () {
return (
<section>
<h5>Tabs</h5>
<p>This tabs can be disabled or hidden</p>
<Tabs>
<Tab label='Primary'><small>Primary content</small></Tab>
<Tab label='Secondary'><small>Secondary content</small></Tab>
<Tab label='Third' disabled><small>Disabled content</small></Tab>
<Tab label='Fourth' hidden><small>Fourth content hidden</small></Tab>
<Tab label='Fifth'><small>Fifth content</small></Tab>
</Tabs>
</section>
);
<Tabs>
<Tab label='Primary'><small>Primary content</small></Tab>
<Tab label='Secondary'><small>Secondary content</small></Tab>
<Tab label='Third' disabled><small>Disabled content</small></Tab>
<Tab label='Fourth' hidden><small>Fourth content hidden</small></Tab>
<Tab label='Fifth'><small>Fifth content</small></Tab>
</Tabs>
</section>
);
}
});
export default TabsTest;