Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Slider] removed react-draggable dependency (fixes IE!) #1825

Merged
merged 10 commits into from
Oct 15, 2015
8 changes: 4 additions & 4 deletions docs/src/app/components/pages/components/sliders.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,15 @@ class SlidersPage extends React.Component {
},
{
name: 'onDragStart',
type: 'function(e, ui)',
type: 'function(e)',
header: 'optional',
desc: 'Callback function that is fired when the slider has begun to move. ui contains the position information.'
desc: 'Callback function that is fired when the slider has begun to move.'
},
{
name: 'onDragStop',
type: 'function(e, ui)',
type: 'function(e)',
header: 'optional',
desc: 'Callback function that is fried when teh slide has stopped moving. ui contains the position information.'
desc: 'Callback function that is fried when teh slide has stopped moving.'
},
{
name: 'onFocus',
Expand Down
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
"url": "https://github.com/callemall/material-ui/issues"
},
"homepage": "http://material-ui.com/",
"dependencies": {
"react-draggable2": "^0.7.0-alpha1"
},
"peerDependencies": {
"react": "^0.14.0",
"react-dom": "^0.14.0",
Expand Down
140 changes: 94 additions & 46 deletions src/slider.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const React = require('react');
const ReactDOM = require('react-dom');
const StylePropable = require('./mixins/style-propable');
const Draggable = require('react-draggable2');
const Transitions = require('./styles/transitions');
const FocusRipple = require('./ripples/focus-ripple');
const DefaultRawTheme = require('./styles/raw-themes/light-raw-theme');
Expand Down Expand Up @@ -155,7 +154,7 @@ const Slider = React.createClass({
position: 'absolute',
cursor: 'pointer',
pointerEvents: 'inherit',
top: ((this.getTheme().handleSizeActive - this.getTheme().trackSize) / 2) + 'px',
top: 0,
left: '0%',
zIndex: 1,
margin: (this.getTheme().trackSize / 2) + 'px 0 0 0',
Expand Down Expand Up @@ -252,7 +251,10 @@ const Slider = React.createClass({
styles.handle,
this.state.active && styles.handleWhenActive,
this.state.focused && {outline: 'none'},
this.props.disabled && styles.handleWhenDisabled
this.props.disabled && styles.handleWhenDisabled,
{
left: (percent * 100) + '%',
}
);
let rippleStyle = this.mergeAndPrefix(
styles.ripple,
Expand All @@ -277,6 +279,16 @@ const Slider = React.createClass({
color={rippleColor}/>
);
}

let handleDragProps = {};

if (!this.props.disabled) {
handleDragProps = {
onTouchStart: this._onHandleTouchStart,
onMouseDown: this._onHandleMouseDown,
}
}

return (
<div {...others } style={this.prepareStyles(this.props.style)}>
<span className="mui-input-highlight"></span>
Expand All @@ -293,18 +305,9 @@ const Slider = React.createClass({
<div ref="track" style={this.prepareStyles(styles.track)}>
<div style={this.prepareStyles(styles.filled)}></div>
<div style={this.prepareStyles(remainingStyles)}></div>
<Draggable axis="x" bound="point"
cancel={this.props.disabled ? '*' : null}
start={{x: (percent * 100) + '%'}}
constrain={this._constrain()}
onStart={this._onDragStart}
onStop={this._onDragStop}
onDrag={this._onDragUpdate}
onMouseDown={this._onMouseDownKnob}>
<div style={handleStyles} tabIndex={0}>
{focusRipple}
</div>
</Draggable>
<div style={handleStyles} tabIndex={0} {...handleDragProps}>
{focusRipple}
</div>
</div>
</div>
<input ref="input" type="hidden"
Expand All @@ -318,6 +321,62 @@ const Slider = React.createClass({
);
},

_onHandleTouchStart(e) {
if (document) {
document.addEventListener('touchmove', this._dragTouchHandler, false);
document.addEventListener('touchup', this._dragTouchEndHandler, false);
document.addEventListener('touchend', this._dragTouchEndHandler, false);
document.addEventListener('touchcancel', this._dragTouchEndHandler, false);
}
this._onDragStart(e);
},

_onHandleMouseDown(e) {
if (document) {
document.addEventListener('mousemove', this._dragHandler, false);
document.addEventListener('mouseup', this._dragEndHandler, false);
}
this._onDragStart(e);
},

_dragHandler(e) {
if (this._dragRunning) { return; }
this._dragRunning = true;
requestAnimationFrame(() => {
this._onDragUpdate(e, e.clientX - this._getTrackLeft());
this._dragRunning = false;
});
},

_dragTouchHandler(e) {
if (this._dragRunning) { return; }
this._dragRunning = true;
requestAnimationFrame(() => {
this._onDragUpdate(e, e.touches[0].clientX - this._getTrackLeft());
this._dragRunning = false;
});
},

_dragEndHandler(e) {
if (document) {
document.removeEventListener('mousemove', this._dragHandler, false);
document.removeEventListener('mouseup', this._dragEndHandler, false);
}

this._onDragStop(e);
},

_dragTouchEndHandler(e) {
if (document) {
document.removeEventListener('touchmove', this._dragTouchHandler, false);
document.removeEventListener('touchup', this._dragTouchEndHandler, false);
document.removeEventListener('touchend', this._dragTouchEndHandler, false);
document.removeEventListener('touchcancel', this._dragTouchEndHandler, false);
}

this._onDragStop(e);
},

getValue() {
return this.state.value;
},
Expand All @@ -337,9 +396,13 @@ const Slider = React.createClass({
return this.state.percent;
},

setPercent(percent) {
setPercent(percent, callback) {
let value = this._alignValue(this._percentToValue(percent));
this.setState({value: value, percent: percent});
let { min, max } = this.props;
let alignedPercent = (value - min) / (max - min);
if (this.state.value !== value) {
this.setState({value: value, percent: alignedPercent}, callback);
}
},

clearValue() {
Expand All @@ -352,20 +415,6 @@ const Slider = React.createClass({
return parseFloat(alignValue.toFixed(5));
},

_constrain() {
let { min, max, step } = this.props;
let steps = (max - min) / step;
return (pos) => {
let pixelMax = ReactDOM.findDOMNode(this.refs.track).clientWidth;
let pixelStep = pixelMax / steps;
let cursor = Math.round(pos.left / pixelStep) * pixelStep;

return {
left: cursor,
};
};
},

_onFocus(e) {
this.setState({focused: true});
if (this.props.onFocus) this.props.onFocus(e);
Expand All @@ -388,39 +437,39 @@ const Slider = React.createClass({
this.setState({hovered: false});
},

_getTrackLeft() {
return ReactDOM.findDOMNode(this.refs.track).getBoundingClientRect().left;
},

_onMouseUp(e) {
if (!this.props.disabled) this.setState({active: false});
if (!this.state.dragging && Math.abs(this._pos - e.clientX) < 5) {
let pos = e.clientX - ReactDOM.findDOMNode(this).getBoundingClientRect().left;
let pos = e.clientX - this._getTrackLeft();
this._dragX(e, pos);
}

this._pos = undefined;
},

_onMouseDownKnob() {
if (!this.props.disabled) this.setState({active: true});
},

_onDragStart(e, ui) {
_onDragStart(e) {
this.setState({
dragging: true,
active: true,
});
if (this.props.onDragStart) this.props.onDragStart(e, ui);
if (this.props.onDragStart) this.props.onDragStart(e);
},

_onDragStop(e, ui) {
_onDragStop(e) {
this.setState({
dragging: false,
active: false,
});
if (this.props.onDragStop) this.props.onDragStop(e, ui);
if (this.props.onDragStop) this.props.onDragStop(e);
},

_onDragUpdate(e, ui) {
_onDragUpdate(e, pos) {
if (!this.state.dragging) return;
if (!this.props.disabled) this._dragX(e, ui.position.left);
if (!this.props.disabled) this._dragX(e, pos);
},

_dragX(e, pos) {
Expand All @@ -430,10 +479,9 @@ const Slider = React.createClass({
},

_updateWithChangeEvent(e, percent) {
if (this.state.percent === percent) return;
this.setPercent(percent);
let value = this._alignValue(this._percentToValue(percent));
if (this.props.onChange) this.props.onChange(e, value);
this.setPercent(percent, () => {
if (this.props.onChange) this.props.onChange(e, this.state.value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will call onChange many times with same value during dragging. I think it will be better to call onChange only when value changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @KapJI for review and for this finding. You are right and I just fixed it, but from setPercent, it seemed more convenient there for me.

});
},

_percentToValue(percent) {
Expand Down