Skip to content

Commit

Permalink
Merge pull request #90 from mikepb/features/slider-component
Browse files Browse the repository at this point in the history
Add Slider component
  • Loading branch information
Hai Nguyen committed Dec 9, 2014
2 parents 6e27f8a + 1e8c2ed commit 3bbc399
Show file tree
Hide file tree
Showing 9 changed files with 412 additions and 32 deletions.
64 changes: 33 additions & 31 deletions docs/src/app/app-routes.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* @jsx React.DOM
*/
var React = require('react'),

var React = require('react'),
Router = require('react-router'),
Route = Router.Route,
Redirect = Router.Redirect,
Expand All @@ -26,36 +26,38 @@ var React = require('react'),
LeftNav = require('./components/pages/components/left-nav.jsx'),
Menus = require('./components/pages/components/menus.jsx'),
Paper = require('./components/pages/components/paper.jsx'),
Sliders = require('./components/pages/components/sliders.jsx'),
Switches = require('./components/pages/components/switches.jsx'),
Toolbars = require('./components/pages/components/toolbars.jsx');

var AppRoutes = (
<Route name="root" path="/" handler={Master}>
<Route name="home" handler={Home} />
<Route name="get-started" handler={GetStarted} />
<Route name="css-framework" handler={CssFramework}>
<Route name="colors" handler={Colors} />
<Route name="typography" handler={Typography} />
<Redirect from="/css-framework" to="colors" />
</Route>

<Route name="components" handler={Components}>
<Route name="buttons" handler={Buttons} />
<Route name="dialog" handler={Dialog} />
<Route name="dropdown-menu" handler={DropDownMenu} />
<Route name="icon-buttons" handler={IconButtons} />
<Route name="icons" handler={Icons} />
<Route name="inputs" handler={Inputs} />
<Route name="left-nav" handler={LeftNav} />
<Route name="menus" handler={Menus} />
<Route name="paper" handler={Paper} />
<Route name="switches" handler={Switches} />
<Route name="toolbars" handler={Toolbars} />
<Redirect from="/components" to="buttons" />
</Route>

<DefaultRoute handler={Home}/>
</Route>
);

module.exports = AppRoutes;
<Route name="root" path="/" handler={Master}>
<Route name="home" handler={Home} />
<Route name="get-started" handler={GetStarted} />
<Route name="css-framework" handler={CssFramework}>
<Route name="colors" handler={Colors} />
<Route name="typography" handler={Typography} />
<Redirect from="/css-framework" to="colors" />
</Route>

<Route name="components" handler={Components}>
<Route name="buttons" handler={Buttons} />
<Route name="dialog" handler={Dialog} />
<Route name="dropdown-menu" handler={DropDownMenu} />
<Route name="icon-buttons" handler={IconButtons} />
<Route name="icons" handler={Icons} />
<Route name="inputs" handler={Inputs} />
<Route name="left-nav" handler={LeftNav} />
<Route name="menus" handler={Menus} />
<Route name="paper" handler={Paper} />
<Route name="sliders" handler={Sliders} />
<Route name="switches" handler={Switches} />
<Route name="toolbars" handler={Toolbars} />
<Redirect from="/components" to="buttons" />
</Route>

<DefaultRoute handler={Home}/>
</Route>
);

