Compare commits

...
17 Commits
Author SHA1 Message Date
Benjy Cui 0e6fed5c9b Merge pull request #85 from react-component/feat-vertical
feat: vertical slider
2016-04-10 08:53:55 +08:00
叶言 1ce8c3b117 fix: eslint error 2016-04-09 13:32:44 +08:00
叶言 ffdd062074 fix: some diffs
- update to 3.6.0 (refs:https://github.com/react-component/slider/pull/85#discussion-diff-58325891)
- change `.rc-slider-vertical` to `.{prefixClass}-vertical` (refs:https://github.com/react-component/slider/pull/85#discussion-diff-58325944)
- put all the slider & Range in one row (refs:https://github.com/react-component/slider/pull/85#discussion-diff-58326190)
2016-04-09 13:04:52 +08:00
叶言 3b03957a54 feat: vertical slider
- add `vertical` props
- add vertical slider demo: v-marks.html v-range.html v-slider.html

refs:https://github.com/react-component/slider/issues/18
2016-04-01 16:40:36 +08:00
Benjy Cui e1be65a107 docs: update demo 2016-03-23 11:48:36 +08:00
Benjy Cui 68d3efc7da deps: remove object-assign 2016-03-23 10:54:54 +08:00
Benjy Cui 806cb06d76 bump 3.5.1 2016-03-22 17:22:43 +08:00
Benjy Cui 73b9953084 refactor: update Marks style algorithm 2016-03-22 17:21:50 +08:00
Benjy Cui 6347b6d0c6 bump 3.5.0 2016-03-22 16:55:02 +08:00
Benjy Cui 6a5573b6ca feat: support React.Component in marks 2016-03-22 16:53:38 +08:00
Benjy Cui e030ba9f9d refactor: rename Dots to Steps 2016-03-22 16:27:50 +08:00
Benjy Cui daaea139b9 bump 3.4.0 2016-03-17 15:48:33 +08:00
Boris Serdiuk 2641880783 Merge pull request #82 from react-component/feat-mark-style
feat: support set style of specific mark point
2016-03-17 10:30:45 +03:00
Benjy Cui d6e81a692c feat: support set style of specific mark point 2016-03-17 09:45:55 +08:00
Benjy Cui 0512ee6ee0 Merge pull request #71 from kalinichenko/master
put marks in correct order so one can style it
2016-02-02 20:53:13 +08:00
Andrey Kalinichenko 613a2ae213 put marks in correct order so one can style it 2016-02-02 11:35:10 +01:00
yiminghe 2cb0dbce6f fix: work with rc-form 2016-01-30 18:52:12 +08:00
18 changed files with 446 additions and 56 deletions
+5
View File
@@ -1,6 +1,11 @@
# History # History
---- ----
## 3.6.0 / 2016-04-01
[#18](https://github.com/react-component/slider/issues/18) add `vertical` props ([@wnlee](https://github.com/WNLee))
...
## 1.2.5 / 2015-07-13 ## 1.2.5 / 2015-07-13
+8 -2
View File
@@ -90,9 +90,9 @@ ReactDOM.render(<Rcslider />, container);
</tr> </tr>
<tr> <tr>
<td>marks</td> <td>marks</td>
<td>object {number: string}</td> <td>object{number: string} or object{number: object{ style, label }}</td>
<td>{}</td> <td>{}</td>
<td>Mark on the slider. The key determines the position, and the value determines what will show.</td> <td>Mark on the slider. The key determines the position, and the value determines what will show. If you want to set the style of a specific mark point, the value should be an object which contains `style` and `label` properties.</td>
</tr> </tr>
<tr> <tr>
<td>step</td> <td>step</td>
@@ -112,6 +112,12 @@ ReactDOM.render(<Rcslider />, container);
<td>true</td> <td>true</td>
<td>When `range` is `true`, `allowCross` could be set as `true` to allow those two handles cross.</td> <td>When `range` is `true`, `allowCross` could be set as `true` to allow those two handles cross.</td>
</tr> </tr>
<tr>
<td>vertical</td>
<td>boolean</td>
<td>false</td>
<td>If vertical is `true`, the slider will be vertical.</td>
</tr>
<tr> <tr>
<td>defaultValue</td> <td>defaultValue</td>
<td>number or [number, number]</td> <td>number or [number, number]</td>
+40 -1
View File
@@ -94,7 +94,7 @@
&-dot { &-dot {
position: absolute; position: absolute;
top: -2px; bottom: -2px;
margin-left: -4px; margin-left: -4px;
width: 8px; width: 8px;
height: 8px; height: 8px;
@@ -133,6 +133,45 @@
} }
} }
.@{prefixClass}-vertical {
width: 4px;
height: 100%;
.@{prefixClass} {
&-track {
bottom: 0;
width: 4px;
}
&-handle {
position: absolute;
margin-left: -5px;
margin-bottom: -7px;
}
&-mark {
top: 0;
left: 10px;
height: 100%;
}
&-step {
height: 100%;
width: 4px;
}
&-dot {
left: 2px;
margin-bottom: -4px;
&:first-child {
margin-bottom: -4px;
}
&:last-child {
margin-bottom: -4px;
}
}
}
}
.motion-common() { .motion-common() {
animation-duration: .3s; animation-duration: .3s;
animation-fill-mode: both; animation-fill-mode: both;
+7 -2
View File
@@ -7,11 +7,16 @@ const Slider = require('rc-slider');
const style = {width: 400, margin: 50}; const style = {width: 400, margin: 50};
const marks = { const marks = {
'-10': '-10°C', '-10': '-10°C',
0: '0°C', 0: <strong>0°C</strong>,
26: '26°C', 26: '26°C',
37: '37°C', 37: '37°C',
50: '50°C', 50: '50°C',
100: '100°C', 100: {
style: {
color: 'red',
},
label: <strong>100°C</strong>,
},
}; };
function log(value) { function log(value) {
+25 -1
View File
@@ -14,17 +14,41 @@ function log(value) {
const CustomizedRange = React.createClass({ const CustomizedRange = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
lowerBound: 20,
upperBound: 40,
value: [20, 40], value: [20, 40],
}; };
}, },
onLowerBoundChange: function(e) {
this.setState({ lowerBound: +e.target.value });
},
onUpperBoundChange: function(e) {
this.setState({ upperBound: +e.target.value });
},
onSliderChange: function(value) { onSliderChange: function(value) {
log(value); log(value);
this.setState({ this.setState({
value: value, value: value,
}); });
}, },
handleApply: function() {
const { lowerBound, upperBound } = this.state;
this.setState({ value: [lowerBound, upperBound]});
},
render: function() { render: function() {
return <Slider range value={this.state.value} onChange={this.onSliderChange} />; return (
<div>
<label>LowerBound: </label>
<input type="number" value={this.state.lowerBound} onChange={this.onLowerBoundChange} />
<br />
<label>UpperBound: </label>
<input type="number" value={this.state.upperBound} onChange={this.onUpperBoundChange} />
<br />
<button onClick={this.handleApply}>Apply</button>
<br /><br />
<Slider range allowCross={false} value={this.state.value} onChange={this.onSliderChange} />
</div>
);
}, },
}); });
+1
View File
@@ -0,0 +1 @@
placeholder
+55
View File
@@ -0,0 +1,55 @@
require('rc-slider/assets/index.less');
const React = require('react');
const ReactDOM = require('react-dom');
const Slider = require('rc-slider');
const style = {float: 'left', width: 160, height: 400, marginBottom: 160, marginLeft: 50};
const parentStyle = {overflow: 'hidden'};
const marks = {
'-10': '-10°C',
0: <strong>0°C</strong>,
26: '26°C',
37: '37°C',
50: '50°C',
100: {
style: {
color: 'red',
},
label: <strong>100°C</strong>,
},
};
function log(value) {
console.log(value);
}
ReactDOM.render(
<div style={parentStyle}>
<div style={style}>
<p>Slider with marks, `step=null`</p>
<Slider vertical min={-10} marks={marks} step={null} onChange={log} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks and steps</p>
<Slider vertical dots min={-10} marks={marks} step={10} onChange={log} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks, `included=false`</p>
<Slider vertical min={-10} marks={marks} included={false} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks and steps, `included=false`</p>
<Slider vertical min={-10} marks={marks} step={10} included={false} defaultValue={20} />
</div>
<div style={style}>
<p>Range with marks</p>
<Slider vertical min={-10} range marks={marks} onChange={log} defaultValue={[20, 40]} />
</div>
<div style={style}>
<p>Range with marks and steps</p>
<Slider vertical min={-10} range marks={marks} step={10} onChange={log} defaultValue={[20, 40]} />
</div>
</div>
, document.getElementById('__react-content'));
View File
+116
View File
@@ -0,0 +1,116 @@
/* eslint react/no-multi-comp: 0 */
require('rc-slider/assets/index.less');
const React = require('react');
const ReactDOM = require('react-dom');
const Slider = require('rc-slider');
const style = {float: 'left', width: 180, height: 400, marginBottom: 160, marginLeft: 50};
const parentStyle = {overflow: 'hidden'};
function log(value) {
console.log(value);
}
const CustomizedRange = React.createClass({
getInitialState: function() {
return {
lowerBound: 20,
upperBound: 40,
value: [20, 40],
};
},
onLowerBoundChange: function(e) {
this.setState({ lowerBound: +e.target.value });
},
onUpperBoundChange: function(e) {
this.setState({ upperBound: +e.target.value });
},
onSliderChange: function(value) {
log(value);
this.setState({
value: value,
});
},
handleApply: function() {
const { lowerBound, upperBound } = this.state;
this.setState({ value: [lowerBound, upperBound]});
},
render: function() {
return (
<div style={style}>
<Slider range vertical allowCross={false} value={this.state.value} onChange={this.onSliderChange} />
<label>LowerBound: </label>
<input type="number" value={this.state.lowerBound} onChange={this.onLowerBoundChange} />
<br />
<label>UpperBound: </label>
<input type="number" value={this.state.upperBound} onChange={this.onUpperBoundChange} />
<br />
<button onClick={this.handleApply}>Apply</button>
</div>
);
},
});
const DynamicBounds = React.createClass({
getInitialState() {
return {
min: 0,
max: 100,
};
},
onSliderChange: function(value) {
log(value);
},
onMinChange: function(e) {
this.setState({
min: +e.target.value || 0,
});
},
onMaxChange: function(e) {
this.setState({
max: +e.target.value || 100,
});
},
render: function() {
return (
<div style={style}>
<Slider range vertical defaultValue={[20, 50]} min={this.state.min} max={this.state.max} onChange={this.onSliderChange} />
<label>Min: </label>
<input type="number" value={this.state.min} onChange={this.onMinChange} />
<br />
<label>Max: </label>
<input type="number" value={this.state.max} onChange={this.onMaxChange} />
</div>
);
},
});
ReactDOM.render(
<div style={parentStyle}>
<div style={style}>
<p>Basic Range`allowCross=false`</p>
<Slider range vertical allowCross={false} defaultValue={[0, 20]} onChange={log} />
</div>
<div style={style}>
<p>Basic Range`step=20` </p>
<Slider range vertical step={20} defaultValue={[20, 40]} onBeforeChange={log} />
</div>
<div style={style}>
<p>Basic Range`step=20, dots` </p>
<Slider range vertical dots step={20} defaultValue={[20, 40]} onAfterChange={log} />
</div>
<div style={style}>
<p>Controlled Range</p>
<Slider range vertical value={[20, 40]} />
</div>
<div style={style}>
<p>Customized Range</p>
<CustomizedRange />
</div>
<div style={style}>
<p>Range with dynamic `max` `min`</p>
<DynamicBounds />
</div>
</div>
, document.getElementById('__react-content'));
+1
View File
@@ -0,0 +1 @@
placeholder
+106
View File
@@ -0,0 +1,106 @@
/* eslint react/no-multi-comp: 0 */
require('rc-slider/assets/index.less');
const React = require('react');
const ReactDOM = require('react-dom');
const Slider = require('rc-slider');
const style = {float: 'left', width: 200, height: 400, marginBottom: 160, marginLeft: 50};
const parentStyle = {overflow: 'hidden'};
function log(value) {
console.log(value);
}
function percentFormatter(v) {
return v + ' %';
}
const CustomizedSlider = React.createClass({
getInitialState: function() {
return {
value: 50,
};
},
onSliderChange: function(value) {
log(value);
this.setState({
value: value,
});
},
render: function() {
return <Slider vertical value={this.state.value} onChange={this.onSliderChange} />;
},
});
const DynamicBounds = React.createClass({
getInitialState: function() {
return {
min: 0,
max: 100,
};
},
onSliderChange: function(value) {
log(value);
},
onMinChange: function(e) {
this.setState({
min: +e.target.value || 0,
});
},
onMaxChange: function(e) {
this.setState({
max: +e.target.value || 100,
});
},
render: function() {
return (
<div style={style}>
<p>Slider with dynamic `min` `max`</p>
<Slider vertical defaultValue={50} min={this.state.min} max={this.state.max} onChange={this.onSliderChange} />
<label>Min: </label>
<input type="number" value={this.state.min} onChange={this.onMinChange} />
<br />
<label>Max: </label>
<input type="number" value={this.state.max} onChange={this.onMaxChange} />
</div>
);
},
});
ReactDOM.render(
<div style={parentStyle}>
<div style={style}>
<p>Basic Slider</p>
<Slider vertical tipTransitionName="rc-slider-tooltip-zoom-down" onChange={log} />
</div>
<div style={style}>
<p>Basic Slider`step=20`</p>
<Slider vertical step={20} defaultValue={50} onBeforeChange={log} />
</div>
<div style={style}>
<p>Basic Slider`step=20, dots`</p>
<Slider vertical dots step={20} defaultValue={100} onAfterChange={log} />
</div>
<div style={style}>
<p>Basic Slider with `tipFormatter`</p>
<Slider vertical tipFormatter={percentFormatter} tipTransitionName="rc-slider-tooltip-zoom-down" onChange={log} />
</div>
<div style={style}>
<p>Basic Slider without tooltip</p>
<Slider vertical tipFormatter={null} onChange={log} />
</div>
<div style={style}>
<p>Controlled Slider</p>
<Slider vertical value={50} />
</div>
<div style={style}>
<p>Customized Slider</p>
<CustomizedSlider />
</div>
<div>
<DynamicBounds />
</div>
</div>
, document.getElementById('__react-content'));
+1 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "rc-slider", "name": "rc-slider",
"version": "3.3.1", "version": "3.6.0",
"description": "slider ui component for react", "description": "slider ui component for react",
"keywords": [ "keywords": [
"react", "react",
@@ -51,7 +51,6 @@
], ],
"dependencies": { "dependencies": {
"classnames": "^2.2.1", "classnames": "^2.2.1",
"object-assign": "^4.0.1",
"rc-tooltip": "3.x", "rc-tooltip": "3.x",
"rc-util": "3.x" "rc-util": "3.x"
} }
+3 -2
View File
@@ -24,10 +24,10 @@ export default class Handle extends React.Component {
render() { render() {
const props = this.props; const props = this.props;
const {className, tipTransitionName, tipFormatter, offset, value} = props; const {className, tipTransitionName, tipFormatter, vertical, offset, value} = props;
const {dragging, noTip} = props; const {dragging, noTip} = props;
const style = { left: offset + '%' }; const style = vertical ? { bottom: offset + '%' } : { left: offset + '%' };
const handle = (<div className={className} style={style} const handle = (<div className={className} style={style}
onMouseUp={this.showTooltip.bind(this)} onMouseUp={this.showTooltip.bind(this)}
onMouseEnter={this.showTooltip.bind(this)} onMouseEnter={this.showTooltip.bind(this)}
@@ -52,6 +52,7 @@ export default class Handle extends React.Component {
Handle.propTypes = { Handle.propTypes = {
className: React.PropTypes.string, className: React.PropTypes.string,
vertical: React.PropTypes.bool,
offset: React.PropTypes.number, offset: React.PropTypes.number,
tipTransitionName: React.PropTypes.string, tipTransitionName: React.PropTypes.string,
tipFormatter: React.PropTypes.func, tipFormatter: React.PropTypes.func,
+23 -6
View File
@@ -1,14 +1,14 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
const Marks = ({className, marks, included, upperBound, lowerBound, max, min}) => { const Marks = ({className, vertical, marks, included, upperBound, lowerBound, max, min}) => {
const marksKeys = Object.keys(marks); const marksKeys = Object.keys(marks);
const marksCount = marksKeys.length; const marksCount = marksKeys.length;
const unit = 100 / (marksCount - 1); const unit = 100 / (marksCount - 1);
const markWidth = unit * 0.9; const markWidth = unit * 0.9;
const range = max - min; const range = max - min;
const elements = marksKeys.map(parseFloat).map((point) => { const elements = marksKeys.map(parseFloat).sort((a, b) => a - b).map((point) => {
const isActived = (!included && point === upperBound) || const isActived = (!included && point === upperBound) ||
(included && point <= upperBound && point >= lowerBound); (included && point <= upperBound && point >= lowerBound);
const markClassName = classNames({ const markClassName = classNames({
@@ -16,11 +16,28 @@ const Marks = ({className, marks, included, upperBound, lowerBound, max, min}) =
[className + '-text-active']: isActived, [className + '-text-active']: isActived,
}); });
const style = { width: markWidth + '%' }; const bottomStyle = {
style.left = (point - min) / range * 100 - markWidth / 2 + '%'; // height: markWidth + '%',
marginBottom: '-200' + '%',
bottom: (point - min) / range * 100 + '%',
};
return (<span className={markClassName} style={style} key={point}> const leftStyle = {
{marks[point]} width: markWidth + '%',
marginLeft: -markWidth / 2 + '%',
left: (point - min) / range * 100 + '%',
};
const style = vertical ? bottomStyle : leftStyle;
const markPoint = marks[point];
const markPointIsObject = typeof markPoint === 'object' &&
!React.isValidElement(markPoint);
const markLabel = markPointIsObject ? markPoint.label : markPoint;
const markStyle = markPointIsObject ?
{ ...style, ...markPoint.style } : style;
return (<span className={markClassName} style={markStyle} key={point}>
{markLabel}
</span>); </span>);
}); });
+34 -30
View File
@@ -1,10 +1,9 @@
import React from 'react'; import React from 'react';
import {Dom as DomUtils} from 'rc-util'; import {Dom as DomUtils} from 'rc-util';
import classNames from 'classnames'; import classNames from 'classnames';
import objectAssign from 'object-assign';
import Track from './Track'; import Track from './Track';
import Handle from './Handle'; import Handle from './Handle';
import Dots from './Dots'; import Steps from './Steps';
import Marks from './Marks'; import Marks from './Marks';
function noop() { function noop() {
@@ -14,12 +13,12 @@ function isNotTouchEvent(e) {
return e.touches.length > 1 || (e.type.toLowerCase() === 'touchend' && e.touches.length > 0); return e.touches.length > 1 || (e.type.toLowerCase() === 'touchend' && e.touches.length > 0);
} }
function getTouchPosition(e) { function getTouchPosition(vertical, e) {
return e.touches[0].pageX; return vertical ? e.touches[0].clientY : e.touches[0].pageX;
} }
function getMousePosition(e) { function getMousePosition(vertical, e) {
return e.pageX; return vertical ? e.clientY : e.pageX;
} }
function pauseEvent(e) { function pauseEvent(e) {
@@ -34,7 +33,7 @@ class Slider extends React.Component {
const {range, min, max} = props; const {range, min, max} = props;
const initialValue = range ? [min, min] : min; const initialValue = range ? [min, min] : min;
const defaultValue = ('defaultValue' in props ? props.defaultValue : initialValue); const defaultValue = ('defaultValue' in props ? props.defaultValue : initialValue);
const value = ('value' in props ? props.value : defaultValue); const value = (props.value !== undefined ? props.value : defaultValue);
let upperBound; let upperBound;
let lowerBound; let lowerBound;
@@ -81,11 +80,11 @@ class Slider extends React.Component {
lowerBound: nextLowerBound, lowerBound: nextLowerBound,
}); });
if (this.isValueOutOfBounds(upperBound, nextProps) || if (this.isValueOutOfBounds(upperBound, nextProps) ||
this.isValueOutOfBounds(lowerBound, nextProps)) { this.isValueOutOfBounds(lowerBound, nextProps)) {
this.props.onChange([nextLowerBound, nextUpperBound]); this.props.onChange([nextLowerBound, nextUpperBound]);
} }
} else { } else {
const value = 'value' in nextProps ? nextProps.value : upperBound; const value = nextProps.value !== undefined ? nextProps.value : upperBound;
const nextValue = this.trimAlignValue(value, nextProps); const nextValue = this.trimAlignValue(value, nextProps);
if (nextValue === upperBound && lowerBound === nextProps.min) return; if (nextValue === upperBound && lowerBound === nextProps.min) return;
@@ -108,13 +107,13 @@ class Slider extends React.Component {
this.setState({handle: state.handle}); this.setState({handle: state.handle});
} }
const data = objectAssign({}, this.state, state); const data = {...this.state, ...state};
const changedValue = props.range ? [data.lowerBound, data.upperBound] : data.upperBound; const changedValue = props.range ? [data.lowerBound, data.upperBound] : data.upperBound;
props.onChange(changedValue); props.onChange(changedValue);
} }
onMouseMove(e) { onMouseMove(e) {
const position = getMousePosition(e); const position = getMousePosition(this.props.vertical, e);
this.onMove(e, position); this.onMove(e, position);
} }
@@ -124,7 +123,7 @@ class Slider extends React.Component {
return; return;
} }
const position = getTouchPosition(e); const position = getTouchPosition(this.props.vertical, e);
this.onMove(e, position); this.onMove(e, position);
} }
@@ -133,7 +132,8 @@ class Slider extends React.Component {
const props = this.props; const props = this.props;
const state = this.state; const state = this.state;
const diffPosition = position - this.startPosition; let diffPosition = position - this.startPosition;
diffPosition = this.props.vertical ? -diffPosition : diffPosition;
const diffValue = diffPosition / this.getSliderLength() * (props.max - props.min); const diffValue = diffPosition / this.getSliderLength() * (props.max - props.min);
const value = this.trimAlignValue(this.startValue + diffValue); const value = this.trimAlignValue(this.startValue + diffValue);
@@ -165,14 +165,14 @@ class Slider extends React.Component {
onTouchStart(e) { onTouchStart(e) {
if (isNotTouchEvent(e)) return; if (isNotTouchEvent(e)) return;
const position = getTouchPosition(e); const position = getTouchPosition(this.props.vertical, e);
this.onStart(position); this.onStart(position);
this.addDocumentEvents('touch'); this.addDocumentEvents('touch');
pauseEvent(e); pauseEvent(e);
} }
onMouseDown(e) { onMouseDown(e) {
const position = getMousePosition(e); const position = getMousePosition(this.props.vertical, e);
this.onStart(position); this.onStart(position);
this.addDocumentEvents('mouse'); this.addDocumentEvents('mouse');
pauseEvent(e); pauseEvent(e);
@@ -230,14 +230,14 @@ class Slider extends React.Component {
return 0; return 0;
} }
return slider.clientWidth; return this.props.vertical ? slider.clientHeight : slider.clientWidth;
} }
getSliderStart() { getSliderStart() {
const slider = this.refs.slider; const slider = this.refs.slider;
const rect = slider.getBoundingClientRect(); const rect = slider.getBoundingClientRect();
return rect.left; return this.props.vertical ? rect.top : rect.left;
} }
getPrecision() { getPrecision() {
@@ -257,7 +257,7 @@ class Slider extends React.Component {
trimAlignValue(v, nextProps) { trimAlignValue(v, nextProps) {
const state = this.state || {}; const state = this.state || {};
const {handle, lowerBound, upperBound} = state; const {handle, lowerBound, upperBound} = state;
const {marks, step, min, max, allowCross} = objectAssign({}, this.props, nextProps || {}); const {marks, step, min, max, allowCross} = {...this.props, ...(nextProps || {})};
let val = v; let val = v;
if (val <= min) { if (val <= min) {
@@ -292,9 +292,10 @@ class Slider extends React.Component {
} }
calcValue(offset) { calcValue(offset) {
const {min, max} = this.props; const {vertical, min, max} = this.props;
const ratio = offset / this.getSliderLength(); const ratio = Math.abs(offset / this.getSliderLength());
return ratio * (max - min) + min; const value = vertical ? (1 - ratio) * (max - min) + min : ratio * (max - min) + min;
return value;
} }
calcValueByPos(position) { calcValueByPos(position) {
@@ -332,8 +333,8 @@ class Slider extends React.Component {
render() { render() {
const {handle, upperBound, lowerBound} = this.state; const {handle, upperBound, lowerBound} = this.state;
const {className, prefixCls, disabled, dots, included, range, step, const {className, prefixCls, disabled, vertical, dots, included, range, step,
marks, max, min, tipTransitionName, tipFormatter, children} = this.props; marks, max, min, tipTransitionName, tipFormatter, children} = this.props;
const upperOffset = this.calcOffset(upperBound); const upperOffset = this.calcOffset(upperBound);
const lowerOffset = this.calcOffset(lowerBound); const lowerOffset = this.calcOffset(lowerBound);
@@ -343,19 +344,20 @@ class Slider extends React.Component {
const upper = (<Handle className={handleClassName} const upper = (<Handle className={handleClassName}
noTip={isNoTip} tipTransitionName={tipTransitionName} tipFormatter={tipFormatter} noTip={isNoTip} tipTransitionName={tipTransitionName} tipFormatter={tipFormatter}
offset={upperOffset} value={upperBound} dragging={handle === 'upperBound'} />); vertical = {vertical} offset={upperOffset} value={upperBound} dragging={handle === 'upperBound'}/>);
let lower = null; let lower = null;
if (range) { if (range) {
lower = (<Handle className={handleClassName} lower = (<Handle className={handleClassName}
noTip={isNoTip} tipTransitionName={tipTransitionName} tipFormatter={tipFormatter} noTip={isNoTip} tipTransitionName={tipTransitionName} tipFormatter={tipFormatter}
offset={lowerOffset} value={lowerBound} dragging={handle === 'lowerBound'} />); vertical = {vertical} offset={lowerOffset} value={lowerBound} dragging={handle === 'lowerBound'}/>);
} }
const sliderClassName = classNames({ const sliderClassName = classNames({
[prefixCls]: true, [prefixCls]: true,
[prefixCls + '-disabled']: disabled, [prefixCls + '-disabled']: disabled,
[className]: !!className, [className]: !!className,
[prefixCls + '-vertical']: this.props.vertical,
}); });
const isIncluded = included || range; const isIncluded = included || range;
return ( return (
@@ -364,14 +366,14 @@ class Slider extends React.Component {
onMouseDown={disabled ? noop : this.onMouseDown.bind(this)}> onMouseDown={disabled ? noop : this.onMouseDown.bind(this)}>
{upper} {upper}
{lower} {lower}
<Track className={prefixCls + '-track'} included={isIncluded} <Track className={prefixCls + '-track'} vertical = {vertical} included={isIncluded}
offset={lowerOffset} length={upperOffset - lowerOffset}/> offset={lowerOffset} length={upperOffset - lowerOffset}/>
<Dots prefixCls={prefixCls} marks={marks} dots={dots} step={step} <Steps prefixCls={prefixCls} vertical = {vertical} marks={marks} dots={dots} step={step}
included={isIncluded} lowerBound={lowerBound} included={isIncluded} lowerBound={lowerBound}
upperBound={upperBound} max={max} min={min} /> upperBound={upperBound} max={max} min={min}/>
<Marks className={prefixCls + '-mark'} marks={marks} <Marks className={prefixCls + '-mark'} vertical = {vertical} marks={marks}
included={isIncluded} lowerBound={lowerBound} included={isIncluded} lowerBound={lowerBound}
upperBound={upperBound} max={max} min={min} /> upperBound={upperBound} max={max} min={min}/>
{children} {children}
</div> </div>
); );
@@ -403,6 +405,7 @@ Slider.propTypes = {
tipFormatter: React.PropTypes.func, tipFormatter: React.PropTypes.func,
dots: React.PropTypes.bool, dots: React.PropTypes.bool,
range: React.PropTypes.bool, range: React.PropTypes.bool,
vertical: React.PropTypes.bool,
allowCross: React.PropTypes.bool, allowCross: React.PropTypes.bool,
}; };
@@ -422,6 +425,7 @@ Slider.defaultProps = {
disabled: false, disabled: false,
dots: false, dots: false,
range: false, range: false,
vertical: false,
allowCross: true, allowCross: true,
}; };
+7 -6
View File
@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
function calcPoints(marks, dots, step, min, max) { function calcPoints(vertical, marks, dots, step, min, max) {
const points = Object.keys(marks).map(parseFloat); const points = Object.keys(marks).map(parseFloat);
if (dots) { if (dots) {
for (let i = min; i <= max; i = i + step) { for (let i = min; i <= max; i = i + step) {
@@ -12,11 +12,12 @@ function calcPoints(marks, dots, step, min, max) {
return points; return points;
} }
const Dots = ({prefixCls, marks, dots, step, included, lowerBound, upperBound, max, min}) => { const Steps = ({prefixCls, vertical, marks, dots, step, included,
lowerBound, upperBound, max, min}) => {
const range = max - min; const range = max - min;
const elements = calcPoints(marks, dots, step, min, max).map((point) => { const elements = calcPoints(vertical, marks, dots, step, min, max).map((point) => {
const offset = (point - min) / range * 100 + '%'; const offset = Math.abs(point - min) / range * 100 + '%';
const style = { left: offset }; const style = vertical ? { bottom: offset } : { left: offset };
const isActived = (!included && point === upperBound) || const isActived = (!included && point === upperBound) ||
(included && point <= upperBound && point >= lowerBound); (included && point <= upperBound && point >= lowerBound);
@@ -31,4 +32,4 @@ const Dots = ({prefixCls, marks, dots, step, included, lowerBound, upperBound, m
return <div className={prefixCls + '-step'}>{elements}</div>; return <div className={prefixCls + '-step'}>{elements}</div>;
}; };
export default Dots; export default Steps;
+8 -3
View File
@@ -1,11 +1,16 @@
import React from 'react'; import React from 'react';
const Track = ({className, included, offset, length}) => { const Track = ({className, included, vertical, offset, length}) => {
const style = { const style = {
left: offset + '%',
width: length + '%',
visibility: included ? 'visible' : 'hidden', visibility: included ? 'visible' : 'hidden',
}; };
if (vertical) {
style.bottom = offset + '%';
style.height = length + '%';
} else {
style.left = offset + '%';
style.width = length + '%';
}
return <div className={className} style={style} />; return <div className={className} style={style} />;
}; };
+6 -1
View File
@@ -6,7 +6,7 @@ const Slider = require('..');
require('../assets/index.less'); require('../assets/index.less');
describe('rc-slider', function() { describe('rc-slider', function test() {
this.timeout(5000); this.timeout(5000);
const div = document.createElement('div'); const div = document.createElement('div');
document.body.appendChild(div); document.body.appendChild(div);
@@ -140,4 +140,9 @@ describe('rc-slider', function() {
expect(range.state.upperBound).to.be(90); expect(range.state.upperBound).to.be(90);
ReactDOM.unmountComponentAtNode(div); ReactDOM.unmountComponentAtNode(div);
}); });
it('should render a vertical slider, when `vertical` is true', () => {
const slider = ReactDOM.render(<Slider vertical />, div);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-vertical').length).to.be(1);
});
}); });