Skip to content

Commit 3bbc399

Browse files
committed
Merge pull request #90 from mikepb/features/slider-component
Add Slider component
2 parents 6e27f8a + 1e8c2ed commit 3bbc399

File tree

9 files changed

+412
-32
lines changed

9 files changed

+412
-32
lines changed

docs/src/app/app-routes.jsx

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/**
22
* @jsx React.DOM
33
*/
4-
5-
var React = require('react'),
4+
5+
var React = require('react'),
66
Router = require('react-router'),
77
Route = Router.Route,
88
Redirect = Router.Redirect,
@@ -26,36 +26,38 @@ var React = require('react'),
2626
LeftNav = require('./components/pages/components/left-nav.jsx'),
2727
Menus = require('./components/pages/components/menus.jsx'),
2828
Paper = require('./components/pages/components/paper.jsx'),
29+
Sliders = require('./components/pages/components/sliders.jsx'),
2930
Switches = require('./components/pages/components/switches.jsx'),
3031
Toolbars = require('./components/pages/components/toolbars.jsx');
3132

3233
var AppRoutes = (
33-
<Route name="root" path="/" handler={Master}>
34-
<Route name="home" handler={Home} />
35-
<Route name="get-started" handler={GetStarted} />
36-
<Route name="css-framework" handler={CssFramework}>
37-
<Route name="colors" handler={Colors} />
38-
<Route name="typography" handler={Typography} />
39-
<Redirect from="/css-framework" to="colors" />
40-
</Route>
41-
42-
<Route name="components" handler={Components}>
43-
<Route name="buttons" handler={Buttons} />
44-
<Route name="dialog" handler={Dialog} />
45-
<Route name="dropdown-menu" handler={DropDownMenu} />
46-
<Route name="icon-buttons" handler={IconButtons} />
47-
<Route name="icons" handler={Icons} />
48-
<Route name="inputs" handler={Inputs} />
49-
<Route name="left-nav" handler={LeftNav} />
50-
<Route name="menus" handler={Menus} />
51-
<Route name="paper" handler={Paper} />
52-
<Route name="switches" handler={Switches} />
53-
<Route name="toolbars" handler={Toolbars} />
54-
<Redirect from="/components" to="buttons" />
55-
</Route>
56-
57-
<DefaultRoute handler={Home}/>
58-
</Route>
59-
);
60-
61-
module.exports = AppRoutes;
34+
<Route name="root" path="/" handler={Master}>
35+
<Route name="home" handler={Home} />
36+
<Route name="get-started" handler={GetStarted} />
37+
<Route name="css-framework" handler={CssFramework}>
38+
<Route name="colors" handler={Colors} />
39+
<Route name="typography" handler={Typography} />
40+
<Redirect from="/css-framework" to="colors" />
41+
</Route>
42+
43+
<Route name="components" handler={Components}>
44+
<Route name="buttons" handler={Buttons} />
45+
<Route name="dialog" handler={Dialog} />
46+
<Route name="dropdown-menu" handler={DropDownMenu} />
47+
<Route name="icon-buttons" handler={IconButtons} />
48+
<Route name="icons" handler={Icons} />
49+
<Route name="inputs" handler={Inputs} />
50+
<Route name="left-nav" handler={LeftNav} />
51+
<Route name="menus" handler={Menus} />
52+
<Route name="paper" handler={Paper} />
53+
<Route name="sliders" handler={Sliders} />
54+
<Route name="switches" handler={Switches} />
55+
<Route name="toolbars" handler={Toolbars} />
56+
<Redirect from="/components" to="buttons" />
57+
</Route>
58+
59+
<DefaultRoute handler={Home}/>
60+
</Route>
61+
);
62+
63+
module.exports = AppRoutes;

