commit
fe5f0f8071
|
@ -251,24 +251,3 @@
|
||||||
transition-timing-function: $animation-curve-default;
|
transition-timing-function: $animation-curve-default;
|
||||||
transition-duration: $duration;
|
transition-duration: $duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frames are this way to prevent a flicker in Safari
|
|
||||||
// See https://goo.gl/5luFDk
|
|
||||||
@mixin ripple-loading($name, $width, $height, $opacity: 0.3) {
|
|
||||||
@keyframes #{$name} {
|
|
||||||
0% {
|
|
||||||
opacity: $opacity;
|
|
||||||
transform: translate3d(-50%, -50%, 0) scale(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
95% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate3d(-50%, -50%, 0) scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate3d(-50%, -50%, 0) scale(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ class Button extends React.Component {
|
||||||
mini: React.PropTypes.bool,
|
mini: React.PropTypes.bool,
|
||||||
primary: React.PropTypes.bool,
|
primary: React.PropTypes.bool,
|
||||||
raised: React.PropTypes.bool,
|
raised: React.PropTypes.bool,
|
||||||
ripple: React.PropTypes.bool,
|
|
||||||
type: React.PropTypes.string
|
type: React.PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,13 +29,7 @@ class Button extends React.Component {
|
||||||
floating: false,
|
floating: false,
|
||||||
mini: false,
|
mini: false,
|
||||||
primary: false,
|
primary: false,
|
||||||
raised: false,
|
raised: false
|
||||||
ripple: true
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseDown = (event) => {
|
|
||||||
if (this.refs.ripple) this.refs.ripple.start(event);
|
|
||||||
if (this.props.onMouseDown) this.props.onMouseDown(event);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseUp = () => {
|
handleMouseUp = () => {
|
||||||
|
@ -45,7 +38,7 @@ class Button extends React.Component {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { accent, children, className, flat, floating, href, icon,
|
const { accent, children, className, flat, floating, href, icon,
|
||||||
inverse, label, mini, primary, raised, ripple, ...others} = this.props;
|
inverse, label, mini, primary, raised, ...others} = this.props;
|
||||||
const element = href ? 'a' : 'button';
|
const element = href ? 'a' : 'button';
|
||||||
const level = primary ? 'primary' : accent ? 'accent' : 'neutral';
|
const level = primary ? 'primary' : accent ? 'accent' : 'neutral';
|
||||||
const shape = flat ? 'flat' : raised ? 'raised' : floating ? 'floating' : 'flat';
|
const shape = flat ? 'flat' : raised ? 'raised' : floating ? 'floating' : 'flat';
|
||||||
|
@ -61,13 +54,11 @@ class Button extends React.Component {
|
||||||
ref: 'button',
|
ref: 'button',
|
||||||
className: classes,
|
className: classes,
|
||||||
disabled: this.props.disabled,
|
disabled: this.props.disabled,
|
||||||
onMouseDown: this.handleMouseDown,
|
|
||||||
onMouseUp: this.handleMouseUp,
|
onMouseUp: this.handleMouseUp,
|
||||||
'data-react-toolbox': 'button'
|
'data-react-toolbox': 'button'
|
||||||
};
|
};
|
||||||
|
|
||||||
return React.createElement(element, props,
|
return React.createElement(element, props,
|
||||||
ripple ? <Ripple ref='ripple' /> : null,
|
|
||||||
icon ? <FontIcon className={style.icon} value={icon}/> : null,
|
icon ? <FontIcon className={style.icon} value={icon}/> : null,
|
||||||
label,
|
label,
|
||||||
children
|
children
|
||||||
|
@ -75,4 +66,4 @@ class Button extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Button;
|
export default Ripple({centered: false})(Button);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import FontIcon from '../font_icon';
|
||||||
import Ripple from '../ripple';
|
import Ripple from '../ripple';
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
class Button extends React.Component {
|
class IconButton extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
accent: React.PropTypes.bool,
|
accent: React.PropTypes.bool,
|
||||||
children: React.PropTypes.node,
|
children: React.PropTypes.node,
|
||||||
|
@ -14,20 +14,13 @@ class Button extends React.Component {
|
||||||
icon: React.PropTypes.string,
|
icon: React.PropTypes.string,
|
||||||
inverse: React.PropTypes.bool,
|
inverse: React.PropTypes.bool,
|
||||||
primary: React.PropTypes.bool,
|
primary: React.PropTypes.bool,
|
||||||
ripple: React.PropTypes.bool,
|
|
||||||
type: React.PropTypes.string
|
type: React.PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
accent: false,
|
accent: false,
|
||||||
className: '',
|
className: '',
|
||||||
primary: false,
|
primary: false
|
||||||
ripple: true
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseDown = (event) => {
|
|
||||||
if (this.refs.ripple) this.refs.ripple.start(event);
|
|
||||||
if (this.props.onMouseDown) this.props.onMouseDown(event);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseUp = () => {
|
handleMouseUp = () => {
|
||||||
|
@ -35,7 +28,7 @@ class Button extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const {accent, children, className, href, icon, inverse, primary, ripple, ...others} = this.props;
|
const {accent, children, className, href, icon, inverse, primary, ...others} = this.props;
|
||||||
const element = href ? 'a' : 'button';
|
const element = href ? 'a' : 'button';
|
||||||
const level = primary ? 'primary' : accent ? 'accent' : 'neutral';
|
const level = primary ? 'primary' : accent ? 'accent' : 'neutral';
|
||||||
const classes = ClassNames([style.toggle, style[level]], {[style.inverse]: inverse}, className);
|
const classes = ClassNames([style.toggle, style[level]], {[style.inverse]: inverse}, className);
|
||||||
|
@ -46,16 +39,15 @@ class Button extends React.Component {
|
||||||
ref: 'button',
|
ref: 'button',
|
||||||
className: classes,
|
className: classes,
|
||||||
disabled: this.props.disabled,
|
disabled: this.props.disabled,
|
||||||
onMouseDown: this.handleMouseDown,
|
|
||||||
onMouseUp: this.handleMouseUp,
|
onMouseUp: this.handleMouseUp,
|
||||||
'data-react-toolbox': 'button'
|
'data-react-toolbox': 'button'
|
||||||
};
|
};
|
||||||
|
|
||||||
return React.createElement(element, props,
|
return React.createElement(element, props,
|
||||||
ripple ? <Ripple ref='ripple' centered /> : null,
|
icon ? <FontIcon className={style.icon} value={icon}/> : null,
|
||||||
icon ? <FontIcon className={style.icon} value={icon}/> : children
|
children
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Button;
|
export default Ripple({centered: true})(IconButton);
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ClassNames from 'classnames';
|
||||||
|
import Ripple from '../ripple';
|
||||||
|
import style from './style';
|
||||||
|
|
||||||
|
const Check = ({checked, children, onMouseDown}) => {
|
||||||
|
const className = ClassNames(style.check, {
|
||||||
|
[style.checked]: checked
|
||||||
|
});
|
||||||
|
|
||||||
|
return <div data-role='checkbox' onMouseDown={onMouseDown} className={className}>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Ripple({
|
||||||
|
className: style.ripple,
|
||||||
|
spread: 2.6,
|
||||||
|
centered: true
|
||||||
|
})(Check);
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ClassNames from 'classnames';
|
import ClassNames from 'classnames';
|
||||||
import Ripple from '../ripple';
|
import Check from './Check';
|
||||||
import events from '../utils/events';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
class Checkbox extends React.Component {
|
class Checkbox extends React.Component {
|
||||||
|
@ -22,21 +21,10 @@ class Checkbox extends React.Component {
|
||||||
disabled: false
|
disabled: false
|
||||||
};
|
};
|
||||||
|
|
||||||
handleClick = (event) => {
|
handleToggle = (event) => {
|
||||||
events.pauseEvent(event);
|
if (event.pageX !== 0 && event.pageY !== 0) this.blur();
|
||||||
if (!this.props.disabled && this.props.onChange) {
|
if (!this.props.disabled && this.props.onChange) {
|
||||||
const value = !this.refs.input.checked;
|
this.props.onChange(!this.props.checked, event);
|
||||||
this.props.onChange(value, event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleInputClick = (event) => {
|
|
||||||
events.pauseEvent(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseDown = (event) => {
|
|
||||||
if (!this.props.disabled) {
|
|
||||||
this.refs.ripple.start(event);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,30 +37,22 @@ class Checkbox extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const fieldClassName = ClassNames(style.field, {
|
const { onChange, ...others } = this.props;
|
||||||
|
const className = ClassNames(style.field, {
|
||||||
[style.disabled]: this.props.disabled
|
[style.disabled]: this.props.disabled
|
||||||
}, this.props.className);
|
}, this.props.className);
|
||||||
|
|
||||||
const checkboxClassName = ClassNames(style.check, {
|
|
||||||
[style.checked]: this.props.checked
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label
|
<label data-react-toolbox='checkbox' className={className}>
|
||||||
data-react-toolbox='checkbox'
|
|
||||||
className={fieldClassName}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
ref='input'
|
{...others}
|
||||||
{...this.props}
|
|
||||||
className={style.input}
|
className={style.input}
|
||||||
onClick={this.handleInputClick}
|
onClick={this.handleToggle}
|
||||||
|
readOnly
|
||||||
|
ref='input'
|
||||||
type='checkbox'
|
type='checkbox'
|
||||||
/>
|
/>
|
||||||
<span data-role='checkbox' className={checkboxClassName} onMouseDown={this.handleMouseDown}>
|
<Check checked={this.props.checked} disabled={this.props.disabled}/>
|
||||||
<Ripple ref='ripple' data-role='ripple' className={style.ripple} spread={3} centered />
|
|
||||||
</span>
|
|
||||||
{this.props.label ? <span data-role='label' className={style.text}>{this.props.label}</span> : null}
|
{this.props.label ? <span data-role='label' className={style.text}>{this.props.label}</span> : null}
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,7 +21,6 @@ $calendar-primary-contrast-color: $calendar-primary-contrast !default;
|
||||||
$calendar-primary-hover-color: rgba($calendar-primary, 0.21) !default;
|
$calendar-primary-hover-color: rgba($calendar-primary, 0.21) !default;
|
||||||
$calendar-arrows-color: $palette-grey-600 !default;
|
$calendar-arrows-color: $palette-grey-600 !default;
|
||||||
$calendar-arrows-font-size: 2 * $unit;
|
$calendar-arrows-font-size: 2 * $unit;
|
||||||
$calendar-arrows-ripple-duration: 450ms;
|
|
||||||
$calendar-year-font-size: 2.4;
|
$calendar-year-font-size: 2.4;
|
||||||
$calendar-day-font-size: 1.3 * $unit;
|
$calendar-day-font-size: 1.3 * $unit;
|
||||||
$calendar-day-disable-opacity: 0.25;
|
$calendar-day-disable-opacity: 0.25;
|
||||||
|
|
|
@ -91,8 +91,3 @@
|
||||||
.month {
|
.month {
|
||||||
background-color: $calendar-primary-contrast-color;
|
background-color: $calendar-primary-contrast-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ripple {
|
|
||||||
opacity: .5;
|
|
||||||
transition-duration: $calendar-arrows-ripple-duration;
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ class ListItem extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
avatar: React.PropTypes.string,
|
avatar: React.PropTypes.string,
|
||||||
caption: React.PropTypes.string.isRequired,
|
caption: React.PropTypes.string.isRequired,
|
||||||
|
children: React.PropTypes.any,
|
||||||
className: React.PropTypes.string,
|
className: React.PropTypes.string,
|
||||||
disabled: React.PropTypes.bool,
|
disabled: React.PropTypes.bool,
|
||||||
leftIcon: React.PropTypes.string,
|
leftIcon: React.PropTypes.string,
|
||||||
|
@ -32,12 +33,6 @@ class ListItem extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseDown = (event) => {
|
|
||||||
if (this.refs.ripple && !this.props.disabled) {
|
|
||||||
this.refs.ripple.start(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderContent () {
|
renderContent () {
|
||||||
const className = ClassNames(style.item, {
|
const className = ClassNames(style.item, {
|
||||||
[style.withLegend]: this.props.legend,
|
[style.withLegend]: this.props.legend,
|
||||||
|
@ -50,7 +45,6 @@ class ListItem extends React.Component {
|
||||||
{this.props.leftIcon ? <FontIcon className={`${style.icon} ${style.left}`} value={this.props.leftIcon} /> : null}
|
{this.props.leftIcon ? <FontIcon className={`${style.icon} ${style.left}`} value={this.props.leftIcon} /> : null}
|
||||||
{this.props.avatar ? <img className={style.avatar} src={this.props.avatar} /> : null}
|
{this.props.avatar ? <img className={style.avatar} src={this.props.avatar} /> : null}
|
||||||
<ListItemContent caption={this.props.caption} legend={this.props.legend} />
|
<ListItemContent caption={this.props.caption} legend={this.props.legend} />
|
||||||
{this.props.ripple ? <Ripple ref='ripple' className={style.ripple} spread={2} /> : null}
|
|
||||||
{this.props.rightIcon ? <FontIcon className={`${style.icon} ${style.right}`} value={this.props.rightIcon} /> : null}
|
{this.props.rightIcon ? <FontIcon className={`${style.icon} ${style.right}`} value={this.props.rightIcon} /> : null}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
@ -58,11 +52,15 @@ class ListItem extends React.Component {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<li className={style['list-item']} onClick={this.handleClick} onMouseDown={this.handleMouseDown}>
|
<li className={style.listItem} onClick={this.handleClick} onMouseDown={this.props.onMouseDown}>
|
||||||
{this.props.to ? <a href={this.props.to}>{this.renderContent()}</a> : this.renderContent()}
|
{this.props.to ? <a href={this.props.to}>{this.renderContent()}</a> : this.renderContent()}
|
||||||
|
{this.props.children}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ListItem;
|
export default Ripple({
|
||||||
|
className: style.ripple,
|
||||||
|
centered: false
|
||||||
|
})(ListItem);
|
||||||
|
|
|
@ -32,11 +32,16 @@
|
||||||
.list + & {
|
.list + & {
|
||||||
margin-top: - $list-vertical-padding;
|
margin-top: - $list-vertical-padding;
|
||||||
}
|
}
|
||||||
.list-item ~ & {
|
.listItem ~ & {
|
||||||
margin: $list-vertical-padding 0;
|
margin: $list-vertical-padding 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.listItem {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -79,7 +84,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.ripple {
|
.ripple {
|
||||||
opacity: .1;
|
color: $color-text-secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FontIcon from '../font_icon';
|
import FontIcon from '../font_icon';
|
||||||
|
import ClassNames from 'classnames';
|
||||||
import Ripple from '../ripple';
|
import Ripple from '../ripple';
|
||||||
import style from './style.menu_item';
|
import style from './style.menu_item';
|
||||||
|
|
||||||
class MenuItem extends React.Component {
|
class MenuItem extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
caption: React.PropTypes.string.isRequired,
|
caption: React.PropTypes.string.isRequired,
|
||||||
|
children: React.PropTypes.any,
|
||||||
className: React.PropTypes.string,
|
className: React.PropTypes.string,
|
||||||
disabled: React.PropTypes.bool,
|
disabled: React.PropTypes.bool,
|
||||||
icon: React.PropTypes.string,
|
icon: React.PropTypes.string,
|
||||||
onClick: React.PropTypes.func,
|
onClick: React.PropTypes.func,
|
||||||
ripple: React.PropTypes.bool,
|
|
||||||
selected: React.PropTypes.bool,
|
selected: React.PropTypes.bool,
|
||||||
shortcut: React.PropTypes.string
|
shortcut: React.PropTypes.string
|
||||||
};
|
};
|
||||||
|
@ -18,7 +19,6 @@ class MenuItem extends React.Component {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
className: '',
|
className: '',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
ripple: false,
|
|
||||||
selected: false
|
selected: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,32 +28,24 @@ class MenuItem extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseDown = (event) => {
|
|
||||||
if (this.props.ripple && !this.props.disabled) {
|
|
||||||
this.refs.ripple.start(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let className = style.root;
|
const {icon, caption, children, shortcut, selected, disabled, ...others} = this.props;
|
||||||
if (this.props.selected) className += ` ${style.selected}`;
|
const className = ClassNames(style.root, {
|
||||||
if (this.props.disabled) className += ` ${style.disabled}`;
|
[style.selected]: selected,
|
||||||
if (this.props.className) className += ` ${this.props.className}`;
|
[style.disabled]: disabled
|
||||||
|
}, this.props.className);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li {...others} data-react-toolbox='menu-item' className={className} onClick={this.handleClick}>
|
||||||
data-react-toolbox='menu-item'
|
{icon ? <FontIcon value={icon} className={style.icon}/> : null}
|
||||||
className={className}
|
<span className={style.caption}>{caption}</span>
|
||||||
onClick={this.handleClick}
|
{shortcut ? <small className={style.shortcut}>{shortcut}</small> : null}
|
||||||
onMouseDown={this.handleMouseDown}
|
{children}
|
||||||
>
|
|
||||||
{this.props.icon ? <FontIcon value={this.props.icon} className={style.icon}/> : null}
|
|
||||||
<span className={style.caption}>{this.props.caption}</span>
|
|
||||||
{this.props.shortcut ? <small className={style.shortcut}>{this.props.shortcut}</small> : null}
|
|
||||||
{this.props.ripple ? <Ripple ref='ripple' className={style.ripple} spread={2.5} /> : null}
|
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MenuItem;
|
export default Ripple({
|
||||||
|
className: style.ripple
|
||||||
|
})(MenuItem);
|
||||||
|
|
|
@ -38,5 +38,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.ripple {
|
.ripple {
|
||||||
opacity: .1;
|
color: $color-text-secondary;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Ripple from '../ripple';
|
||||||
|
import style from './style';
|
||||||
|
|
||||||
|
const Radio = ({checked, children, onMouseDown}) => {
|
||||||
|
const className = style[checked ? 'radio-checked' : 'radio'];
|
||||||
|
return <div data-role='radio' onMouseDown={onMouseDown} className={className}>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Ripple({
|
||||||
|
className: style.ripple,
|
||||||
|
spread: 2.6,
|
||||||
|
centered: true
|
||||||
|
})(Radio);
|
|
@ -1,8 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ClassNames from 'classnames';
|
import ClassNames from 'classnames';
|
||||||
import Ripple from '../ripple';
|
import Radio from './Radio';
|
||||||
import style from './style';
|
import style from './style';
|
||||||
import events from '../utils/events';
|
|
||||||
|
|
||||||
class RadioButton extends React.Component {
|
class RadioButton extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -23,23 +22,10 @@ class RadioButton extends React.Component {
|
||||||
disabled: false
|
disabled: false
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChange = (event) => {
|
|
||||||
if (!this.props.checked && this.props.onChange) {
|
|
||||||
this.props.onChange(event, this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleClick = (event) => {
|
handleClick = (event) => {
|
||||||
events.pauseEvent(event);
|
const {checked, disabled, onChange} = this.props;
|
||||||
if (!this.props.disabled) this.handleChange(event);
|
if (event.pageX !== 0 && event.pageY !== 0) this.blur();
|
||||||
};
|
if (!disabled && !checked && onChange) onChange(event, this);
|
||||||
|
|
||||||
handleInputClick = (event) => {
|
|
||||||
events.pauseEvent(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseDown = (event) => {
|
|
||||||
if (!this.props.disabled) this.refs.ripple.start(event);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
blur () {
|
blur () {
|
||||||
|
@ -51,22 +37,20 @@ class RadioButton extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const labelClassName = ClassNames(style[this.props.disabled ? 'disabled' : 'field'], this.props.className);
|
const className = ClassNames(style[this.props.disabled ? 'disabled' : 'field'], this.props.className);
|
||||||
const radioClassName = style[this.props.checked ? 'radio-checked' : 'radio'];
|
const { onChange, ...others } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label className={labelClassName} onClick={this.handleClick}>
|
<label className={className}>
|
||||||
<input
|
<input
|
||||||
{...this.props}
|
{...others}
|
||||||
ref='input'
|
|
||||||
className={style.input}
|
className={style.input}
|
||||||
onChange={this.handleChange}
|
onClick={this.handleClick}
|
||||||
onClick={this.handleInputClick}
|
readOnly
|
||||||
|
ref='input'
|
||||||
type='radio'
|
type='radio'
|
||||||
/>
|
/>
|
||||||
<span role='radio' className={radioClassName} onMouseDown={this.handleMouseDown}>
|
<Radio checked={this.props.checked} disabled={this.props.disabled}/>
|
||||||
<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>
|
</label>
|
||||||
);
|
);
|
||||||
|
|
|
@ -28,15 +28,12 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
||||||
appearance: none;
|
appearance: none;
|
||||||
&:focus:not(&:active) {
|
&:focus ~ .radio {
|
||||||
+ .radio {
|
box-shadow: 0 0 0 $unit $radio-focus-color;
|
||||||
box-shadow: 0 0 0 $unit $radio-focus-color;
|
}
|
||||||
}
|
&:focus ~ .radio-checked {
|
||||||
+ .radio-checked {
|
box-shadow: 0 0 0 $unit $radio-checked-focus-color;
|
||||||
box-shadow: 0 0 0 $unit $radio-checked-focus-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,84 +1,122 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import ClassNames from 'classnames';
|
import ClassNames from 'classnames';
|
||||||
import prefixer from '../utils/prefixer';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
import prefixer from '../utils/prefixer';
|
||||||
|
|
||||||
class Ripple extends React.Component {
|
const defaults = {
|
||||||
static propTypes = {
|
centered: false,
|
||||||
centered: React.PropTypes.bool,
|
className: '',
|
||||||
className: React.PropTypes.string,
|
spread: 2
|
||||||
loading: React.PropTypes.bool,
|
};
|
||||||
spread: React.PropTypes.number
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
const Ripple = (options = {}) => {
|
||||||
centered: false,
|
const {
|
||||||
className: '',
|
centered: defaultCentered,
|
||||||
loading: false,
|
className: defaultClassName,
|
||||||
spread: 2
|
spread: defaultSpread
|
||||||
};
|
} = {...defaults, ...options};
|
||||||
|
|
||||||
state = {
|
return ComposedComponent => {
|
||||||
active: false,
|
return class RippledComponent extends React.Component {
|
||||||
left: null,
|
static propTypes = {
|
||||||
restarting: false,
|
children: React.PropTypes.any,
|
||||||
top: null,
|
disabled: React.PropTypes.bool,
|
||||||
width: null
|
ripple: React.PropTypes.bool,
|
||||||
};
|
rippleCentered: React.PropTypes.bool,
|
||||||
|
rippleClassName: React.PropTypes.string,
|
||||||
|
rippleSpread: React.PropTypes.number
|
||||||
|
};
|
||||||
|
|
||||||
handleEnd = () => {
|
static defaultProps = {
|
||||||
document.removeEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
disabled: false,
|
||||||
this.setState({active: false});
|
ripple: true,
|
||||||
};
|
rippleCentered: defaultCentered,
|
||||||
|
rippleClassName: defaultClassName,
|
||||||
|
rippleSpread: defaultSpread
|
||||||
|
};
|
||||||
|
|
||||||
start = ({pageX, pageY}, touch = false) => {
|
state = {
|
||||||
if (!this._isTouchRippleReceivingMouseEvent(touch)) {
|
active: false,
|
||||||
this.touch = touch;
|
left: null,
|
||||||
document.addEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
restarting: false,
|
||||||
const {top, left, width} = this._getDescriptor(pageX, pageY);
|
top: null,
|
||||||
this.setState({active: false, restarting: true, top, left, width}, () => {
|
width: null
|
||||||
this.refs.ripple.offsetWidth; //eslint-disable-line no-unused-expressions
|
};
|
||||||
this.setState({active: true, restarting: false});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_isTouchRippleReceivingMouseEvent (touch) {
|
handleEnd = () => {
|
||||||
return this.touch && !touch;
|
document.removeEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
||||||
}
|
this.setState({active: false});
|
||||||
|
};
|
||||||
|
|
||||||
_getDescriptor (pageX, pageY) {
|
start = ({pageX, pageY}, touch = false) => {
|
||||||
const {left, top, height, width} = ReactDOM.findDOMNode(this).getBoundingClientRect();
|
if (!this._isTouchRippleReceivingMouseEvent(touch)) {
|
||||||
return {
|
this.touch = touch;
|
||||||
left: this.props.centered ? 0 : pageX - left - width / 2 - window.scrollX,
|
document.addEventListener(this.touch ? 'touchend' : 'mouseup', this.handleEnd);
|
||||||
top: this.props.centered ? 0 : pageY - top - height / 2 - window.scrollY,
|
const {top, left, width} = this._getDescriptor(pageX, pageY);
|
||||||
width: width * this.props.spread
|
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});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_isTouchRippleReceivingMouseEvent (touch) {
|
||||||
|
return this.touch && !touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getDescriptor (pageX, pageY) {
|
||||||
|
const {left, top, height, width} = ReactDOM.findDOMNode(this).getBoundingClientRect();
|
||||||
|
const {rippleCentered: centered, rippleSpread: spread} = this.props;
|
||||||
|
return {
|
||||||
|
left: centered ? 0 : pageX - left - width / 2 - window.scrollX,
|
||||||
|
top: centered ? 0 : pageY - top - height / 2 - window.scrollY,
|
||||||
|
width: width * spread
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseDown = (event) => {
|
||||||
|
if (!this.props.disabled) this.start(event);
|
||||||
|
if (this.props.onMouseDown) this.props.onMouseDown(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (!this.props.ripple) {
|
||||||
|
return <ComposedComponent {...this.props} />;
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
children,
|
||||||
|
ripple,
|
||||||
|
rippleClassName: className,
|
||||||
|
rippleCentered: centered,
|
||||||
|
rippleSpread: spread,
|
||||||
|
...other
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const rippleClassName = ClassNames(style.normal, {
|
||||||
|
[style.active]: this.state.active,
|
||||||
|
[style.restarting]: this.state.restarting
|
||||||
|
}, className);
|
||||||
|
|
||||||
|
const { left, top, width } = this.state;
|
||||||
|
const scale = this.state.restarting ? 0 : 1;
|
||||||
|
const rippleStyle = prefixer({
|
||||||
|
transform: `translate3d(${-width / 2 + left}px, ${-width / 2 + top}px, 0) scale(${scale})`
|
||||||
|
}, {width, height: width});
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ComposedComponent {...other} onMouseDown={this.handleMouseDown}>
|
||||||
|
{children ? children : null}
|
||||||
|
<span data-react-toolbox='ripple' className={style.wrapper}>
|
||||||
|
<span ref='ripple' role='ripple' className={rippleClassName} style={rippleStyle} />
|
||||||
|
</span>
|
||||||
|
</ComposedComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
};
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
const className = ClassNames(style[this.props.loading ? 'loading' : 'normal'], {
|
|
||||||
[style.active]: this.state.active,
|
|
||||||
[style.restarting]: this.state.restarting
|
|
||||||
}, 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 Ripple;
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
$ripple-duration: 1.2s;
|
$ripple-duration: 800ms !default;
|
||||||
$ripple-final-opacity: .3;
|
$ripple-final-opacity: .3 !default;
|
||||||
$ripple-size: 15 * $unit;
|
$ripple-size: 15 * $unit !default;
|
||||||
|
|
|
@ -38,15 +38,3 @@
|
||||||
transition-property: opacity, transform;
|
transition-property: opacity, transform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading {
|
|
||||||
@extend %ripple;
|
|
||||||
@include ripple-loading(ripple, $ripple-size, $ripple-size);
|
|
||||||
width: $ripple-size;
|
|
||||||
height: $ripple-size;
|
|
||||||
opacity: $ripple-final-opacity;
|
|
||||||
animation-name: ripple;
|
|
||||||
animation-duration: $ripple-duration;
|
|
||||||
animation-timing-function: $animation-curve-linear-out-slow-in;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Ripple from '../ripple';
|
import Thumb from './Thumb';
|
||||||
import style from './style';
|
import style from './style';
|
||||||
import events from '../utils/events';
|
|
||||||
|
|
||||||
class Switch extends React.Component {
|
class Switch extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -21,22 +20,13 @@ class Switch extends React.Component {
|
||||||
disabled: false
|
disabled: false
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChange = (event) => {
|
handleToggle = (event) => {
|
||||||
events.pauseEvent(event);
|
if (event.pageX !== 0 && event.pageY !== 0) this.blur();
|
||||||
if (this.props.onChange && !this.props.disabled) {
|
if (!this.props.disabled && this.props.onChange) {
|
||||||
const value = !this.refs.input.checked;
|
this.props.onChange(!this.props.checked, event);
|
||||||
this.props.onChange(value, event);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleInputClick = (event) => {
|
|
||||||
events.pauseEvent(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseDown = (event) => {
|
|
||||||
if (!this.props.disabled) this.refs.ripple.start(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
blur () {
|
blur () {
|
||||||
this.refs.input.blur();
|
this.refs.input.blur();
|
||||||
}
|
}
|
||||||
|
@ -46,29 +36,24 @@ class Switch extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let labelClassName = style[this.props.disabled ? 'disabled' : 'field'];
|
let className = style[this.props.disabled ? 'disabled' : 'field'];
|
||||||
const switchClassName = style[this.props.checked ? 'on' : 'off'];
|
const switchClassName = style[this.props.checked ? 'on' : 'off'];
|
||||||
if (this.props.className) labelClassName += ` ${this.props.className}`;
|
const { onChange, ...others } = this.props;
|
||||||
|
if (this.props.className) className += ` ${this.props.className}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label
|
<label data-react-toolbox='checkbox' className={className}>
|
||||||
data-react-toolbox='checkbox'
|
|
||||||
className={labelClassName}
|
|
||||||
onClick={this.handleChange}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
{...this.props}
|
{...others}
|
||||||
ref='input'
|
|
||||||
checked={this.props.checked}
|
checked={this.props.checked}
|
||||||
className={style.input}
|
className={style.input}
|
||||||
onChange={this.handleChange}
|
onClick={this.handleToggle}
|
||||||
onClick={this.handleInputClick}
|
readOnly
|
||||||
|
ref='input'
|
||||||
type='checkbox'
|
type='checkbox'
|
||||||
/>
|
/>
|
||||||
<span role='switch' className={switchClassName}>
|
<span role='switch' className={switchClassName}>
|
||||||
<span role='thumb' className={style.thumb} onMouseDown={this.handleMouseDown}>
|
<Thumb disabled={this.props.disabled} />
|
||||||
<Ripple ref='ripple' role='ripple' className={style.ripple} spread={2.4} centered />
|
|
||||||
</span>
|
|
||||||
</span>
|
</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>
|
</label>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Ripple from '../ripple';
|
||||||
|
import style from './style';
|
||||||
|
|
||||||
|
const Check = ({children, onMouseDown}) => (
|
||||||
|
<span role='thumb' className={style.thumb} onMouseDown={onMouseDown}>{children}</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Ripple({
|
||||||
|
className: style.ripple,
|
||||||
|
spread: 2.6,
|
||||||
|
centered: true
|
||||||
|
})(Check);
|
|
@ -109,7 +109,7 @@
|
||||||
.text {
|
.text {
|
||||||
color: $switch-disabled-text-color;
|
color: $switch-disabled-text-color;
|
||||||
}
|
}
|
||||||
.switch-on, .switch-off {
|
.on, .off {
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
background: $switch-disabled-track-color;
|
background: $switch-disabled-track-color;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue