From 8dc66dd2a4f0f0ac2da4fb0957b2397e0826610d Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Mon, 16 Nov 2015 17:42:46 +0800 Subject: [PATCH 01/12] chore: remove `isIncluded` --- src/Slider.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Slider.jsx b/src/Slider.jsx index 4dde98a..2baca4a 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -352,7 +352,7 @@ class Slider extends React.Component { render() { const {handle, upperBound, lowerBound} = this.state; - const {className, prefixCls, disabled, included, isIncluded, dots, range, + const {className, prefixCls, disabled, included, dots, range, marks, step, max, min, tipTransitionName, tipFormatter, children} = this.props; const marksLen = marks.length; @@ -366,7 +366,7 @@ class Slider extends React.Component { const lowerOffset = this.calcOffset(lowerBound); let track = null; - if ((included && isIncluded) || range) { + if (included || range) { const trackClassName = prefixCls + '-track'; track = ; } @@ -390,14 +390,14 @@ class Slider extends React.Component { const stepNum = marksLen > 0 ? marksLen : Math.floor((max - min) / step) + 1; steps = (); + included={included || range}/>); } let mark = null; if (marksLen > 0) { const markClassName = prefixCls + '-mark'; mark = (); + index={upperIndex} included={included}/>); } return ( @@ -436,7 +436,6 @@ Slider.propTypes = { React.PropTypes.arrayOf(React.PropTypes.number), ]), marks: React.PropTypes.array, - isIncluded: React.PropTypes.bool, // @Deprecated included: React.PropTypes.bool, className: React.PropTypes.string, prefixCls: React.PropTypes.string, @@ -457,7 +456,6 @@ Slider.defaultProps = { step: 1, defaultIndex: 0, marks: [], - isIncluded: true, // @Deprecated included: true, className: '', prefixCls: 'rc-slider', From e3ba1eee5b40b5d646f5a5db794e59b379709b33 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Mon, 16 Nov 2015 17:53:26 +0800 Subject: [PATCH 02/12] feat: marks should be an object --- examples/marks.js | 10 ++++++- src/Marks.jsx | 33 ++++++++++++----------- src/Slider.jsx | 68 ++++++++++++++++++++++++----------------------- src/Steps.jsx | 31 +++++++++------------ 4 files changed, 74 insertions(+), 68 deletions(-) diff --git a/examples/marks.js b/examples/marks.js index a487bc0..6e1dac6 100644 --- a/examples/marks.js +++ b/examples/marks.js @@ -7,7 +7,15 @@ var ReactDOM = require('react-dom'); var Slider = require('rc-slider'); var style = {width: 400, margin: 50}; -var marks = ['A','B','C','D', 'E', 'F']; +var marks = { + 0: 'A', + 20: 'B', + 40: 'C', + 60: 'D', + 80: 'E', + 100: 'F' +}; + var log = function(value) { console.log(value); }; diff --git a/src/Marks.jsx b/src/Marks.jsx index 7a03023..db7ace7 100644 --- a/src/Marks.jsx +++ b/src/Marks.jsx @@ -1,35 +1,36 @@ import React from 'react'; import rcUtil from 'rc-util'; -const Marks = ({className, marks, index, included}) => { - const marksLen = marks.length; - const unit = 100 / (marksLen - 1); +const Marks = ({className, marks, included, upperBound, lowerBound, max, min}) => { + const marksKeys = Object.keys(marks); + const marksCount = marksKeys.length; + const unit = 100 / (marksCount - 1); const markWidth = unit / 2 + '%'; - const elements = []; - for (let i = 0; i < marksLen; i++) { - const isActived = (included && i <= index) || (!included && i === index); + const range = max - min; + const elements = marksKeys.map(parseFloat).map((point) => { + const isActived = (!included && point === upperBound) || + (included && point <= upperBound && point >= lowerBound); const markClassName = rcUtil.classSet({ [className + '-text']: true, [className + '-text-active']: isActived, }); const style = { width: markWidth }; - const offset = unit * i; - if (i === marksLen - 1) { + if (point === marksCount - 1) { style.right = -unit / 4 + '%'; + } else if (point === 0) { + style.left = -unit / 4 + '%'; } else { - style.left = (i > 0 ? offset - unit / 4 : -unit / 4) + '%'; + style.left = (point - min) / range * 100 - unit / 4 + '%'; } - elements.push( - {marks[i]} - ); - } + return ( + {marks[point]} + ); + }); - return (
- {elements} -
); + return
{elements}
; }; export default Marks; diff --git a/src/Slider.jsx b/src/Slider.jsx index 2baca4a..99fe49a 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -25,6 +25,10 @@ function pauseEvent(e) { e.preventDefault(); } +function isEmpty(collection) { + return Object.keys(collection).length === 0; +} + // This is an utility method, tries to get property, then defaultPropery with // special check using 'in', because propery can be '0' function propOrDefault(props, name, fallback) { @@ -40,7 +44,7 @@ class Slider extends React.Component { let upperBound; let lowerBound; const initialValue = props.range ? [0, 0] : 0; - if (props.marks.length > 0) { + if (!isEmpty(props.marks)) { const index = propOrDefault(props, 'index', initialValue); ({lowerBound, upperBound} = this.getBoundsFromIndex(index, props)); } else { @@ -139,7 +143,7 @@ class Slider extends React.Component { pauseEvent(e); } - onSliderMouseDown(e) { + onMouseDown(e) { const position = getMousePosition(e); this.onStart(position); this.addDocumentEvents('mouse'); @@ -209,10 +213,10 @@ class Slider extends React.Component { getIndex(value) { const {marks, min, max, step} = this.props; - if (marks.length === 0) { + if (isEmpty(marks)) { return Math.floor((value - min) / step); } - const unit = ((max - min) / (marks.length - 1)).toFixed(5); + const unit = ((max - min) / (Object.keys(marks).length - 1)).toFixed(5); return Math.round(value / unit); } @@ -228,6 +232,17 @@ class Slider extends React.Component { }; } + getPoints() { + const {marks, step, dots, min, max} = this.props; + const points = new Set(Object.keys(marks)); + if (step > 1 && dots) { + for (let i = min; i <= max; i = i + step) { + points.add(i); + } + } + return Array.from(points); + } + getSliderLength() { const slider = this.refs.slider; if (!slider) { @@ -249,7 +264,7 @@ class Slider extends React.Component { const {handle, lowerBound, upperBound} = state; const props = this.props; const {marks, min, max} = props; - const marksLen = marks.length; + const marksLen = Object.keys(marks).length; const step = (marksLen > 0) ? (max - min) / (marksLen - 1) : props.step; let val = v; @@ -295,7 +310,7 @@ class Slider extends React.Component { } calcValueFromIndex(index, props) { - const marksLen = props.marks.length; + const marksLen = Object.keys(props.marks).length; if (marksLen > 0) { const value = ((props.max - props.min) / (marksLen - 1)) * (index); return parseFloat(value.toFixed(5)); @@ -305,7 +320,7 @@ class Slider extends React.Component { triggerEvents(event, v) { const props = this.props; - const hasMarks = (props.marks.length > 0); + const hasMarks = !isEmpty(props.marks); if (props[event]) { let data; if (hasMarks) { @@ -352,9 +367,9 @@ class Slider extends React.Component { render() { const {handle, upperBound, lowerBound} = this.state; - const {className, prefixCls, disabled, included, dots, range, - marks, step, max, min, tipTransitionName, tipFormatter, children} = this.props; - const marksLen = marks.length; + const {className, prefixCls, disabled, included, range, + marks, max, min, tipTransitionName, tipFormatter, children} = this.props; + const marksLen = Object.keys(marks).length; const sliderClassName = classSet({ [prefixCls]: true, @@ -382,33 +397,20 @@ class Slider extends React.Component { offset={lowerOffset} value={lowerBound} dragging={handle === 'lowerBound'} />); } - const upperIndex = this.getIndex(upperBound); - - let steps = null; - if (marksLen > 0 || (step > 1 && dots)) { - const stepsClassName = prefixCls + '-step'; - const stepNum = marksLen > 0 ? marksLen : Math.floor((max - min) / step) + 1; - steps = (); - } - - let mark = null; - if (marksLen > 0) { - const markClassName = prefixCls + '-mark'; - mark = (); - } - + const isIncluded = included || range; return (
+ onMouseDown={disabled ? noop : this.onMouseDown.bind(this)}> {track} {upper} {lower} - {steps} - {mark} + + {children}
); @@ -435,7 +437,7 @@ Slider.propTypes = { React.PropTypes.number, React.PropTypes.arrayOf(React.PropTypes.number), ]), - marks: React.PropTypes.array, + marks: React.PropTypes.object, included: React.PropTypes.bool, className: React.PropTypes.string, prefixCls: React.PropTypes.string, @@ -455,7 +457,7 @@ Slider.defaultProps = { max: 100, step: 1, defaultIndex: 0, - marks: [], + marks: {}, included: true, className: '', prefixCls: 'rc-slider', diff --git a/src/Steps.jsx b/src/Steps.jsx index da2cdb0..816dcd5 100644 --- a/src/Steps.jsx +++ b/src/Steps.jsx @@ -1,28 +1,23 @@ import React from 'react'; -import rcUtil from 'rc-util'; +import { classSet } from 'rc-util'; -const Steps = ({className, stepNum, included, lowerIndex, upperIndex}) => { - const dotClassName = className.replace('step', 'dot'); - const unit = 100 / (stepNum - 1); - - const elements = []; - for (let i = 0; i < stepNum; i++) { - const offset = unit * i + '%'; +const Steps = ({prefixCls, points, included, lowerBound, upperBound, max, min}) => { + const range = max - min; + const elements = points.map(parseFloat).map((point) => { + const offset = (point - min) / range * 100 + '%'; const style = { left: offset }; - const isActived = (included && i <= upperIndex && i >= lowerIndex ) || - (!included && i === upperIndex); - const stepClassName = rcUtil.classSet({ - [dotClassName]: true, - [dotClassName + '-active']: isActived, + const isActived = (!included && point === upperBound) || + (included && point <= upperBound && point >= lowerBound); + const pointClassName = classSet({ + [prefixCls + '-dot']: true, + [prefixCls + '-dot-active']: isActived, }); - elements.push(); - } + return ; + }); - return (
- {elements} -
); + return
{elements}
; }; export default Steps; From fd6c393f660ef21bc22ffb42f978a23062f92d25 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Tue, 17 Nov 2015 16:04:50 +0800 Subject: [PATCH 03/12] feat: `Steps` should not depend on `marks` --- src/Slider.jsx | 34 ++++++++++++++-------------------- src/Steps.jsx | 25 +++++++++++++------------ 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/Slider.jsx b/src/Slider.jsx index 99fe49a..87423ca 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -233,9 +233,9 @@ class Slider extends React.Component { } getPoints() { - const {marks, step, dots, min, max} = this.props; + const {marks, step, min, max} = this.props; const points = new Set(Object.keys(marks)); - if (step > 1 && dots) { + if (step > 1) { for (let i = min; i <= max; i = i + step) { points.add(i); } @@ -262,10 +262,7 @@ class Slider extends React.Component { trimAlignValue(v) { const state = this.state || {}; const {handle, lowerBound, upperBound} = state; - const props = this.props; - const {marks, min, max} = props; - const marksLen = Object.keys(marks).length; - const step = (marksLen > 0) ? (max - min) / (marksLen - 1) : props.step; + const {min, max} = this.props; let val = v; if (val <= min) { @@ -281,14 +278,11 @@ class Slider extends React.Component { val = upperBound; } - const valModStep = (val - min) % step; + const points = this.getPoints().map(parseFloat); + const diffs = points.map((point) => Math.abs(val - point)); + const closestPoint = points[diffs.indexOf(Math.min.apply(Math, diffs))]; - let alignValue = val - valModStep; - if (Math.abs(valModStep) * 2 >= step) { - alignValue += (valModStep > 0) ? step : (-step); - } - - return parseFloat(alignValue.toFixed(5)); + return closestPoint; } calcOffset(value) { @@ -310,9 +304,9 @@ class Slider extends React.Component { } calcValueFromIndex(index, props) { - const marksLen = Object.keys(props.marks).length; - if (marksLen > 0) { - const value = ((props.max - props.min) / (marksLen - 1)) * (index); + const marksCount = Object.keys(props.marks).length; + if (marksCount > 0) { + const value = ((props.max - props.min) / (marksCount - 1)) * (index); return parseFloat(value.toFixed(5)); } return ('value' in props ? props.value : props.defaultValue); @@ -367,9 +361,9 @@ class Slider extends React.Component { render() { const {handle, upperBound, lowerBound} = this.state; - const {className, prefixCls, disabled, included, range, + const {className, prefixCls, disabled, dots, included, range, marks, max, min, tipTransitionName, tipFormatter, children} = this.props; - const marksLen = Object.keys(marks).length; + const marksCount = Object.keys(marks).length; const sliderClassName = classSet({ [prefixCls]: true, @@ -387,7 +381,7 @@ class Slider extends React.Component { } const handleClassName = prefixCls + '-handle'; - const isNoTip = (marksLen > 0) && !tipFormatter; + const isNoTip = (marksCount > 0) && !tipFormatter; const upper = (); @@ -405,7 +399,7 @@ class Slider extends React.Component { {track} {upper} {lower} - { +const Steps = ({prefixCls, points, dots, included, lowerBound, upperBound, max, min}) => { const range = max - min; - const elements = points.map(parseFloat).map((point) => { - const offset = (point - min) / range * 100 + '%'; - const style = { left: offset }; + const elements = points.filter((point) => typeof point === 'string' || dots).map(parseFloat) + .map((point) => { + const offset = (point - min) / range * 100 + '%'; + const style = { left: offset }; - const isActived = (!included && point === upperBound) || - (included && point <= upperBound && point >= lowerBound); - const pointClassName = classSet({ - [prefixCls + '-dot']: true, - [prefixCls + '-dot-active']: isActived, - }); + const isActived = (!included && point === upperBound) || + (included && point <= upperBound && point >= lowerBound); + const pointClassName = classSet({ + [prefixCls + '-dot']: true, + [prefixCls + '-dot-active']: isActived, + }); - return ; - }); + return ; + }); return
{elements}
; }; From f29894e6908aa39ac1b9d81ac02a3765018c70de Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Tue, 17 Nov 2015 16:35:44 +0800 Subject: [PATCH 04/12] chore: update tooltip `className` --- assets/index.less | 97 +++++++++++++++++++++++------------------------ src/Handle.jsx | 2 +- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/assets/index.less b/assets/index.less index a736195..66717e3 100644 --- a/assets/index.less +++ b/assets/index.less @@ -131,55 +131,6 @@ cursor: not-allowed!important; } } - - // slider tooltip style - &-tooltip { - position: absolute; - left: -9999px; - top: -9999px; - z-index: 4; - visibility: visible; - - .borderBox(); - - &-hidden { - display: none; - } - - &-placement-top { - padding: @tooltip-arrow-width 0 @tooltip-distance 0; - } - - &-inner { - padding: 6px 2px; - min-width: 24px; - height: 24px; - font-size: 12px; - line-height: 1; - color: @tooltip-color; - text-align: center; - text-decoration: none; - background-color: @tooltip-bg; - border-radius: @border-radius-base; - box-shadow: 0 0 4px #d9d9d9; - } - - &-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - } - - &-placement-top &-arrow { - bottom: @tooltip-distance - @tooltip-arrow-width; - left: 50%; - margin-left: -@tooltip-arrow-width; - border-width: @tooltip-arrow-width @tooltip-arrow-width 0; - border-top-color: @tooltip-arrow-color; - } - } } .motion-common() { @@ -241,3 +192,51 @@ transform: scale(0, 0); } } + +.rc-tooltip { + position: absolute; + left: -9999px; + top: -9999px; + z-index: 4; + visibility: visible; + + .borderBox(); + + &-hidden { + display: none; + } + + &-placement-top { + padding: @tooltip-arrow-width 0 @tooltip-distance 0; + } + + &-inner { + padding: 6px 2px; + min-width: 24px; + height: 24px; + font-size: 12px; + line-height: 1; + color: @tooltip-color; + text-align: center; + text-decoration: none; + background-color: @tooltip-bg; + border-radius: @border-radius-base; + box-shadow: 0 0 4px #d9d9d9; + } + + &-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + } + + &-placement-top &-arrow { + bottom: @tooltip-distance - @tooltip-arrow-width; + left: 50%; + margin-left: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width 0; + border-top-color: @tooltip-arrow-color; + } +} \ No newline at end of file diff --git a/src/Handle.jsx b/src/Handle.jsx index 80df82e..929d330 100644 --- a/src/Handle.jsx +++ b/src/Handle.jsx @@ -39,7 +39,7 @@ export default class Handle extends React.Component { const isTooltipVisible = dragging || this.state.isTooltipVisible; return ({tipFormatter ? tipFormatter(value) : value}
} From 1e430ba6947da2a03852f8a442c9c8fa809d7d2d Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Tue, 17 Nov 2015 17:30:48 +0800 Subject: [PATCH 05/12] fix: if there is no marks, `step=1` should work --- src/Slider.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Slider.jsx b/src/Slider.jsx index 87423ca..60e493b 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -235,7 +235,7 @@ class Slider extends React.Component { getPoints() { const {marks, step, min, max} = this.props; const points = new Set(Object.keys(marks)); - if (step > 1) { + if (isEmpty(marks) || step > 1) { for (let i = min; i <= max; i = i + step) { points.add(i); } From 0566e7f0989538b7323fa68759bdf5bd49f11370 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 18 Nov 2015 10:24:46 +0800 Subject: [PATCH 06/12] fix: should trigger event after the value is changed --- src/Slider.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Slider.jsx b/src/Slider.jsx index 60e493b..df42c84 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -182,6 +182,9 @@ class Slider extends React.Component { recent: valueNeedChanging, }); + const oldValue = state[valueNeedChanging]; + if (value === oldValue) return; + const props = this.props; // If it is not controlled component if (!('value' in props) && !('index' in props)) { From e2530ad2bf0e16c05865f24b2df4ba65d22557fc Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 18 Nov 2015 10:43:40 +0800 Subject: [PATCH 07/12] feat: Slider with marks should pass value(not index) to event handles --- examples/marks.js | 4 ++-- src/Slider.jsx | 45 ++++++++++++++------------------------------- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/examples/marks.js b/examples/marks.js index 6e1dac6..b3a3f6d 100644 --- a/examples/marks.js +++ b/examples/marks.js @@ -28,7 +28,7 @@ ReactDOM.render(

Slider with marks and steps, `included=true`

- +
@@ -46,7 +46,7 @@ ReactDOM.render(

Range with marks and steps

- +
, document.getElementById('__react-content')); diff --git a/src/Slider.jsx b/src/Slider.jsx index df42c84..f73f90f 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -127,10 +127,10 @@ class Slider extends React.Component { // If it is not controlled component if (!('value' in props) && !('index' in props)) { this.setState({[state.handle]: value}, () => { - this.triggerEvents('onChange', this.getValue()); + props.onChange(this.getValue()); }); } else { - this.triggerEvents('onChange', this.getChangedValue(state.handle, value)); + props.onChange(this.getChangedValue(state.handle, value)); } } @@ -151,7 +151,8 @@ class Slider extends React.Component { } onStart(position) { - this.triggerEvents('onBeforeChange', this.getValue()); + const props = this.props; + props.onBeforeChange(this.getValue()); const value = this.calcValueByPos(position); this.startValue = value; @@ -185,16 +186,15 @@ class Slider extends React.Component { const oldValue = state[valueNeedChanging]; if (value === oldValue) return; - const props = this.props; // If it is not controlled component if (!('value' in props) && !('index' in props)) { this.setState({ [valueNeedChanging]: value, }, () => { - this.triggerEvents('onChange', this.getValue()); + props.onChange(this.getValue()); }); } else { - this.triggerEvents('onChange', this.getChangedValue(valueNeedChanging, value)); + props.onChange(this.getChangedValue(valueNeedChanging, value)); } } @@ -315,26 +315,6 @@ class Slider extends React.Component { return ('value' in props ? props.value : props.defaultValue); } - triggerEvents(event, v) { - const props = this.props; - const hasMarks = !isEmpty(props.marks); - if (props[event]) { - let data; - if (hasMarks) { - if (props.range) { - data = v.map(bound => this.getIndex(bound)); - } else { - data = this.getIndex(v); - } - } else if (v === undefined) { - data = this.state.value; - } else { - data = v; - } - props[event](data); - } - } - addDocumentEvents(type) { if (type === 'touch') { // just work for chrome iOS Safari and Android Browser @@ -358,7 +338,7 @@ class Slider extends React.Component { end(type) { this.removeEventons(type); - this.triggerEvents('onAfterChange', this.getValue()); + this.props.onAfterChange(this.getValue()); this.setState({handle: null}); } @@ -450,16 +430,19 @@ Slider.propTypes = { }; Slider.defaultProps = { + prefixCls: 'rc-slider', + className: '', + tipTransitionName: '', min: 0, max: 100, step: 1, - defaultIndex: 0, + defaultIndex: 0, // TODO marks: {}, + onBeforeChange: noop, + onChange: noop, + onAfterChange: noop, included: true, - className: '', - prefixCls: 'rc-slider', disabled: false, - tipTransitionName: '', dots: false, range: false, }; From 7680347dfe1c645d4a72be6f1eb4c98279bd30b2 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 18 Nov 2015 11:39:18 +0800 Subject: [PATCH 08/12] feat: remove `index/defaultIndex` --- src/Slider.jsx | 132 ++++++++++++++----------------------------------- 1 file changed, 36 insertions(+), 96 deletions(-) diff --git a/src/Slider.jsx b/src/Slider.jsx index f73f90f..e40b1da 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -29,40 +29,30 @@ function isEmpty(collection) { return Object.keys(collection).length === 0; } -// This is an utility method, tries to get property, then defaultPropery with -// special check using 'in', because propery can be '0' -function propOrDefault(props, name, fallback) { - const defaultName = 'default' + name.charAt(0).toUpperCase() + name.substring(1); - const defaultValue = (defaultName in props ? props[defaultName] : fallback); - return (name in props ? props[name] : defaultValue); -} - class Slider extends React.Component { constructor(props) { super(props); + const {range, min, max} = props; + const initialValue = range ? [min, min] : min; + const defaultValue = ('defaultValue' in props ? props.defaultValue : initialValue); + const value = ('value' in props ? props.value : defaultValue); + let upperBound; let lowerBound; - const initialValue = props.range ? [0, 0] : 0; - if (!isEmpty(props.marks)) { - const index = propOrDefault(props, 'index', initialValue); - ({lowerBound, upperBound} = this.getBoundsFromIndex(index, props)); + if (props.range) { + lowerBound = this.trimAlignValue(value[0]); + upperBound = this.trimAlignValue(value[1]); } else { - const value = propOrDefault(props, 'value', initialValue); - if (props.range) { - lowerBound = this.trimAlignValue(value[0]); - upperBound = this.trimAlignValue(value[1]); - } else { - upperBound = this.trimAlignValue(value); - } + upperBound = this.trimAlignValue(value); } let recent; if (props.range && upperBound === lowerBound) { - if (lowerBound === props.max) { + if (lowerBound === max) { recent = 'lowerBound'; } - if (upperBound === props.min) { + if (upperBound === min) { recent = 'upperBound'; } } else { @@ -74,7 +64,7 @@ class Slider extends React.Component { recent: recent, upperBound: upperBound, // If Slider is not range, set `lowerBound` equal to `min`. - lowerBound: (lowerBound || props.min), + lowerBound: (lowerBound || min), }; } @@ -91,9 +81,25 @@ class Slider extends React.Component { this.setState({ upperBound: nextProps.value, }); - } else if ('index' in nextProps) { - const index = ('index' in nextProps ? nextProps.index : nextProps.defaultIndex); - this.setState(this.getBoundsFromIndex(index, nextProps)); + } + } + + onChange(handle, value) { + const props = this.props; + const isNotControlled = !('value' in props); + if (isNotControlled) { + this.setState({[handle]: value}, () => { + props.onChange(this.getValue()); + }); + } else { + const state = this.state; + const data = { + upperBound: state.upperBound, + lowerBound: state.lowerBound, + }; + data[handle] = value; + const changedValue = props.range ? [data.lowerBound, data.upperBound] : data.upperBound; + props.onChange(changedValue); } } @@ -124,14 +130,7 @@ class Slider extends React.Component { const oldValue = state[state.handle]; if (value === oldValue) return; - // If it is not controlled component - if (!('value' in props) && !('index' in props)) { - this.setState({[state.handle]: value}, () => { - props.onChange(this.getValue()); - }); - } else { - props.onChange(this.getChangedValue(state.handle, value)); - } + this.onChange(state.handle, value); } onTouchStart(e) { @@ -186,16 +185,7 @@ class Slider extends React.Component { const oldValue = state[valueNeedChanging]; if (value === oldValue) return; - // If it is not controlled component - if (!('value' in props) && !('index' in props)) { - this.setState({ - [valueNeedChanging]: value, - }, () => { - props.onChange(this.getValue()); - }); - } else { - props.onChange(this.getChangedValue(valueNeedChanging, value)); - } + this.onChange(valueNeedChanging, value); } getValue() { @@ -203,47 +193,15 @@ class Slider extends React.Component { return this.props.range ? [lowerBound, upperBound] : upperBound; } - getChangedValue(valueNeedChanging, value) { - const state = this.state; - const data = { - upperBound: state.upperBound, - lowerBound: state.lowerBound, - }; - data[valueNeedChanging] = value; - return this.props.range ? [data.lowerBound, data.upperBound] : data.upperBound; - } - - getIndex(value) { - const {marks, min, max, step} = this.props; - - if (isEmpty(marks)) { - return Math.floor((value - min) / step); - } - const unit = ((max - min) / (Object.keys(marks).length - 1)).toFixed(5); - return Math.round(value / unit); - } - - getBoundsFromIndex(indexes, props) { - if (props.range) { - return { - lowerBound: this.calcValueFromIndex(indexes[0], props), - upperBound: this.calcValueFromIndex(indexes[1], props), - }; - } - return { - upperBound: this.calcValueFromIndex(indexes, props), - }; - } - getPoints() { const {marks, step, min, max} = this.props; - const points = new Set(Object.keys(marks)); + const points = Object.keys(marks); if (isEmpty(marks) || step > 1) { for (let i = min; i <= max; i = i + step) { - points.add(i); + points.push(i); } } - return Array.from(points); + return points; } getSliderLength() { @@ -306,15 +264,6 @@ class Slider extends React.Component { return nextValue; } - calcValueFromIndex(index, props) { - const marksCount = Object.keys(props.marks).length; - if (marksCount > 0) { - const value = ((props.max - props.min) / (marksCount - 1)) * (index); - return parseFloat(value.toFixed(5)); - } - return ('value' in props ? props.value : props.defaultValue); - } - addDocumentEvents(type) { if (type === 'touch') { // just work for chrome iOS Safari and Android Browser @@ -402,18 +351,10 @@ Slider.propTypes = { React.PropTypes.number, React.PropTypes.arrayOf(React.PropTypes.number), ]), - defaultIndex: React.PropTypes.oneOfType([ - React.PropTypes.number, - React.PropTypes.arrayOf(React.PropTypes.number), - ]), value: React.PropTypes.oneOfType([ React.PropTypes.number, React.PropTypes.arrayOf(React.PropTypes.number), ]), - index: React.PropTypes.oneOfType([ - React.PropTypes.number, - React.PropTypes.arrayOf(React.PropTypes.number), - ]), marks: React.PropTypes.object, included: React.PropTypes.bool, className: React.PropTypes.string, @@ -436,7 +377,6 @@ Slider.defaultProps = { min: 0, max: 100, step: 1, - defaultIndex: 0, // TODO marks: {}, onBeforeChange: noop, onChange: noop, From d4e2aad482f4ee7387844cf64f7436b513e6dd90 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 18 Nov 2015 11:39:44 +0800 Subject: [PATCH 09/12] chore: update examples --- examples/marks.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/examples/marks.js b/examples/marks.js index b3a3f6d..7592dca 100644 --- a/examples/marks.js +++ b/examples/marks.js @@ -8,12 +8,10 @@ var Slider = require('rc-slider'); var style = {width: 400, margin: 50}; var marks = { - 0: 'A', - 20: 'B', - 40: 'C', - 60: 'D', - 80: 'E', - 100: 'F' + 0: '0°C', + 26: '26°C', + 37: '37°C', + 100: '100°C' }; var log = function(value) { @@ -24,29 +22,29 @@ ReactDOM.render(

Slider with marks, `included=true`

- +

Slider with marks and steps, `included=true`

- +

Slider with marks, `included=false`

- +

Slider with marks and steps, `included=false`

- +

Range with marks

- +

Range with marks and steps

- +
, document.getElementById('__react-content')); From 1546546040e914a097ddef84b468210216845701 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 18 Nov 2015 12:04:24 +0800 Subject: [PATCH 10/12] refactor: remove useless code --- src/Slider.jsx | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Slider.jsx b/src/Slider.jsx index e40b1da..5cecc7c 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -88,19 +88,17 @@ class Slider extends React.Component { const props = this.props; const isNotControlled = !('value' in props); if (isNotControlled) { - this.setState({[handle]: value}, () => { - props.onChange(this.getValue()); - }); - } else { - const state = this.state; - const data = { - upperBound: state.upperBound, - lowerBound: state.lowerBound, - }; - data[handle] = value; - const changedValue = props.range ? [data.lowerBound, data.upperBound] : data.upperBound; - props.onChange(changedValue); + this.setState({[handle]: value}); } + + const state = this.state; + const data = { + upperBound: state.upperBound, + lowerBound: state.lowerBound, + }; + data[handle] = value; + const changedValue = props.range ? [data.lowerBound, data.upperBound] : data.upperBound; + props.onChange(changedValue); } onMouseMove(e) { From 99e61001fce961fb023db44a940f9be50ae2f74f Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 18 Nov 2015 12:14:01 +0800 Subject: [PATCH 11/12] chore: update unit test --- tests/index.spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/index.spec.js b/tests/index.spec.js index 07c55ec..68acbef 100644 --- a/tests/index.spec.js +++ b/tests/index.spec.js @@ -52,17 +52,17 @@ describe('rc-slider', function () { it('should render a slider with marks correctly!', function () { var slider = ReactDOM.render( - , + , div ); var node = $(div); expect(node.find('.rc-slider').length).to.be(1); expect(node.find('.rc-slider-handle').length).to.be(1); expect(node.find('.rc-slider-track').length).to.be(1); - expect(node.find('.rc-slider-dot').length).to.be(slider.props.marks.length); + expect(node.find('.rc-slider-dot').length).to.be(Object.keys(slider.props.marks).length); expect(node.find('.rc-slider-mark').length).to.be(1); - expect(node.find('.rc-slider-mark-text').length).to.be(slider.props.marks.length); - expect(slider.getIndex(slider.state.upperBound)).to.be(3); + expect(node.find('.rc-slider-mark-text').length).to.be(Object.keys(slider.props.marks).length); + expect(slider.state.upperBound).to.be(40); }); // it('should mouseDown works!', function (done) { From 8448e80212e4e61795e2d5baf1e97475e0b553bf Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 18 Nov 2015 14:38:52 +0800 Subject: [PATCH 12/12] bump 3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ea1296..fd1ec6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-slider", - "version": "2.4.0", + "version": "3.0.0", "description": "slider ui component for react", "keywords": [ "react",