module.exports = AppRoutes;
3 changes: 2 additions & 1 deletion docs/src/app/components/pages/components.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var CssFramework = React.createClass({
{ route: 'menus', text: 'Menus'},
{ route: 'left-nav', text: 'Left Nav'},
{ route: 'paper', text: 'Paper'},
{ route: 'sliders', text: 'Sliders'},
{ route: 'switches', text: 'Switches'},
//{ route: 'toasts', text: 'Toasts'},
{ route: 'toolbars', text: 'Toolbars'},
Expand All @@ -26,4 +27,4 @@ var CssFramework = React.createClass({

});

module.exports = CssFramework;
module.exports = CssFramework;
41 changes: 41 additions & 0 deletions docs/src/app/components/pages/components/sliders.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* @jsx React.DOM
*/

var React = require('react'),
mui = require('mui'),
Slider = mui.Slider,
CodeExample = require('../../code-example/code-example.jsx');

var SlidersPage = React.createClass({

render: function() {
var code =
'// Default\n' +
'<Slider name="slider1" />\n\n' +
'// With starting value\n' +
'<Slider name="slider2" defaultValue={0.5} />\n' +
'<Slider name="slider3" defaultValue={1} />\n\n' +
'// Disabled with fixed value\n' +
'<Slider name="slider1" disabled={true} />\n' +
'<Slider name="slider2" disabled={true} value={0.5} />\n' +
'<Slider name="slider3" disabled={true} value={1} />';

return (
<div>
<h2 className="mui-font-style-headline">Sliders</h2>
<CodeExample code={code}>
<Slider name="slider1" />
<Slider name="slider2" value={0.5} />
<Slider name="slider3" value={1} />
<Slider name="slider1" disabled={true} />
<Slider name="slider2" disabled={true} value={0.5} />
<Slider name="slider3" disabled={true} value={1} />
</CodeExample>
</div>
);
}

});

module.exports = SlidersPage;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
},
"dependencies": {
"react": "^0.12.1",
"react-draggable2": "^0.4.1",
"react-tap-event-plugin": "^0.1.3"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module.exports = {
RadioButton: require('./js/radio-button.jsx'),
RaisedButton: require('./js/raised-button.jsx'),
Ripple: require('./js/ripple.jsx'),
Slider: require('./js/slider.jsx'),
Toggle: require('./js/toggle.jsx'),
Toast: require('./js/toast.jsx'),
Toolbar: require('./js/toolbar.jsx'),
Expand Down
171 changes: 171 additions & 0 deletions src/js/slider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/**
* @jsx React.DOM
*/

var React = require('react'),
Paper = require('./paper.jsx'),
Classable = require('./mixins/classable.js'),
Draggable = require('react-draggable');

var Slider = React.createClass({

propTypes: {
required: React.PropTypes.bool,
disabled: React.PropTypes.bool,
min: React.PropTypes.number,
max: React.PropTypes.number,
step: React.PropTypes.number,
error: React.PropTypes.string,
description: React.PropTypes.string,
name: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func
},

mixins: [Classable],

getDefaultProps: function() {
return {
required: true,
disabled: false,
defaultValue: 0,
min: 0,
max: 1,
dragging: false
};
},

getInitialState: function() {
var value = this.props.value;
if (value == null) value = this.props.defaultValue;
var percent = value / this.props.max;
if (isNaN(percent)) percent = 0;
return {
value: value,
percent: percent
}
},

componentWillReceiveProps: function(nextProps) {
if (nextProps.value != null) {
this.setValue(nextProps.value);
}
},

render: function() {
var classes = this.getClasses('mui-input', {
'mui-error': this.props.error != null
});

var sliderClasses = this.getClasses('mui-slider', {
'mui-slider-zero': this.state.percent == 0,
'mui-disabled': this.props.disabled
});

var percent = this.state.percent;
if (percent > 1) percent = 1; else if (percent < 0) percent = 0;

return (
<div className={classes}>
<span className="mui-input-highlight"></span>
<span className="mui-input-bar"></span>
<span className="mui-input-description">{this.props.description}</span>
<span className="mui-input-error">{this.props.error}</span>
<div className={sliderClasses} onClick={this._onClick}>
<div ref="track" className="mui-slider-track">
<Draggable axis="x" bound="point"
cancel={this.props.disabled ? '*' : null}
start={{x: (percent * 100) + '%'}}
onStart={this._onDragStart}
onStop={this._onDragStop}
onDrag={this._onDragUpdate}>
<div className="mui-slider-handle" tabIndex={0}></div>
</Draggable>
<div className="mui-slider-selection mui-slider-selection-low"
style={{width: (percent * 100) + '%'}}>
<div className="mui-slider-selection-fill"></div>
</div>
<div className="mui-slider-selection mui-slider-selection-high"
style={{width: ((1 - percent) * 100) + '%'}}>
<div className="mui-slider-selection-fill"></div>
</div>
</div>
</div>
<input ref="input" type="hidden"
name={this.props.name}
value={this.state.value}
required={this.props.required}
min={this.props.min}
max={this.props.max}
step={this.props.step} />
</div>
);
},

getValue: function() {
return this.state.value;
},

setValue: function(i) {
// calculate percentage
var percent = (i - this.props.min) / (this.props.max - this.props.min);
if (isNaN(percent)) percent = 0;
// update state
this.setState({
value: i,
percent: percent
});
},

getPercent: function() {
return this.state.percent;
},

setPercent: function (percent) {
var value = percent * (this.props.max - this.props.min) + this.props.min;
this.setState({value: value, percent: percent});
},

clearValue: function() {
this.setValue(0);
},

_onClick: function (e) {
// let draggable handle the slider
if (this.state.dragging || this.props.disabled) return;
var node = this.refs.track.getDOMNode();
var boundingClientRect = node.getBoundingClientRect();
var offset = e.clientX - boundingClientRect.left;
var percent = offset / node.clientWidth;
this.setPercent(percent);
},

_onDragStart: function(e, ui) {
this.setState({
dragging: true
});
},

_onDragStop: function(e, ui) {
this.setState({
dragging: false
});
},

_onDragUpdate: function(e, ui) {
if (!this.state.dragging) return;
var value = this.state.value;
if (!this.props.disabled) this._dragX(ui.position.left);
if (this.state.value != value && this.props.onChange) {
this.props.onChange(e, this.state.value);
}
},

_dragX: function(pos) {
var max = this.refs.track.getDOMNode().clientWidth;
if (pos < 0) pos = 0; else if (pos > max) pos = max;
this.setPercent(pos / max);
}

});

module.exports = Slider;
1 change: 1 addition & 0 deletions src/less/components/components.less
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@import "radio-button.less";
@import "raised-button.less";
@import "ripple.less";
@import "slider.less";
@import "subheader.less";
@import "table.less";
@import "toast.less";
Expand Down
Loading

0 comments on commit 3bbc399

Please sign in to comment.