/
Ripple.jsx
123 lines (107 loc) · 3.77 KB
/
Ripple.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import React from 'react';
import ReactDOM from 'react-dom';
import ClassNames from 'classnames';
import style from './style';
import prefixer from '../utils/prefixer';
const defaults = {
centered: false,
className: '',
spread: 2
};
const Ripple = (options = {}) => {
const {
centered: defaultCentered,
className: defaultClassName,
spread: defaultSpread,
...props
} = {...defaults, ...options};
return ComposedComponent => {
return class RippledComponent extends React.Component {
static propTypes = {
children: React.PropTypes.any,
disabled: React.PropTypes.bool,
ripple: React.PropTypes.bool,
rippleCentered: React.PropTypes.bool,
rippleClassName: React.PropTypes.string,
rippleSpread: React.PropTypes.number
};
static defaultProps = {
disabled: false,
ripple: true,
rippleCentered: defaultCentered,
rippleClassName: defaultClassName,
rippleSpread: defaultSpread
};
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) => {
if (!this._isTouchRippleReceivingMouseEvent(touch)) {
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});
});
}
};
_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} {...props}>
<span ref='ripple' role='ripple' className={rippleClassName} style={rippleStyle} />
</span>
</ComposedComponent>
);
}
}
};
};
};
export default Ripple;