docs/src/app/components/pages/components.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var CssFramework = React.createClass({
1414
{ route: 'menus', text: 'Menus'},
1515
{ route: 'left-nav', text: 'Left Nav'},
1616
{ route: 'paper', text: 'Paper'},
17+
{ route: 'sliders', text: 'Sliders'},
1718
{ route: 'switches', text: 'Switches'},
1819
//{ route: 'toasts', text: 'Toasts'},
1920
{ route: 'toolbars', text: 'Toolbars'},
@@ -26,4 +27,4 @@ var CssFramework = React.createClass({
2627

2728
});
2829

29-
module.exports = CssFramework;
30+
module.exports = CssFramework;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @jsx React.DOM
3+
*/
4+
5+
var React = require('react'),
6+
mui = require('mui'),
7+
Slider = mui.Slider,
8+
CodeExample = require('../../code-example/code-example.jsx');
9+
10+
var SlidersPage = React.createClass({
11+
12+
render: function() {
13+
var code =
14+
'// Default\n' +
15+
'<Slider name="slider1" />\n\n' +
16+
'// With starting value\n' +
17+
'<Slider name="slider2" defaultValue={0.5} />\n' +
18+
'<Slider name="slider3" defaultValue={1} />\n\n' +
19+
'// Disabled with fixed value\n' +
20+
'<Slider name="slider1" disabled={true} />\n' +
21+
'<Slider name="slider2" disabled={true} value={0.5} />\n' +
22+
'<Slider name="slider3" disabled={true} value={1} />';
23+
24+
return (
25+
<div>
26+
<h2 className="mui-font-style-headline">Sliders</h2>
27+
<CodeExample code={code}>
28+
<Slider name="slider1" />
29+
<Slider name="slider2" value={0.5} />
30+
<Slider name="slider3" value={1} />
31+
<Slider name="slider1" disabled={true} />
32+
<Slider name="slider2" disabled={true} value={0.5} />
33+
<Slider name="slider3" disabled={true} value={1} />
34+
</CodeExample>
35+
</div>
36+
);
37+
}
38+
39+
});
40+
41+
module.exports = SlidersPage;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
},
3636
"dependencies": {
3737
"react": "^0.12.1",
38+
"react-draggable2": "^0.4.1",
3839
"react-tap-event-plugin": "^0.1.3"
3940
},
4041
"devDependencies": {

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module.exports = {
2424
RadioButton: require('./js/radio-button.jsx'),
2525
RaisedButton: require('./js/raised-button.jsx'),
2626
Ripple: require('./js/ripple.jsx'),
27+
Slider: require('./js/slider.jsx'),
2728
Toggle: require('./js/toggle.jsx'),
2829
Toast: require('./js/toast.jsx'),
2930
Toolbar: require('./js/toolbar.jsx'),

src/js/slider.jsx

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/**
2+
* @jsx React.DOM
3+
*/
4+
5+
var React = require('react'),
6+
Paper = require('./paper.jsx'),
7+
Classable = require('./mixins/classable.js'),
8+
Draggable = require('react-draggable');
9+
10+
var Slider = React.createClass({
11+
12+
propTypes: {
13+
required: React.PropTypes.bool,
14+
disabled: React.PropTypes.bool,
15+
min: React.PropTypes.number,
16+
max: React.PropTypes.number,
17+
step: React.PropTypes.number,
18+
error: React.PropTypes.string,
19+
description: React.PropTypes.string,
20+
name: React.PropTypes.string.isRequired,
21+
onChange: React.PropTypes.func
22+
},
23+
24+
mixins: [Classable],
25+
26+
getDefaultProps: function() {
27+
return {
28+
required: true,
29+
disabled: false,
30+
defaultValue: 0,
31+
min: 0,
32+
max: 1,
33+
dragging: false
34+
};
35+
},
36+
37+
getInitialState: function() {
38+
var value = this.props.value;
39+
if (value == null) value = this.props.defaultValue;
40+
var percent = value / this.props.max;
41+
if (isNaN(percent)) percent = 0;
42+
return {
43+
value: value,
44+
percent: percent
45+
}
46+
},
47+
48+
componentWillReceiveProps: function(nextProps) {
49+
if (nextProps.value != null) {
50+
this.setValue(nextProps.value);
51+
}
52+
},
53+
54+
render: function() {
55+
var classes = this.getClasses('mui-input', {
56+
'mui-error': this.props.error != null
57+
});
58+
59+
var sliderClasses = this.getClasses('mui-slider', {
60+
'mui-slider-zero': this.state.percent == 0,
61+
'mui-disabled': this.props.disabled
62+
});
63+
64+
var percent = this.state.percent;
65+
if (percent > 1) percent = 1; else if (percent < 0) percent = 0;
66+
67+
return (
68+
<div className={classes}>
69+
<span className="mui-input-highlight"></span>
70+
<span className="mui-input-bar"></span>
71+
<span className="mui-input-description">{this.props.description}</span>
72+
<span className="mui-input-error">{this.props.error}</span>
73+
<div className={sliderClasses} onClick={this._onClick}>
74+
<div ref="track" className="mui-slider-track">
75+
<Draggable axis="x" bound="point"
76+
cancel={this.props.disabled ? '*' : null}
77+
start={{x: (percent * 100) + '%'}}
78+
onStart={this._onDragStart}
79+
onStop={this._onDragStop}
80+
onDrag={this._onDragUpdate}>
81+
<div className="mui-slider-handle" tabIndex={0}></div>
82+
</Draggable>
83+
<div className="mui-slider-selection mui-slider-selection-low"
84+
style={{width: (percent * 100) + '%'}}>
85+
<div className="mui-slider-selection-fill"></div>
86+
</div>
87+
<div className="mui-slider-selection mui-slider-selection-high"
88+
style={{width: ((1 - percent) * 100) + '%'}}>
89+
<div className="mui-slider-selection-fill"></div>
90+
</div>
91+
</div>
92+
</div>
93+
<input ref="input" type="hidden"
94+
name={this.props.name}
95+
value={this.state.value}
96+
required={this.props.required}
97+
min={this.props.min}
98+
max={this.props.max}
99+
step={this.props.step} />
100+
</div>
101+
);
102+
},
103+
104+
getValue: function() {
105+
return this.state.value;
106+
},
107+
108+
setValue: function(i) {
109+
// calculate percentage
110+
var percent = (i - this.props.min) / (this.props.max - this.props.min);
111+
if (isNaN(percent)) percent = 0;
112+
// update state
113+
this.setState({
114+
value: i,
115+
percent: percent
116+
});
117+
},
118+
119+
getPercent: function() {
120+
return this.state.percent;
121+
},
122+
123+
setPercent: function (percent) {
124+
var value = percent * (this.props.max - this.props.min) + this.props.min;
125+
this.setState({value: value, percent: percent});
126+
},
127+
128+
clearValue: function() {
129+
this.setValue(0);
130+
},
131+
132+
_onClick: function (e) {
133+
// let draggable handle the slider
134+
if (this.state.dragging || this.props.disabled) return;
135+
var node = this.refs.track.getDOMNode();
136+
var boundingClientRect = node.getBoundingClientRect();
137+
var offset = e.clientX - boundingClientRect.left;
138+
var percent = offset / node.clientWidth;
139+
this.setPercent(percent);
140+
},
141+
142+
_onDragStart: function(e, ui) {
143+
this.setState({
144+
dragging: true
145+
});
146+
},
147+
148+
_onDragStop: function(e, ui) {
149+
this.setState({
150+
dragging: false
151+
});
152+
},
153+
154+
_onDragUpdate: function(e, ui) {
155+
if (!this.state.dragging) return;
156+
var value = this.state.value;
157+
if (!this.props.disabled) this._dragX(ui.position.left);
158+
if (this.state.value != value && this.props.onChange) {
159+
this.props.onChange(e, this.state.value);
160+
}
161+
},
162+
163+
_dragX: function(pos) {
164+
var max = this.refs.track.getDOMNode().clientWidth;
165+
if (pos < 0) pos = 0; else if (pos > max) pos = max;
166+
this.setPercent(pos / max);
167+
}
168+
169+
});
170+
171+
module.exports = Slider;

src/less/components/components.less

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
@import "radio-button.less";
2020
@import "raised-button.less";
2121
@import "ripple.less";
22+
@import "slider.less";
2223
@import "subheader.less";
2324
@import "table.less";
2425
@import "toast.less";

0 commit comments

Comments
 (0)