Rename most components index to actual components
parent
1611b491fa
commit
cfebdb55f4
4
.babelrc
4
.babelrc
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"stage": 1,
|
||||
"optional": ["es7.classProperties"],
|
||||
"stage": 2,
|
||||
"optional": ["es7.classProperties", "es7.exportExtensions"],
|
||||
"env": {
|
||||
"development": {
|
||||
"plugins": ["react-transform"],
|
||||
|
|
|
@ -227,7 +227,7 @@
|
|||
"react/no-danger": 0,
|
||||
"react/no-did-mount-set-state": 0,
|
||||
"react/no-did-update-set-state": 1,
|
||||
"react/no-multi-comp": 1,
|
||||
"react/no-multi-comp": 0,
|
||||
"react/no-unknown-property": 1,
|
||||
"react/prop-types": [2, {"ignore": ["onMouseDown", "onTouchStart"]}],
|
||||
"react/react-in-jsx-scope": 1,
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
import SlideLeft from './slide-left';
|
||||
import SlideRight from './slide-right';
|
||||
|
||||
export default {SlideLeft, SlideRight};
|
||||
export SlideLeft from './slide-left';
|
||||
export SlideRight from './slide-right';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import Calendar from './calendar';
|
||||
import Dialog from '../Dialog';
|
||||
import Dialog from '../dialog';
|
||||
import style from './style';
|
||||
import time from '../utils/time';
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class DropdownTest extends React.Component {
|
|||
render () {
|
||||
return (
|
||||
<Dropdown
|
||||
auto={true}
|
||||
auto
|
||||
onChange={this.handleChange}
|
||||
source={countries}
|
||||
value={this.state.value}
|
||||
|
|
|
@ -34,7 +34,7 @@ class List extends React.Component {
|
|||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
return (
|
||||
<ul className={className}>
|
||||
{ this.renderItems() }
|
||||
{this.renderItems()}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import React from 'react';
|
||||
import style from './style';
|
||||
import Button from '../button';
|
||||
import Link from '../link';
|
||||
|
||||
const Navigation = props => {
|
||||
let className = `${style[props.type]}`;
|
||||
if (props.className) className += ` ${props.className}`;
|
||||
|
||||
const buttons = props.actions.map((action, index) => {
|
||||
return <Button className={style.button} key={index} {...action} />;
|
||||
});
|
||||
|
||||
const links = props.routes.map((route, index) => {
|
||||
return <Link className={style.link} key={index} {...route} />;
|
||||
});
|
||||
|
||||
return (
|
||||
<nav data-react-toolbox='navigation' className={className}>
|
||||
{links}
|
||||
{buttons}
|
||||
{props.children}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.propTypes = {
|
||||
actions: React.PropTypes.array,
|
||||
children: React.PropTypes.node,
|
||||
className: React.PropTypes.string,
|
||||
routes: React.PropTypes.array,
|
||||
type: React.PropTypes.oneOf(['vertical', 'horizontal'])
|
||||
};
|
||||
|
||||
Navigation.defaultProps = {
|
||||
actions: [],
|
||||
className: '',
|
||||
type: 'horizontal',
|
||||
routes: []
|
||||
};
|
||||
|
||||
export default Navigation;
|
|
@ -1,41 +1 @@
|
|||
import React from 'react';
|
||||
import style from './style';
|
||||
import Button from '../button';
|
||||
import Link from '../link';
|
||||
|
||||
const Navigation = props => {
|
||||
let className = `${style[props.type]}`;
|
||||
if (props.className) className += ` ${props.className}`;
|
||||
|
||||
const buttons = props.actions.map((action, index) => {
|
||||
return <Button className={style.button} key={index} {...action} />;
|
||||
});
|
||||
|
||||
const links = props.routes.map((route, index) => {
|
||||
return <Link className={style.link} key={index} {...route} />;
|
||||
});
|
||||
|
||||
return (
|
||||
<nav data-react-toolbox='navigation' className={className}>
|
||||
{ links }
|
||||
{ buttons }
|
||||
{ props.children }
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.propTypes = {
|
||||
actions: React.PropTypes.array,
|
||||
className: React.PropTypes.string,
|
||||
routes: React.PropTypes.array,
|
||||
type: React.PropTypes.oneOf(['vertical', 'horizontal'])
|
||||
};
|
||||
|
||||
Navigation.defaultProps = {
|
||||
actions: [],
|
||||
className: '',
|
||||
type: 'horizontal',
|
||||
routes: []
|
||||
};
|
||||
|
||||
export default Navigation;
|
||||
export default from './Navigation.jsx';
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import style from './style';
|
||||
|
||||
class Overlay extends React.Component {
|
||||
static propTypes = {
|
||||
active: React.PropTypes.bool,
|
||||
children: React.PropTypes.node,
|
||||
className: React.PropTypes.string,
|
||||
onClick: React.PropTypes.func,
|
||||
opacity: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
opacity: 0.5
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.app = document.querySelector('[data-react-toolbox="app"]') || document.body;
|
||||
this.node = document.createElement('div');
|
||||
this.node.setAttribute('data-react-toolbox', 'overlay');
|
||||
this.app.appendChild(this.node);
|
||||
this.handleRender();
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this.handleRender();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
ReactDOM.unmountComponentAtNode(this.node);
|
||||
this.app.removeChild(this.node);
|
||||
}
|
||||
|
||||
handleRender () {
|
||||
let className = style.root;
|
||||
const overlayStyle = {};
|
||||
|
||||
if (this.props.active) {
|
||||
className += ` ${style.active}`;
|
||||
overlayStyle.opacity = this.props.opacity;
|
||||
}
|
||||
if (this.props.className) className += ` ${className}`;
|
||||
|
||||
ReactDOM.render(
|
||||
<div className={className}>
|
||||
<div
|
||||
className={style.overlay}
|
||||
onClick={this.props.onClick}
|
||||
style={overlayStyle}
|
||||
/>
|
||||
{this.props.children}
|
||||
</div>
|
||||
, this.node);
|
||||
}
|
||||
|
||||
render () {
|
||||
return React.DOM.noscript();
|
||||
}
|
||||
}
|
||||
|
||||
export default Overlay;
|
|
@ -1,61 +1 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import style from './style';
|
||||
|
||||
class Overlay extends React.Component {
|
||||
static propTypes = {
|
||||
active: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
onClick: React.PropTypes.func,
|
||||
opacity: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
opacity: 0.5
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.app = document.querySelector('[data-react-toolbox="app"]') || document.body;
|
||||
this.node = document.createElement('div');
|
||||
this.node.setAttribute('data-react-toolbox', 'overlay');
|
||||
this.app.appendChild(this.node);
|
||||
this.handleRender();
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this.handleRender();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
ReactDOM.unmountComponentAtNode(this.node);
|
||||
this.app.removeChild(this.node);
|
||||
}
|
||||
|
||||
handleRender () {
|
||||
let className = style.root;
|
||||
const overlayStyle = {};
|
||||
|
||||
if (this.props.active) {
|
||||
className += ` ${style.active}`;
|
||||
overlayStyle.opacity = this.props.opacity;
|
||||
}
|
||||
if (this.props.className) className += ` ${className}`;
|
||||
|
||||
ReactDOM.render(
|
||||
<div className={className}>
|
||||
<div
|
||||
className={style.overlay}
|
||||
onClick={this.props.onClick}
|
||||
style={overlayStyle}
|
||||
/>
|
||||
{this.props.children}
|
||||
</div>
|
||||
, this.node);
|
||||
}
|
||||
|
||||
render () {
|
||||
return React.DOM.noscript();
|
||||
}
|
||||
}
|
||||
|
||||
export default Overlay;
|
||||
export default from './Overlay.jsx';
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
import React from 'react';
|
||||
import style from './style';
|
||||
import prefixer from '../utils/prefixer';
|
||||
|
||||
class ProgressBar extends React.Component {
|
||||
static propTypes = {
|
||||
buffer: React.PropTypes.number,
|
||||
className: React.PropTypes.string,
|
||||
max: React.PropTypes.number,
|
||||
min: React.PropTypes.number,
|
||||
mode: React.PropTypes.string,
|
||||
multicolor: React.PropTypes.bool,
|
||||
type: React.PropTypes.string,
|
||||
value: React.PropTypes.number
|
||||
};
|
||||
|
||||
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`};
|
||||
}
|
||||
}
|
||||
|
||||
linearStyle () {
|
||||
if (this.props.mode !== 'indeterminate') {
|
||||
return {
|
||||
buffer: prefixer({transform: `scaleX(${this.calculateRatio(this.props.buffer)})`}),
|
||||
value: prefixer({transform: `scaleX(${this.calculateRatio(this.props.value)})`})
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
renderCircular () {
|
||||
return (
|
||||
<svg className={style.circle}>
|
||||
<circle className={style.path} style={this.circularStyle()} cx='30' cy='30' r='25' />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
renderLinear () {
|
||||
const {buffer, value} = this.linearStyle();
|
||||
return (
|
||||
<div>
|
||||
<span ref='buffer' data-ref='buffer' className={style.buffer} style={buffer}></span>
|
||||
<span ref='value' data-ref='value' className={style.value} style={value}></span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = this.props.type === 'linear' ? style.linear : style.circular;
|
||||
if (this.props.mode) className += ` ${style[this.props.mode]}`;
|
||||
if (this.props.multicolor) className += ` ${style.multicolor}`;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-react-toolbox='progress-bar'
|
||||
aria-valuenow={this.props.value}
|
||||
aria-valuemin={this.props.min}
|
||||
aria-valuemax={this.props.max}
|
||||
className={className}
|
||||
>
|
||||
{this.props.type === 'circular' ? this.renderCircular() : this.renderLinear()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ProgressBar;
|
|
@ -1,89 +1 @@
|
|||
import React from 'react';
|
||||
import style from './style';
|
||||
import prefixer from '../utils/prefixer';
|
||||
|
||||
class ProgressBar extends React.Component {
|
||||
static propTypes = {
|
||||
buffer: React.PropTypes.number,
|
||||
className: React.PropTypes.string,
|
||||
max: React.PropTypes.number,
|
||||
min: React.PropTypes.number,
|
||||
mode: React.PropTypes.string,
|
||||
multicolor: React.PropTypes.bool,
|
||||
type: React.PropTypes.string,
|
||||
value: React.PropTypes.number
|
||||
};
|
||||
|
||||
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`};
|
||||
}
|
||||
}
|
||||
|
||||
linearStyle () {
|
||||
if (this.props.mode !== 'indeterminate') {
|
||||
return {
|
||||
buffer: prefixer({transform: `scaleX(${this.calculateRatio(this.props.buffer)})`}),
|
||||
value: prefixer({transform: `scaleX(${this.calculateRatio(this.props.value)})`})
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
renderCircular () {
|
||||
return (
|
||||
<svg className={style.circle}>
|
||||
<circle className={style.path} style={this.circularStyle()} cx='30' cy='30' r='25' />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
renderLinear () {
|
||||
const {buffer, value} = this.linearStyle();
|
||||
return (
|
||||
<div>
|
||||
<span ref='buffer' data-ref='buffer' className={style.buffer} style={buffer}></span>
|
||||
<span ref='value' data-ref='value' className={style.value} style={value}></span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = this.props.type === 'linear' ? style.linear : style.circular;
|
||||
if (this.props.mode) className += ` ${style[this.props.mode]}`;
|
||||
if (this.props.multicolor) className += ` ${style.multicolor}`;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-react-toolbox='progress-bar'
|
||||
aria-valuenow={this.props.value}
|
||||
aria-valuemin={this.props.min}
|
||||
aria-valuemax={this.props.max}
|
||||
className={className}
|
||||
>
|
||||
{ this.props.type === 'circular' ? this.renderCircular() : this.renderLinear() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ProgressBar;
|
||||
export default from './ProgressBar.jsx';
|
||||
|
|
|
@ -41,6 +41,14 @@ class RadioButton extends React.Component {
|
|||
if (!this.props.disabled) this.refs.ripple.start(event);
|
||||
};
|
||||
|
||||
blur () {
|
||||
this.refs.input.blur();
|
||||
}
|
||||
|
||||
focus () {
|
||||
this.refs.input.focus();
|
||||
}
|
||||
|
||||
render () {
|
||||
let labelClassName = style[this.props.disabled ? 'disabled' : 'field'];
|
||||
const radioClassName = style[this.props.checked ? 'radio-checked' : 'radio'];
|
||||
|
@ -59,18 +67,10 @@ class RadioButton extends React.Component {
|
|||
<span role='radio' className={radioClassName} onMouseDown={this.handleMouseDown}>
|
||||
<Ripple ref='ripple' role='ripple' className={style.ripple} spread={3} centered />
|
||||
</span>
|
||||
{ this.props.label ? <span className={style.text}>{this.props.label}</span> : null }
|
||||
{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;
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import RadioButton from './radio_button';
|
||||
import RadioButton from './RadioButton';
|
||||
|
||||
class RadioGroup extends React.Component {
|
||||
static propTypes = {
|
||||
children: React.PropTypes.node,
|
||||
className: React.PropTypes.string,
|
||||
disabled: React.PropTypes.bool,
|
||||
name: React.PropTypes.string,
|
|
@ -1,4 +1,2 @@
|
|||
import RadioButton from './radio_button';
|
||||
import RadioGroup from './radio_group';
|
||||
|
||||
export default {RadioButton, RadioGroup};
|
||||
export RadioButton from './RadioButton';
|
||||
export RadioGroup from './RadioGroup';
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import prefixer from '../utils/prefixer';
|
||||
import style from './style';
|
||||
|
||||
class Ripple extends React.Component {
|
||||
static propTypes = {
|
||||
centered: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
loading: React.PropTypes.bool,
|
||||
spread: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
centered: false,
|
||||
className: '',
|
||||
loading: false,
|
||||
spread: 2
|
||||
};
|
||||
|
||||
state = {
|
||||
active: false,
|
||||
left: null,
|
||||
restarting: false,
|
||||
top: null,
|
||||
width: null
|
||||
};
|
||||
|
||||
handleEnd = () => {
|
||||
document.removeEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
||||
this.setState({active: false});
|
||||
};
|
||||
|
||||
start = ({pageX, pageY}, touch = false) => {
|
||||
this.touch = touch;
|
||||
document.addEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
||||
const {top, left, width} = this._getDescriptor(pageX, pageY);
|
||||
this.setState({active: false, restarting: true, top, left, width}, () => {
|
||||
this.refs.ripple.offsetWidth; //eslint-disable-line no-unused-expressions
|
||||
this.setState({active: true, restarting: false});
|
||||
});
|
||||
};
|
||||
|
||||
_getDescriptor (pageX, pageY) {
|
||||
const {left, top, height, width} = ReactDOM.findDOMNode(this).getBoundingClientRect();
|
||||
return {
|
||||
left: this.props.centered ? 0 : pageX - left - width / 2 + window.scrollX,
|
||||
top: this.props.centered ? 0 : pageY - top - height / 2 + window.scrollY,
|
||||
width: width * this.props.spread
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { left, top, width } = this.state;
|
||||
const scale = this.state.restarting ? 0 : 1;
|
||||
let rippleStyle = {width, height: width};
|
||||
|
||||
if (!this.props.loading) {
|
||||
rippleStyle = prefixer({
|
||||
transform: `translate3d(${-width / 2 + left}px, ${-width / 2 + top}px, 0) scale(${scale})`
|
||||
}, rippleStyle);
|
||||
}
|
||||
|
||||
let className = style[this.props.loading ? 'loading' : 'normal'];
|
||||
if (this.state.active) className += ` ${style.active}`;
|
||||
if (this.state.restarting) className += ` ${style.restarting}`;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<span data-react-toolbox='ripple' className={style.wrapper}>
|
||||
<span ref='ripple' role='ripple' className={className} style={rippleStyle} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Ripple;
|
|
@ -1,77 +1 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import prefixer from '../utils/prefixer';
|
||||
import style from './style';
|
||||
|
||||
class Ripple extends React.Component {
|
||||
static propTypes = {
|
||||
centered: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
loading: React.PropTypes.bool,
|
||||
spread: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
centered: false,
|
||||
className: '',
|
||||
loading: false,
|
||||
spread: 2
|
||||
};
|
||||
|
||||
state = {
|
||||
active: false,
|
||||
left: null,
|
||||
restarting: false,
|
||||
top: null,
|
||||
width: null
|
||||
};
|
||||
|
||||
handleEnd = () => {
|
||||
document.removeEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
||||
this.setState({active: false});
|
||||
};
|
||||
|
||||
start = ({pageX, pageY}, touch = false) => {
|
||||
this.touch = touch;
|
||||
document.addEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
||||
const {top, left, width} = this._getDescriptor(pageX, pageY);
|
||||
this.setState({active: false, restarting: true, top, left, width}, () => {
|
||||
this.refs.ripple.offsetWidth; //eslint-disable-line no-unused-expressions
|
||||
this.setState({active: true, restarting: false});
|
||||
});
|
||||
};
|
||||
|
||||
_getDescriptor (pageX, pageY) {
|
||||
const {left, top, height, width} = ReactDOM.findDOMNode(this).getBoundingClientRect();
|
||||
return {
|
||||
left: this.props.centered ? 0 : pageX - left - width / 2 + window.scrollX,
|
||||
top: this.props.centered ? 0 : pageY - top - height / 2 + window.scrollY,
|
||||
width: width * this.props.spread
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { left, top, width } = this.state;
|
||||
const scale = this.state.restarting ? 0 : 1;
|
||||
let rippleStyle = {width, height: width};
|
||||
|
||||
if (!this.props.loading) {
|
||||
rippleStyle = prefixer({
|
||||
transform: `translate3d(${-width / 2 + left}px, ${-width / 2 + top}px, 0) scale(${scale})`
|
||||
}, rippleStyle);
|
||||
}
|
||||
|
||||
let className = style[this.props.loading ? 'loading' : 'normal'];
|
||||
if (this.state.active) className += ` ${style.active}`;
|
||||
if (this.state.restarting) className += ` ${style.restarting}`;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<span data-react-toolbox='ripple' className={style.wrapper}>
|
||||
<span ref='ripple' role='ripple' className={className} style={rippleStyle} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Ripple;
|
||||
export default from './Ripple';
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import style from './style';
|
||||
import events from '../utils/events';
|
||||
import prefixer from '../utils/prefixer';
|
||||
import utils from '../utils/utils';
|
||||
import ProgressBar from '../progress_bar';
|
||||
import Input from '../input';
|
||||
|
||||
class Slider extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
editable: React.PropTypes.bool,
|
||||
max: React.PropTypes.number,
|
||||
min: React.PropTypes.number,
|
||||
onChange: React.PropTypes.func,
|
||||
pinned: React.PropTypes.bool,
|
||||
snaps: React.PropTypes.bool,
|
||||
step: React.PropTypes.number,
|
||||
value: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
editable: false,
|
||||
max: 100,
|
||||
min: 0,
|
||||
pinned: false,
|
||||
snaps: false,
|
||||
step: 0.01,
|
||||
value: 0
|
||||
};
|
||||
|
||||
state = {
|
||||
inputFocused: false,
|
||||
inputValue: null,
|
||||
sliderLength: 0,
|
||||
sliderStart: 0
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
this.handleResize();
|
||||
}
|
||||
|
||||
shouldComponentUpdate (nextProps, nextState) {
|
||||
if (!this.state.inputFocused && nextState.inputFocused) return false;
|
||||
if (this.state.inputFocused && this.props.value !== nextProps.value) {
|
||||
this.setState({inputValue: this.valueForInput(nextProps.value)});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
}
|
||||
|
||||
handleInputFocus = () => {
|
||||
this.setState({
|
||||
inputFocused: true,
|
||||
inputValue: this.valueForInput(this.props.value)
|
||||
});
|
||||
};
|
||||
|
||||
handleInputChange = (event) => {
|
||||
this.setState({inputValue: event.target.value});
|
||||
};
|
||||
|
||||
handleInputBlur = () => {
|
||||
const value = this.state.inputValue || 0;
|
||||
this.setState({inputFocused: false, inputValue: null}, () => {
|
||||
this.props.onChange(this.trimValue(value));
|
||||
});
|
||||
};
|
||||
|
||||
handleKeyDown = (event) => {
|
||||
if ([13, 27].indexOf(event.keyCode) !== -1) {
|
||||
this.refs.input.blur();
|
||||
ReactDOM.findDOMNode(this).blur();
|
||||
}
|
||||
if (event.keyCode === 38) this.addToValue(this.props.step);
|
||||
if (event.keyCode === 40) this.addToValue(-this.props.step);
|
||||
};
|
||||
|
||||
handleMouseDown = (event) => {
|
||||
if (this.state.inputFocused) this.refs.input.blur();
|
||||
events.addEventsToDocument(this.getMouseEventMap());
|
||||
this.start(events.getMousePosition(event));
|
||||
events.pauseEvent(event);
|
||||
};
|
||||
|
||||
handleMouseMove = (event) => {
|
||||
events.pauseEvent(event);
|
||||
this.move(events.getMousePosition(event));
|
||||
};
|
||||
|
||||
handleMouseUp = () => {
|
||||
this.end(this.getMouseEventMap());
|
||||
};
|
||||
|
||||
handleResize = (event, callback) => {
|
||||
const {left, right} = ReactDOM.findDOMNode(this.refs.progressbar).getBoundingClientRect();
|
||||
const cb = callback || () => {};
|
||||
this.setState({sliderStart: left, sliderLength: right - left}, cb);
|
||||
};
|
||||
|
||||
handleSliderBlur = () => {
|
||||
events.removeEventsFromDocument(this.getKeyboardEvents());
|
||||
};
|
||||
|
||||
handleSliderFocus = () => {
|
||||
events.addEventsToDocument(this.getKeyboardEvents());
|
||||
};
|
||||
|
||||
handleTouchEnd = () => {
|
||||
this.end(this.getTouchEventMap());
|
||||
};
|
||||
|
||||
handleTouchMove = (event) => {
|
||||
this.move(events.getTouchPosition(event));
|
||||
};
|
||||
|
||||
handleTouchStart = (event) => {
|
||||
if (this.state.inputFocused) this.refs.input.blur();
|
||||
this.start(events.getTouchPosition(event));
|
||||
events.addEventsToDocument(this.getTouchEventMap());
|
||||
events.pauseEvent(event);
|
||||
};
|
||||
|
||||
addToValue (increment) {
|
||||
let value = this.state.inputFocused ? parseFloat(this.state.inputValue) : this.props.value;
|
||||
value = this.trimValue(value + increment);
|
||||
if (value !== this.props.value) this.props.onChange(value);
|
||||
}
|
||||
|
||||
getKeyboardEvents () {
|
||||
return {
|
||||
keydown: this.handleKeyDown
|
||||
};
|
||||
}
|
||||
|
||||
getMouseEventMap () {
|
||||
return {
|
||||
mousemove: this.handleMouseMove,
|
||||
mouseup: this.handleMouseUp
|
||||
};
|
||||
}
|
||||
|
||||
getTouchEventMap () {
|
||||
return {
|
||||
touchmove: this.handleTouchMove,
|
||||
touchend: this.handleTouchEnd
|
||||
};
|
||||
}
|
||||
|
||||
end (revents) {
|
||||
events.removeEventsFromDocument(revents);
|
||||
this.setState({ pressed: false });
|
||||
}
|
||||
|
||||
knobOffset () {
|
||||
const { max, min } = this.props;
|
||||
return this.state.sliderLength * (this.props.value - min) / (max - min);
|
||||
}
|
||||
|
||||
move (position) {
|
||||
const newValue = this.positionToValue(position);
|
||||
if (newValue !== this.props.value) this.props.onChange(newValue);
|
||||
}
|
||||
|
||||
positionToValue (position) {
|
||||
const { sliderStart: start, sliderLength: length } = this.state;
|
||||
const { max, min } = this.props;
|
||||
return this.trimValue((position.x - start) / length * (max - min) + min);
|
||||
}
|
||||
|
||||
start (position) {
|
||||
this.handleResize(null, () => {
|
||||
this.setState({pressed: true});
|
||||
this.props.onChange(this.positionToValue(position));
|
||||
});
|
||||
}
|
||||
|
||||
stepDecimals () {
|
||||
return (this.props.step.toString().split('.')[1] || []).length;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
valueForInput (value) {
|
||||
const decimals = this.stepDecimals();
|
||||
return decimals > 0 ? value.toFixed(decimals) : value.toString();
|
||||
}
|
||||
|
||||
renderSnaps () {
|
||||
if (this.props.snaps) {
|
||||
return (
|
||||
<div ref='snaps' className={style.snaps}>
|
||||
{utils.range(0, (this.props.max - this.props.min) / this.props.step).map(i => {
|
||||
return <div key={`span-${i}`} className={style.snap}></div>;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderInput () {
|
||||
if (this.props.editable) {
|
||||
const value = this.state.inputFocused ? this.state.inputValue : this.valueForInput(this.props.value);
|
||||
return (
|
||||
<Input
|
||||
ref='input'
|
||||
className={style.input}
|
||||
onFocus={this.handleInputFocus}
|
||||
onChange={this.handleInputChange}
|
||||
onBlur={this.handleInputBlur}
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const knobStyles = prefixer({transform: `translateX(${this.knobOffset()}px)`});
|
||||
let className = this.props.className;
|
||||
if (this.props.editable) className += ` ${style.editable}`;
|
||||
if (this.props.pinned) className += ` ${style.pinned}`;
|
||||
if (this.state.pressed) className += ` ${style.pressed}`;
|
||||
if (this.props.value === this.props.min) className += ` ${style.ring}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={style.root + className}
|
||||
data-react-toolbox='slider'
|
||||
onBlur={this.handleSliderBlur}
|
||||
onFocus={this.handleSliderFocus}
|
||||
tabIndex='0'
|
||||
>
|
||||
<div
|
||||
ref='slider'
|
||||
className={style.container}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
>
|
||||
<div
|
||||
ref='knob'
|
||||
className={style.knob}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
style={knobStyles}
|
||||
>
|
||||
<div className={style.innerknob} data-value={parseInt(this.props.value)}></div>
|
||||
</div>
|
||||
|
||||
<div className={style.progress}>
|
||||
<ProgressBar
|
||||
ref='progressbar'
|
||||
className={style.innerprogress}
|
||||
max={this.props.max}
|
||||
min={this.props.min}
|
||||
mode='determinate'
|
||||
value={this.props.value}
|
||||
/>
|
||||
{this.renderSnaps()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.renderInput()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Slider;
|
|
@ -1,279 +1 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import style from './style';
|
||||
import events from '../utils/events';
|
||||
import prefixer from '../utils/prefixer';
|
||||
import utils from '../utils/utils';
|
||||
import ProgressBar from '../progress_bar';
|
||||
import Input from '../input';
|
||||
|
||||
class Slider extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
editable: React.PropTypes.bool,
|
||||
max: React.PropTypes.number,
|
||||
min: React.PropTypes.number,
|
||||
onChange: React.PropTypes.func,
|
||||
pinned: React.PropTypes.bool,
|
||||
snaps: React.PropTypes.bool,
|
||||
step: React.PropTypes.number,
|
||||
value: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
editable: false,
|
||||
max: 100,
|
||||
min: 0,
|
||||
pinned: false,
|
||||
snaps: false,
|
||||
step: 0.01,
|
||||
value: 0
|
||||
};
|
||||
|
||||
state = {
|
||||
inputFocused: false,
|
||||
inputValue: null,
|
||||
sliderLength: 0,
|
||||
sliderStart: 0
|
||||
};
|
||||
|
||||
shouldComponentUpdate (nextProps, nextState) {
|
||||
if (!this.state.inputFocused && nextState.inputFocused) return false;
|
||||
if (this.state.inputFocused && this.props.value !== nextProps.value) {
|
||||
this.setState({inputValue: this.valueForInput(nextProps.value)});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
this.handleResize();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
}
|
||||
|
||||
handleInputFocus = () => {
|
||||
this.setState({
|
||||
inputFocused: true,
|
||||
inputValue: this.valueForInput(this.props.value)
|
||||
});
|
||||
};
|
||||
|
||||
handleInputChange = (event) => {
|
||||
this.setState({inputValue: event.target.value});
|
||||
};
|
||||
|
||||
handleInputBlur = () => {
|
||||
const value = this.state.inputValue || 0;
|
||||
this.setState({inputFocused: false, inputValue: null}, () => {
|
||||
this.props.onChange(this.trimValue(value));
|
||||
});
|
||||
};
|
||||
|
||||
handleKeyDown = (event) => {
|
||||
if ([13, 27].indexOf(event.keyCode) !== -1) {
|
||||
this.refs.input.blur();
|
||||
ReactDOM.findDOMNode(this).blur();
|
||||
}
|
||||
if (event.keyCode === 38) this.addToValue(this.props.step);
|
||||
if (event.keyCode === 40) this.addToValue(-this.props.step);
|
||||
};
|
||||
|
||||
handleMouseDown = (event) => {
|
||||
if (this.state.inputFocused) this.refs.input.blur();
|
||||
events.addEventsToDocument(this.getMouseEventMap());
|
||||
this.start(events.getMousePosition(event));
|
||||
events.pauseEvent(event);
|
||||
};
|
||||
|
||||
handleMouseMove = (event) => {
|
||||
events.pauseEvent(event);
|
||||
this.move(events.getMousePosition(event));
|
||||
};
|
||||
|
||||
handleMouseUp = () => {
|
||||
this.end(this.getMouseEventMap());
|
||||
};
|
||||
|
||||
handleResize = (event, callback) => {
|
||||
const {left, right} = ReactDOM.findDOMNode(this.refs.progressbar).getBoundingClientRect();
|
||||
const cb = callback || () => {};
|
||||
this.setState({sliderStart: left, sliderLength: right - left}, cb);
|
||||
};
|
||||
|
||||
handleSliderBlur = () => {
|
||||
events.removeEventsFromDocument(this.getKeyboardEvents());
|
||||
};
|
||||
|
||||
handleSliderFocus = () => {
|
||||
events.addEventsToDocument(this.getKeyboardEvents());
|
||||
};
|
||||
|
||||
handleTouchEnd = () => {
|
||||
this.end(this.getTouchEventMap());
|
||||
};
|
||||
|
||||
handleTouchMove = (event) => {
|
||||
this.move(events.getTouchPosition(event));
|
||||
};
|
||||
|
||||
handleTouchStart = (event) => {
|
||||
if (this.state.inputFocused) this.refs.input.blur();
|
||||
this.start(events.getTouchPosition(event));
|
||||
events.addEventsToDocument(this.getTouchEventMap());
|
||||
events.pauseEvent(event);
|
||||
};
|
||||
|
||||
addToValue (increment) {
|
||||
let value = this.state.inputFocused ? parseFloat(this.state.inputValue) : this.props.value;
|
||||
value = this.trimValue(value + increment);
|
||||
if (value !== this.props.value) this.props.onChange(value);
|
||||
}
|
||||
|
||||
getKeyboardEvents () {
|
||||
return {
|
||||
keydown: this.handleKeyDown
|
||||
};
|
||||
}
|
||||
|
||||
getMouseEventMap () {
|
||||
return {
|
||||
mousemove: this.handleMouseMove,
|
||||
mouseup: this.handleMouseUp
|
||||
};
|
||||
}
|
||||
|
||||
getTouchEventMap () {
|
||||
return {
|
||||
touchmove: this.handleTouchMove,
|
||||
touchend: this.handleTouchEnd
|
||||
};
|
||||
}
|
||||
|
||||
end (revents) {
|
||||
events.removeEventsFromDocument(revents);
|
||||
this.setState({ pressed: false });
|
||||
}
|
||||
|
||||
knobOffset () {
|
||||
const { max, min } = this.props;
|
||||
return this.state.sliderLength * (this.props.value - min) / (max - min);
|
||||
}
|
||||
|
||||
move (position) {
|
||||
const newValue = this.positionToValue(position);
|
||||
if (newValue !== this.props.value) this.props.onChange(newValue);
|
||||
}
|
||||
|
||||
positionToValue (position) {
|
||||
const { sliderStart: start, sliderLength: length } = this.state;
|
||||
const { max, min } = this.props;
|
||||
return this.trimValue((position.x - start) / length * (max - min) + min);
|
||||
}
|
||||
|
||||
start (position) {
|
||||
this.handleResize(null, () => {
|
||||
this.setState({pressed: true});
|
||||
this.props.onChange(this.positionToValue(position));
|
||||
});
|
||||
}
|
||||
|
||||
stepDecimals () {
|
||||
return (this.props.step.toString().split('.')[1] || []).length;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
valueForInput (value) {
|
||||
const decimals = this.stepDecimals();
|
||||
return decimals > 0 ? value.toFixed(decimals) : value.toString();
|
||||
}
|
||||
|
||||
renderSnaps () {
|
||||
if (this.props.snaps) {
|
||||
return (
|
||||
<div ref='snaps' className={style.snaps}>
|
||||
{ utils.range(0, (this.props.max - this.props.min) / this.props.step).map(i => {
|
||||
return <div key={`span-${i}`} className={style.snap}></div>;
|
||||
}) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderInput () {
|
||||
if (this.props.editable) {
|
||||
const value = this.state.inputFocused ? this.state.inputValue : this.valueForInput(this.props.value);
|
||||
return (
|
||||
<Input
|
||||
ref='input'
|
||||
className={style.input}
|
||||
onFocus={this.handleInputFocus}
|
||||
onChange={this.handleInputChange}
|
||||
onBlur={this.handleInputBlur}
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const knobStyles = prefixer({transform: `translateX(${this.knobOffset()}px)`});
|
||||
let className = this.props.className;
|
||||
if (this.props.editable) className += ` ${style.editable}`;
|
||||
if (this.props.pinned) className += ` ${style.pinned}`;
|
||||
if (this.state.pressed) className += ` ${style.pressed}`;
|
||||
if (this.props.value === this.props.min) className += ` ${style.ring}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={style.root + className}
|
||||
data-react-toolbox='slider'
|
||||
onBlur={this.handleSliderBlur}
|
||||
onFocus={this.handleSliderFocus}
|
||||
tabIndex='0'
|
||||
>
|
||||
<div
|
||||
ref='slider'
|
||||
className={style.container}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
>
|
||||
<div
|
||||
ref='knob'
|
||||
className={style.knob}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
style={knobStyles}
|
||||
>
|
||||
<div className={style.innerknob} data-value={parseInt(this.props.value)}></div>
|
||||
</div>
|
||||
|
||||
<div className={style.progress}>
|
||||
<ProgressBar
|
||||
ref='progressbar'
|
||||
className={style.innerprogress}
|
||||
max={this.props.max}
|
||||
min={this.props.min}
|
||||
mode='determinate'
|
||||
value={this.props.value}
|
||||
/>
|
||||
{ this.renderSnaps() }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ this.renderInput() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Slider;
|
||||
export default from './Slider';
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import React from 'react';
|
||||
import Button from '../button';
|
||||
import FontIcon from '../font_icon';
|
||||
import Overlay from '../overlay';
|
||||
import style from './style';
|
||||
|
||||
class Snackbar extends React.Component {
|
||||
static propTypes = {
|
||||
action: React.PropTypes.string,
|
||||
active: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
icon: React.PropTypes.string,
|
||||
label: React.PropTypes.string.isRequired,
|
||||
onClick: React.PropTypes.func,
|
||||
onTimeout: React.PropTypes.func,
|
||||
timeout: React.PropTypes.number,
|
||||
type: React.PropTypes.string
|
||||
};
|
||||
|
||||
componentDidUpdate () {
|
||||
if (this.props.active && this.props.timeout) {
|
||||
setTimeout(() => {
|
||||
this.props.onTimeout();
|
||||
}, this.props.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
renderButton () {
|
||||
if (this.props.action) {
|
||||
return (
|
||||
<Button
|
||||
className={style.button}
|
||||
label={this.props.action}
|
||||
onClick={this.props.onClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = `${style.root} ${style[this.props.type]}`;
|
||||
if (this.props.active) className += ` ${style.active}`;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<Overlay active={this.props.active} opacity={0}>
|
||||
<div data-react-toolbox='snackbar' className={className}>
|
||||
{this.props.icon ? <FontIcon value={this.props.icon} className={style.icon} /> : null}
|
||||
<span className={style.label}>{this.props.label}</span>
|
||||
{this.renderButton()}
|
||||
</div>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Snackbar;
|
|
@ -1,57 +1 @@
|
|||
import React from 'react';
|
||||
import Button from '../button';
|
||||
import FontIcon from '../font_icon';
|
||||
import Overlay from '../overlay';
|
||||
import style from './style';
|
||||
|
||||
class Snackbar extends React.Component {
|
||||
static propTypes = {
|
||||
action: React.PropTypes.string,
|
||||
active: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
icon: React.PropTypes.string,
|
||||
label: React.PropTypes.string.isRequired,
|
||||
onClick: React.PropTypes.func,
|
||||
onTimeout: React.PropTypes.func,
|
||||
timeout: React.PropTypes.number,
|
||||
type: React.PropTypes.string
|
||||
};
|
||||
|
||||
componentDidUpdate () {
|
||||
if (this.props.active && this.props.timeout) {
|
||||
setTimeout(() => {
|
||||
this.props.onTimeout();
|
||||
}, this.props.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
renderButton () {
|
||||
if (this.props.action) {
|
||||
return (
|
||||
<Button
|
||||
className={style.button}
|
||||
label={this.props.action}
|
||||
onClick={this.props.onClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = `${style.root} ${style[this.props.type]}`;
|
||||
if (this.props.active) className += ` ${style.active}`;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<Overlay active={this.props.active} opacity={0}>
|
||||
<div data-react-toolbox='snackbar' className={className}>
|
||||
{ this.props.icon ? <FontIcon value={this.props.icon} className={style.icon} /> : null }
|
||||
<span className={style.label}>{this.props.label}</span>
|
||||
{ this.renderButton() }
|
||||
</div>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Snackbar;
|
||||
export default from './Snackbar.jsx';
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import React from 'react';
|
||||
import Ripple from '../ripple';
|
||||
import style from './style';
|
||||
import events from '../utils/events';
|
||||
|
||||
class Switch extends React.Component {
|
||||
static propTypes = {
|
||||
checked: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
disabled: React.PropTypes.bool,
|
||||
label: React.PropTypes.string,
|
||||
name: React.PropTypes.string,
|
||||
onBlur: React.PropTypes.func,
|
||||
onChange: React.PropTypes.func,
|
||||
onFocus: React.PropTypes.func
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
checked: false,
|
||||
className: '',
|
||||
disabled: false
|
||||
};
|
||||
|
||||
handleChange = (event) => {
|
||||
events.pauseEvent(event);
|
||||
if (this.props.onChange && !this.props.disabled) this.props.onChange(event);
|
||||
};
|
||||
|
||||
handleInputClick = (event) => {
|
||||
events.pauseEvent(event);
|
||||
};
|
||||
|
||||
handleMouseDown = (event) => {
|
||||
if (!this.props.disabled) this.refs.ripple.start(event);
|
||||
};
|
||||
|
||||
blur () {
|
||||
this.refs.input.blur();
|
||||
}
|
||||
|
||||
focus () {
|
||||
this.refs.input.focus();
|
||||
}
|
||||
|
||||
render () {
|
||||
let labelClassName = style[this.props.disabled ? 'disabled' : 'field'];
|
||||
const switchClassName = style[this.props.checked ? 'on' : 'off'];
|
||||
if (this.props.className) labelClassName += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<label
|
||||
data-react-toolbox='checkbox'
|
||||
className={labelClassName}
|
||||
onClick={this.handleChange}
|
||||
>
|
||||
<input
|
||||
{...this.props}
|
||||
ref='input'
|
||||
checked={this.props.checked}
|
||||
className={style.input}
|
||||
onChange={this.handleChange}
|
||||
onClick={this.handleInputClick}
|
||||
type='checkbox'
|
||||
/>
|
||||
<span role='switch' className={switchClassName}>
|
||||
<span role='thumb' className={style.thumb} onMouseDown={this.handleMouseDown}>
|
||||
<Ripple ref='ripple' role='ripple' className={style.ripple} spread={2.4} centered />
|
||||
</span>
|
||||
</span>
|
||||
{this.props.label ? <span className={style.text}>{this.props.label}</span> : null}
|
||||
</label>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Switch;
|
|
@ -1,76 +1 @@
|
|||
import React from 'react';
|
||||
import Ripple from '../ripple';
|
||||
import style from './style';
|
||||
import events from '../utils/events';
|
||||
|
||||
class Switch extends React.Component {
|
||||
static propTypes = {
|
||||
checked: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
disabled: React.PropTypes.bool,
|
||||
label: React.PropTypes.string,
|
||||
name: React.PropTypes.string,
|
||||
onBlur: React.PropTypes.func,
|
||||
onChange: React.PropTypes.func,
|
||||
onFocus: React.PropTypes.func
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
checked: false,
|
||||
className: '',
|
||||
disabled: false
|
||||
};
|
||||
|
||||
handleChange = (event) => {
|
||||
events.pauseEvent(event);
|
||||
if (this.props.onChange && !this.props.disabled) this.props.onChange(event);
|
||||
};
|
||||
|
||||
handleInputClick = (event) => {
|
||||
events.pauseEvent(event);
|
||||
};
|
||||
|
||||
handleMouseDown = (event) => {
|
||||
if (!this.props.disabled) this.refs.ripple.start(event);
|
||||
};
|
||||
|
||||
render () {
|
||||
let labelClassName = style[this.props.disabled ? 'disabled' : 'field'];
|
||||
const switchClassName = style[this.props.checked ? 'on' : 'off'];
|
||||
if (this.props.className) labelClassName += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<label
|
||||
data-react-toolbox='checkbox'
|
||||
className={labelClassName}
|
||||
onClick={this.handleChange}
|
||||
>
|
||||
<input
|
||||
{...this.props}
|
||||
ref='input'
|
||||
checked={this.props.checked}
|
||||
className={style.input}
|
||||
onChange={this.handleChange}
|
||||
onClick={this.handleInputClick}
|
||||
type='checkbox'
|
||||
/>
|
||||
<span role='switch' className={switchClassName}>
|
||||
<span role='thumb' className={style.thumb} onMouseDown={this.handleMouseDown}>
|
||||
<Ripple ref='ripple' role='ripple' className={style.ripple} spread={2.4} centered />
|
||||
</span>
|
||||
</span>
|
||||
{ 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 Switch;
|
||||
export default from './Switch.jsx';
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
import React from 'react';
|
||||
import TableHead from './TableHead';
|
||||
import TableRow from './TableRow';
|
||||
import style from './style';
|
||||
|
||||
class Table extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
heading: React.PropTypes.bool,
|
||||
model: React.PropTypes.object,
|
||||
onChange: React.PropTypes.func,
|
||||
onSelect: React.PropTypes.func,
|
||||
selectable: React.PropTypes.bool,
|
||||
selected: React.PropTypes.array,
|
||||
source: React.PropTypes.array
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
heading: true,
|
||||
selectable: true,
|
||||
selected: [],
|
||||
source: []
|
||||
};
|
||||
|
||||
handleFullSelect = () => {
|
||||
if (this.props.onSelect) {
|
||||
const {source, selected} = this.props;
|
||||
const newSelected = source.length === selected.length ? [] : source.map((i, idx) => idx);
|
||||
this.props.onSelect(newSelected);
|
||||
}
|
||||
};
|
||||
|
||||
handleRowSelect = (index) => {
|
||||
if (this.props.onSelect) {
|
||||
const position = this.props.selected.indexOf(index);
|
||||
const newSelected = [...this.props.selected];
|
||||
if (position !== -1) newSelected.splice(position, 1); else newSelected.push(index);
|
||||
this.props.onSelect(newSelected);
|
||||
}
|
||||
};
|
||||
|
||||
handleRowChange = (index, key, value) => {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(index, key, value);
|
||||
}
|
||||
};
|
||||
|
||||
renderHead () {
|
||||
if (this.props.heading) {
|
||||
const {model, selected, source, selectable} = this.props;
|
||||
const isSelected = selected.length === source.length;
|
||||
return (
|
||||
<TableHead
|
||||
model={model}
|
||||
onSelect={this.handleFullSelect}
|
||||
selectable={selectable}
|
||||
selected={isSelected}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderBody () {
|
||||
const rows = this.props.source.map((data, idx) => {
|
||||
return (
|
||||
<TableRow
|
||||
data={data}
|
||||
index={idx}
|
||||
key={idx}
|
||||
model={this.props.model}
|
||||
onChange={this.handleRowChange.bind(this, idx)}
|
||||
onSelect={this.handleRowSelect.bind(this, idx)}
|
||||
selectable={this.props.selectable}
|
||||
selected={this.props.selected.indexOf(idx) !== -1}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return <tbody>{rows}</tbody>;
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = style.root;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
return (
|
||||
<table data-react-toolbox='table' className={className}>
|
||||
{this.renderHead()}
|
||||
{this.renderBody()}
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Table;
|
|
@ -6,6 +6,7 @@ import style from './style';
|
|||
class TableRow extends React.Component {
|
||||
static propTypes = {
|
||||
data: React.PropTypes.object,
|
||||
model: React.PropTypes.object,
|
||||
onChange: React.PropTypes.func,
|
||||
onSelect: React.PropTypes.func,
|
||||
selectable: React.PropTypes.bool,
|
||||
|
@ -63,8 +64,8 @@ class TableRow extends React.Component {
|
|||
|
||||
return (
|
||||
<tr data-react-toolbox-table='row' className={className}>
|
||||
{ this.renderSelectCell() }
|
||||
{ this.renderCells() }
|
||||
{this.renderSelectCell()}
|
||||
{this.renderCells()}
|
||||
</tr>
|
||||
);
|
||||
}
|
|
@ -1,95 +1 @@
|
|||
import React from 'react';
|
||||
import TableHead from './head';
|
||||
import TableRow from './row';
|
||||
import style from './style';
|
||||
|
||||
class Table extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
heading: React.PropTypes.bool,
|
||||
model: React.PropTypes.object,
|
||||
onChange: React.PropTypes.func,
|
||||
onSelect: React.PropTypes.func,
|
||||
selectable: React.PropTypes.bool,
|
||||
selected: React.PropTypes.array,
|
||||
source: React.PropTypes.array
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
heading: true,
|
||||
selectable: true,
|
||||
selected: [],
|
||||
source: []
|
||||
};
|
||||
|
||||
handleFullSelect = () => {
|
||||
if (this.props.onSelect) {
|
||||
const {source, selected} = this.props;
|
||||
const newSelected = source.length === selected.length ? [] : source.map((i, idx) => idx);
|
||||
this.props.onSelect(newSelected);
|
||||
}
|
||||
};
|
||||
|
||||
handleRowSelect = (index) => {
|
||||
if (this.props.onSelect) {
|
||||
const position = this.props.selected.indexOf(index);
|
||||
const newSelected = [...this.props.selected];
|
||||
if (position !== -1) newSelected.splice(position, 1); else newSelected.push(index);
|
||||
this.props.onSelect(newSelected);
|
||||
}
|
||||
};
|
||||
|
||||
handleRowChange = (index, key, value) => {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(index, key, value);
|
||||
}
|
||||
};
|
||||
|
||||
renderHead () {
|
||||
if (this.props.heading) {
|
||||
const {model, selected, source, selectable} = this.props;
|
||||
const isSelected = selected.length === source.length;
|
||||
return (
|
||||
<TableHead
|
||||
model={model}
|
||||
onSelect={this.handleFullSelect}
|
||||
selectable={selectable}
|
||||
selected={isSelected}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderBody () {
|
||||
const rows = this.props.source.map((data, idx) => {
|
||||
return (
|
||||
<TableRow
|
||||
data={data}
|
||||
index={idx}
|
||||
key={idx}
|
||||
model={this.props.model}
|
||||
onChange={this.handleRowChange.bind(this, idx)}
|
||||
onSelect={this.handleRowSelect.bind(this, idx)}
|
||||
selectable={this.props.selectable}
|
||||
selected={this.props.selected.indexOf(idx) !== -1}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return <tbody>{rows}</tbody>;
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = style.root;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
return (
|
||||
<table data-react-toolbox='table' className={className}>
|
||||
{ this.renderHead() }
|
||||
{ this.renderBody() }
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Table;
|
||||
export default from './Table.jsx';
|
||||
|
|
|
@ -39,7 +39,7 @@ class TableTest extends React.Component {
|
|||
model={UserModel}
|
||||
onChange={this.handleChange}
|
||||
onSelect={this.handleSelect}
|
||||
selectable={true}
|
||||
selectable
|
||||
selected={this.state.selected}
|
||||
source={this.state.source}
|
||||
/>
|
||||
|
|
|
@ -4,6 +4,7 @@ import style from './style';
|
|||
class TabContent extends React.Component {
|
||||
static propTypes = {
|
||||
active: React.PropTypes.bool,
|
||||
children: React.PropTypes.node,
|
||||
className: React.PropTypes.string,
|
||||
tabIndex: React.PropTypes.number
|
||||
};
|
|
@ -1,4 +1,2 @@
|
|||
import Tabs from './tabs';
|
||||
import Tab from './tab';
|
||||
|
||||
export default { Tabs, Tab };
|
||||
export Tabs from './Tabs.jsx';
|
||||
export Tab from './Tab.jsx';
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React from 'react';
|
||||
import Tab from './tab';
|
||||
import Content from './content';
|
||||
import Tab from './Tab';
|
||||
import TabContent from './TabContent';
|
||||
import style from './style';
|
||||
|
||||
class Tabs extends React.Component {
|
||||
static propTypes = {
|
||||
index: React.PropTypes.number,
|
||||
children: React.PropTypes.node,
|
||||
className: React.PropTypes.string,
|
||||
index: React.PropTypes.number,
|
||||
onChange: React.PropTypes.func
|
||||
};
|
||||
|
||||
|
@ -18,16 +19,16 @@ class Tabs extends React.Component {
|
|||
pointer: {}
|
||||
};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.updatePointer(nextProps.index);
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
setTimeout(() => {
|
||||
this.updatePointer(this.props.index);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.updatePointer(nextProps.index);
|
||||
}
|
||||
|
||||
handleHeaderClick = (idx) => {
|
||||
if (this.props.onChange) this.props.onChange(idx);
|
||||
};
|
||||
|
@ -40,9 +41,9 @@ class Tabs extends React.Component {
|
|||
if (item.type === Tab) {
|
||||
headers.push(item);
|
||||
if (item.props.children) {
|
||||
contents.push(<Content children={item.props.children}/>);
|
||||
contents.push(<TabContent children={item.props.children}/>);
|
||||
}
|
||||
} else if (item.type === Content) {
|
||||
} else if (item.type === TabContent) {
|
||||
contents.push(item);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import React from 'react';
|
||||
import events from '../utils/events';
|
||||
import time from '../utils/time';
|
||||
import style from './style';
|
||||
import Input from '../input';
|
||||
import TimePickerDialog from './TimePickerDialog';
|
||||
|
||||
class TimePicker extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
format: React.PropTypes.oneOf(['24hr', 'ampm']),
|
||||
label: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func,
|
||||
value: React.PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
format: '24hr'
|
||||
};
|
||||
|
||||
state = {
|
||||
active: false
|
||||
};
|
||||
|
||||
handleDismiss = () => {
|
||||
this.setState({active: false});
|
||||
};
|
||||
|
||||
handleInputMouseDown = (event) => {
|
||||
events.pauseEvent(event);
|
||||
this.setState({active: true});
|
||||
};
|
||||
|
||||
handleSelect = (value) => {
|
||||
if (this.props.onChange) this.props.onChange(value);
|
||||
this.setState({active: false});
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, format } = this.props;
|
||||
const formattedTime = value ? time.formatTime(value, format) : null;
|
||||
return (
|
||||
<div data-react-toolbox='time-picker'>
|
||||
<Input
|
||||
className={style.input}
|
||||
label={this.props.label}
|
||||
onMouseDown={this.handleInputMouseDown}
|
||||
readOnly
|
||||
type='text'
|
||||
value={formattedTime}
|
||||
/>
|
||||
<TimePickerDialog
|
||||
active={this.state.active}
|
||||
format={format}
|
||||
onDismiss={this.handleDismiss}
|
||||
onSelect={this.handleSelect}
|
||||
value={this.props.value}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TimePicker;
|
|
@ -78,13 +78,13 @@ class TimePickerDialog extends React.Component {
|
|||
<Dialog active={this.props.active} className={className} actions={this.actions}>
|
||||
<header className={style.header}>
|
||||
<span className={style.hours} onClick={this.switchDisplay.bind(this, 'hours')}>
|
||||
{ ('0' + this.formatHours()).slice(-2) }
|
||||
{('0' + this.formatHours()).slice(-2)}
|
||||
</span>
|
||||
<span className={style.separator}>:</span>
|
||||
<span className={style.minutes} onClick={this.switchDisplay.bind(this, 'minutes')}>
|
||||
{ ('0' + this.state.displayTime.getMinutes()).slice(-2) }
|
||||
{('0' + this.state.displayTime.getMinutes()).slice(-2)}
|
||||
</span>
|
||||
{ this.renderAMPMLabels() }
|
||||
{this.renderAMPMLabels()}
|
||||
</header>
|
||||
<Clock
|
||||
ref='clock'
|
|
@ -0,0 +1,106 @@
|
|||
import React from 'react';
|
||||
import style from './style';
|
||||
import time from '../../utils/time';
|
||||
import Hours from './Hours';
|
||||
import Minutes from './Minutes';
|
||||
|
||||
class Clock extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
display: React.PropTypes.oneOf(['hours', 'minutes']),
|
||||
format: React.PropTypes.oneOf(['24hr', 'ampm']),
|
||||
onChange: React.PropTypes.func,
|
||||
time: React.PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
display: 'hours',
|
||||
format: '24hr',
|
||||
time: new Date()
|
||||
};
|
||||
|
||||
state = {
|
||||
center: {x: null, y: null},
|
||||
radius: 0
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('resize', this.handleCalculateShape);
|
||||
this.handleCalculateShape();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('resize', this.handleCalculateShape);
|
||||
}
|
||||
|
||||
handleHourChange = (hours) => {
|
||||
if (this.props.time.getHours() !== hours) {
|
||||
this.props.onChange(time.setHours(this.props.time, this.adaptHourToFormat(hours)));
|
||||
}
|
||||
};
|
||||
|
||||
handleMinuteChange = (minutes) => {
|
||||
if (this.props.time.getMinutes() !== minutes) {
|
||||
this.props.onChange(time.setMinutes(this.props.time, minutes));
|
||||
}
|
||||
};
|
||||
|
||||
handleCalculateShape = () => {
|
||||
const { top, left, width } = this.refs.wrapper.getBoundingClientRect();
|
||||
this.setState({
|
||||
center: { x: left + width / 2, y: top + width / 2 },
|
||||
radius: width / 2
|
||||
});
|
||||
};
|
||||
|
||||
adaptHourToFormat (hour) {
|
||||
if (this.props.format === 'ampm') {
|
||||
if (time.getTimeMode(this.props.time) === 'pm') {
|
||||
return hour < 12 ? hour + 12 : hour;
|
||||
} else {
|
||||
return hour === 12 ? 0 : hour;
|
||||
}
|
||||
} else {
|
||||
return hour;
|
||||
}
|
||||
}
|
||||
|
||||
renderHours () {
|
||||
return (
|
||||
<Hours
|
||||
center={this.state.center}
|
||||
format={this.props.format}
|
||||
onChange={this.handleHourChange}
|
||||
radius={this.state.radius}
|
||||
selected={this.props.time.getHours()}
|
||||
spacing={this.state.radius * 0.18}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderMinutes () {
|
||||
return (
|
||||
<Minutes
|
||||
center={this.state.center}
|
||||
onChange={this.handleMinuteChange}
|
||||
radius={this.state.radius}
|
||||
selected={this.props.time.getMinutes()}
|
||||
spacing={this.state.radius * 0.18}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div data-react-toolbox='clock' className={style.root}>
|
||||
<div ref='wrapper' className={style.wrapper} style={{height: this.state.radius * 2}}>
|
||||
{this.props.display === 'hours' ? this.renderHours() : null}
|
||||
{this.props.display === 'minutes' ? this.renderMinutes() : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Clock;
|
|
@ -2,6 +2,14 @@ import React from 'react';
|
|||
import style from './style';
|
||||
|
||||
class Face extends React.Component {
|
||||
static propTypes = {
|
||||
active: React.PropTypes.number,
|
||||
numbers: React.PropTypes.array,
|
||||
radius: React.PropTypes.number,
|
||||
spacing: React.PropTypes.number,
|
||||
twoDigits: React.PropTypes.bool
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
active: null,
|
||||
numbers: [],
|
||||
|
@ -33,7 +41,7 @@ class Face extends React.Component {
|
|||
style={this.numberStyle(this.props.radius - this.props.spacing, idx + 1)}
|
||||
key={number}
|
||||
>
|
||||
{ this.props.twoDigits ? ('0' + number).slice(-2) : number }
|
||||
{this.props.twoDigits ? ('0' + number).slice(-2) : number}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -47,7 +55,7 @@ class Face extends React.Component {
|
|||
onMouseDown={this.props.onMouseDown}
|
||||
style={this.faceStyle()}
|
||||
>
|
||||
{ this.props.numbers.map(this.renderNumber.bind(this))}
|
||||
{this.props.numbers.map(this.renderNumber.bind(this))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@ import utils from '../../utils/utils';
|
|||
|
||||
class Hand extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
angle: React.PropTypes.number,
|
||||
className: React.PropTypes.string,
|
||||
length: React.PropTypes.number,
|
||||
onMove: React.PropTypes.func,
|
||||
onMoved: React.PropTypes.func
|
||||
onMoved: React.PropTypes.func,
|
||||
origin: React.PropTypes.object,
|
||||
step: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import utils from '../../utils/utils';
|
||||
import Face from './face';
|
||||
import Hand from './hand';
|
||||
import Face from './Face';
|
||||
import Hand from './Hand';
|
||||
|
||||
const outerNumbers = [0, ...utils.range(13, 24)];
|
||||
const innerNumbers = [12, ...utils.range(1, 12)];
|
||||
|
@ -10,10 +10,13 @@ const step = 360 / 12;
|
|||
|
||||
class Hours extends React.Component {
|
||||
static propTypes = {
|
||||
center: React.PropTypes.object,
|
||||
format: React.PropTypes.oneOf(['24hr', 'ampm']),
|
||||
onChange: React.PropTypes.func,
|
||||
onHandMoved: React.PropTypes.func,
|
||||
selected: React.PropTypes.number
|
||||
radius: React.PropTypes.number,
|
||||
selected: React.PropTypes.number,
|
||||
spacing: React.PropTypes.number
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -77,7 +80,7 @@ class Hours extends React.Component {
|
|||
twoDigits={is24hr}
|
||||
active={is24hr ? selected : (selected % 12 || 12)}
|
||||
/>
|
||||
{ this.renderInnerFace(radius - spacing * innerSpacing) }
|
||||
{this.renderInnerFace(radius - spacing * innerSpacing)}
|
||||
<Hand ref='hand'
|
||||
angle={selected * step}
|
||||
length={(this.state.inner ? radius - spacing * innerSpacing : radius) - spacing}
|
||||
|
|
|
@ -1,106 +1 @@
|
|||
import React from 'react';
|
||||
import style from './style';
|
||||
import time from '../../utils/time';
|
||||
import Hours from './hours';
|
||||
import Minutes from './minutes';
|
||||
|
||||
class Clock extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
display: React.PropTypes.oneOf(['hours', 'minutes']),
|
||||
format: React.PropTypes.oneOf(['24hr', 'ampm']),
|
||||
time: React.PropTypes.object,
|
||||
onChange: React.PropTypes.func
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
display: 'hours',
|
||||
format: '24hr',
|
||||
time: new Date()
|
||||
};
|
||||
|
||||
state = {
|
||||
center: {x: null, y: null},
|
||||
radius: 0
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('resize', this.handleCalculateShape);
|
||||
this.handleCalculateShape();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('resize', this.handleCalculateShape);
|
||||
}
|
||||
|
||||
handleHourChange = (hours) => {
|
||||
if (this.props.time.getHours() !== hours) {
|
||||
this.props.onChange(time.setHours(this.props.time, this.adaptHourToFormat(hours)));
|
||||
}
|
||||
};
|
||||
|
||||
handleMinuteChange = (minutes) => {
|
||||
if (this.props.time.getMinutes() !== minutes) {
|
||||
this.props.onChange(time.setMinutes(this.props.time, minutes));
|
||||
}
|
||||
};
|
||||
|
||||
handleCalculateShape = () => {
|
||||
const { top, left, width } = this.refs.wrapper.getBoundingClientRect();
|
||||
this.setState({
|
||||
center: { x: left + width / 2, y: top + width / 2 },
|
||||
radius: width / 2
|
||||
});
|
||||
};
|
||||
|
||||
adaptHourToFormat (hour) {
|
||||
if (this.props.format === 'ampm') {
|
||||
if (time.getTimeMode(this.props.time) === 'pm') {
|
||||
return hour < 12 ? hour + 12 : hour;
|
||||
} else {
|
||||
return hour === 12 ? 0 : hour;
|
||||
}
|
||||
} else {
|
||||
return hour;
|
||||
}
|
||||
}
|
||||
|
||||
renderHours () {
|
||||
return (
|
||||
<Hours
|
||||
center={this.state.center}
|
||||
format={this.props.format}
|
||||
onChange={this.handleHourChange}
|
||||
radius={this.state.radius}
|
||||
selected={this.props.time.getHours()}
|
||||
spacing={this.state.radius * 0.18}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderMinutes () {
|
||||
return (
|
||||
<Minutes
|
||||
center={this.state.center}
|
||||
onChange={this.handleMinuteChange}
|
||||
radius={this.state.radius}
|
||||
selected={this.props.time.getMinutes()}
|
||||
spacing={this.state.radius * 0.18}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div data-react-toolbox='clock' className={style.root}>
|
||||
<div ref='wrapper' className={style.wrapper} style={{height: this.state.radius * 2}}>
|
||||
{ this.props.display === 'hours' ? this.renderHours() : null }
|
||||
{ this.props.display === 'minutes' ? this.renderMinutes() : null }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Clock;
|
||||
export default from './Clock.jsx';
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import React from 'react';
|
||||
import utils from '../../utils/utils';
|
||||
import style from './style';
|
||||
import Face from './face';
|
||||
import Hand from './hand';
|
||||
import Face from './Face';
|
||||
import Hand from './Hand';
|
||||
|
||||
const minutes = utils.range(0, 60, 5);
|
||||
const step = 360 / 60;
|
||||
|
||||
class Minutes extends React.Component {
|
||||
static propTypes = {
|
||||
center: React.PropTypes.object,
|
||||
onChange: React.PropTypes.func,
|
||||
radius: React.PropTypes.number,
|
||||
selected: React.PropTypes.number,
|
||||
onChange: React.PropTypes.func
|
||||
spacing: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -39,7 +42,7 @@ class Minutes extends React.Component {
|
|||
numbers={minutes}
|
||||
spacing={this.props.spacing}
|
||||
radius={this.props.radius}
|
||||
twoDigits={true}
|
||||
twoDigits
|
||||
active={this.props.selected}
|
||||
/>
|
||||
<Hand ref='hand'
|
||||
|
|
|
@ -1,65 +1 @@
|
|||
import React from 'react';
|
||||
import events from '../utils/events';
|
||||
import time from '../utils/time';
|
||||
import style from './style';
|
||||
import Input from '../input';
|
||||
import TimeDialog from './dialog';
|
||||
|
||||
class TimePicker extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
format: React.PropTypes.oneOf(['24hr', 'ampm']),
|
||||
label: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func,
|
||||
value: React.PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
format: '24hr'
|
||||
};
|
||||
|
||||
state = {
|
||||
active: false
|
||||
};
|
||||
|
||||
handleDismiss = () => {
|
||||
this.setState({active: false});
|
||||
};
|
||||
|
||||
handleInputMouseDown = (event) => {
|
||||
events.pauseEvent(event);
|
||||
this.setState({active: true});
|
||||
};
|
||||
|
||||
handleSelect = (value) => {
|
||||
if (this.props.onChange) this.props.onChange(value);
|
||||
this.setState({active: false});
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, format } = this.props;
|
||||
const formattedTime = value ? time.formatTime(value, format) : null;
|
||||
return (
|
||||
<div data-react-toolbox='time-picker'>
|
||||
<Input
|
||||
className={style.input}
|
||||
label={this.props.label}
|
||||
onMouseDown={this.handleInputMouseDown}
|
||||
readOnly={true}
|
||||
type='text'
|
||||
value={formattedTime}
|
||||
/>
|
||||
<TimeDialog
|
||||
active={this.state.active}
|
||||
format={format}
|
||||
onDismiss={this.handleDismiss}
|
||||
onSelect={this.handleSelect}
|
||||
value={this.props.value}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TimePicker;
|
||||
export default from './TimePicker.jsx';
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import style from './style';
|
||||
|
||||
const HIDE_TIMEOUT = 100;
|
||||
|
||||
class Tooltip extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
delay: React.PropTypes.number,
|
||||
label: React.PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
delay: 0
|
||||
};
|
||||
|
||||
state = {
|
||||
active: false
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
const parent = ReactDOM.findDOMNode(this).parentNode;
|
||||
|
||||
if (parent.style.position !== 'relative' && parent.style.position !== 'absolute'){
|
||||
parent.style.position = 'relative';
|
||||
}
|
||||
|
||||
parent.onmouseover = this.handleParentMouseOver;
|
||||
parent.onmouseout = this.handleParentMouseOut;
|
||||
};
|
||||
|
||||
handleParentMouseOver = () => {
|
||||
setTimeout(() => {
|
||||
if (this.deferredHide) clearTimeout(this.deferredHide);
|
||||
const node = ReactDOM.findDOMNode(this);
|
||||
const parent = node.parentNode;
|
||||
const parentStyle = parent.currentStyle || window.getComputedStyle(parent);
|
||||
const offset = parseFloat(parentStyle['margin-bottom']) + parseFloat(parentStyle['padding-bottom']);
|
||||
const position = parent.getBoundingClientRect();
|
||||
|
||||
node.style.top = `${position.height - offset}px`;
|
||||
node.style.left = `${parseInt((position.width / 2) - (node.offsetWidth / 2))}px`;
|
||||
if (!this.state.active) this.setState({ active: true});
|
||||
}, this.props.delay);
|
||||
};
|
||||
|
||||
handleParentMouseOut = () => {
|
||||
if (this.state.active) {
|
||||
this.deferredHide = setTimeout(() => { this.setState({active: false}); }, HIDE_TIMEOUT);
|
||||
console.log(this.deferredHide);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
let className = style.root;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
if (this.state.active) className += ` ${style.active}`;
|
||||
|
||||
return (
|
||||
<span data-react-toolbox='tooltip' className={className}>
|
||||
{this.props.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Tooltip;
|
|
@ -1,69 +1 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import style from './style';
|
||||
|
||||
const HIDE_TIMEOUT = 100;
|
||||
|
||||
class Tooltip extends React.Component {
|
||||
static propTypes = {
|
||||
className: React.PropTypes.string,
|
||||
delay: React.PropTypes.number,
|
||||
label: React.PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
delay: 0
|
||||
};
|
||||
|
||||
state = {
|
||||
active: false
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
const parent = ReactDOM.findDOMNode(this).parentNode;
|
||||
|
||||
if (parent.style.position !== 'relative' && parent.style.position !== 'absolute'){
|
||||
parent.style.position = 'relative';
|
||||
}
|
||||
|
||||
parent.onmouseover = this.handleParentMouseOver;
|
||||
parent.onmouseout = this.handleParentMouseOut;
|
||||
};
|
||||
|
||||
handleParentMouseOver = () => {
|
||||
setTimeout(() => {
|
||||
if (this.deferredHide) clearTimeout(this.deferredHide);
|
||||
const node = ReactDOM.findDOMNode(this);
|
||||
const parent = node.parentNode;
|
||||
const parentStyle = parent.currentStyle || window.getComputedStyle(parent);
|
||||
const offset = parseFloat(parentStyle['margin-bottom']) + parseFloat(parentStyle['padding-bottom']);
|
||||
const position = parent.getBoundingClientRect();
|
||||
|
||||
node.style.top = `${position.height - offset}px`;
|
||||
node.style.left = `${parseInt((position.width / 2) - (node.offsetWidth / 2))}px`;
|
||||
if (!this.state.active) this.setState({ active: true});
|
||||
}, this.props.delay);
|
||||
};
|
||||
|
||||
handleParentMouseOut = () => {
|
||||
if (this.state.active) {
|
||||
this.deferredHide = setTimeout(() => { this.setState({active: false}); }, HIDE_TIMEOUT);
|
||||
console.log(this.deferredHide);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
let className = style.root;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
if (this.state.active) className += ` ${style.active}`;
|
||||
|
||||
return (
|
||||
<span data-react-toolbox='tooltip' className={className}>
|
||||
{this.props.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Tooltip;
|
||||
export default from './Tooltip.jsx';
|
||||
|
|
|
@ -31,7 +31,7 @@ class TableTest extends React.Component {
|
|||
model={UserModel}
|
||||
onChange={this.handleChange}
|
||||
onSelect={this.handleSelect}
|
||||
selectable={true}
|
||||
selectable
|
||||
selected={this.state.selected}
|
||||
source={this.state.source}
|
||||
/>
|
||||
|
|
|
@ -67,7 +67,7 @@ class DropdownTest extends React.Component {
|
|||
|
||||
<Dropdown
|
||||
source={countries}
|
||||
disabled={true}
|
||||
disabled
|
||||
onChange={this.handleChange.bind(this, 'dropdown3')}
|
||||
/>
|
||||
</section>
|
||||
|
|
|
@ -31,12 +31,12 @@ class IconMenuTest extends React.Component {
|
|||
<IconMenu
|
||||
icon='more-vert'
|
||||
position='auto'
|
||||
iconRipple={true}
|
||||
menuRipple={true}
|
||||
iconRipple
|
||||
menuRipple
|
||||
onShow={this.handleShow}
|
||||
onHide={this.handleHide}
|
||||
onSelect={this.handleSelect}
|
||||
selectable={true}
|
||||
selectable
|
||||
selected={this.state.selected}
|
||||
>
|
||||
<MenuItem onClick={this.handleItem} value='refresh' caption='Refresh' />
|
||||
|
|
|
@ -3,6 +3,10 @@ import Button from '../../components/button';
|
|||
import Snackbar from '../../components/snackbar';
|
||||
|
||||
class SnackbarTest extends React.Component {
|
||||
state = {
|
||||
active: false
|
||||
};
|
||||
|
||||
handleSnackbarClick = () => {
|
||||
this.setState({active: false});
|
||||
};
|
||||
|
@ -15,10 +19,6 @@ class SnackbarTest extends React.Component {
|
|||
this.setState({active: true});
|
||||
};
|
||||
|
||||
state = {
|
||||
active: false
|
||||
};
|
||||
|
||||
render () {
|
||||
return (
|
||||
<section>
|
||||
|
|
|
@ -40,7 +40,7 @@ class TableTest extends React.Component {
|
|||
model={UserModel}
|
||||
onChange={this.handleChange}
|
||||
onSelect={this.handleSelect}
|
||||
selectable={true}
|
||||
selectable
|
||||
selected={this.state.selected}
|
||||
source={this.state.source}
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue