diff --git a/README.md b/README.md index 5669d94..e462d68 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,10 @@ slider ui component for react ## Usage ```js -var Rcslider = require('rc-slider'); var React = require('react'); -React.render(, container); +var ReactDOM = require('react-dom'); +var Rcslider = require('rc-slider'); +ReactDOM.render(, container); ``` ## API diff --git a/examples/simple.js b/examples/simple.js index c0d47fc..6ebfa54 100644 --- a/examples/simple.js +++ b/examples/simple.js @@ -2,8 +2,8 @@ require('rc-slider/assets/index.less'); -var Slider = require('rc-slider'); var React = require('react'); +var Slider = require('rc-slider'); function onChange(v) { console.log(v); diff --git a/package.json b/package.json index da4079a..ab705d4 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,13 @@ }, "devDependencies": { "expect.js": "0.3.x", + "jquery": "^1.11.2", "precommit-hook": "^1.0.7", "rc-server": "3.x", "rc-tools": "4.x", - "react": "^0.13.x", - "jquery": "^1.11.2" + "react": "~0.14.0", + "react-addons-test-utils": "^0.14.0", + "react-dom": "~0.14.0" }, "precommit": [ "lint" diff --git a/src/Handle.jsx b/src/Handle.jsx new file mode 100644 index 0000000..98b968b --- /dev/null +++ b/src/Handle.jsx @@ -0,0 +1,60 @@ +import React from 'react'; +import Tooltip from 'rc-tooltip'; + +export default class Handle extends React.Component { + constructor(props) { + super(props); + + this.state = { + isTooltipVisible: false, + }; + } + + render() { + const props = this.props; + const {className, prefixCls, offset, tipTransitionName, value} = props; + const {dragging, noTip} = props; + + const style = { left: offset + '%' }; + const handle = (
); + + if (noTip) { + return handle; + } + + const isTooltipVisible = dragging || this.state.isTooltipVisible; + return ({value}} + delay={0} + transitionName={tipTransitionName}> + {handle} + ); + } + + showTooltip() { + this.setState({ + isTooltipVisible: true, + }); + } + hideTooltip() { + this.setState({ + isTooltipVisible: false, + }); + } +} + +Handle.propTypes = { + className: React.PropTypes.string, + prefixCls: React.PropTypes.string, + offset: React.PropTypes.number, + tipTransitionName: React.PropTypes.string, + value: React.PropTypes.number, + dragging: React.PropTypes.bool, + noTip: React.PropTypes.bool, +}; diff --git a/src/Marks.jsx b/src/Marks.jsx new file mode 100644 index 0000000..d4afefa --- /dev/null +++ b/src/Marks.jsx @@ -0,0 +1,35 @@ +import React from 'react'; +import rcUtil from 'rc-util'; + +const Marks = ({className, marks, index, isIncluded}) => { + const marksLen = marks.length; + const unit = 100 / (marksLen - 1); + const markWidth = unit / 2 + '%'; + + const elements = []; + for (let i = 0; i < marksLen; i++) { + const isActived = (isIncluded && i <= index) || (!isIncluded && i === index); + const markClassName = rcUtil.classSet({ + [className + '-text']: true, + [className + '-text-active']: isActived, + }); + + const style = { width: markWidth }; + const offset = unit * i; + if (i === marksLen - 1) { + style.right = -unit / 4 + '%'; + } else { + style.left = (i > 0 ? offset - unit / 4 : -unit / 4) + '%'; + } + + elements.push( + {marks[i]} + ); + } + + return (
+ {elements} +
); +}; + +export default Marks; diff --git a/src/Slider.jsx b/src/Slider.jsx index cb1d452..f093049 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -1,6 +1,9 @@ import React from 'react'; -import Tooltip from 'rc-tooltip'; import rcUtil, {Dom as DomUtils} from 'rc-util'; +import Track from './Track'; +import Handle from './Handle'; +import Steps from './Steps'; +import Marks from './Marks'; function noop() { } @@ -16,12 +19,6 @@ function pauseEvent(e) { } } -function prefixClsFn(prefixCls, ...args) { - return args.map((s)=> { - return prefixCls + '-' + s; - }).join(' '); -} - function getValueFromIndex(props) { let value; const marksLen = props.marks.length; @@ -90,7 +87,6 @@ const Slider = React.createClass({ } return { dragging: false, - showTooltip: false, value: value, }; }, @@ -107,14 +103,8 @@ const Slider = React.createClass({ } }, - onMouseUp(e) { - const m = e.target; - const handleDom = React.findDOMNode(this.refs.handle); - let showToolTip = false; - if (m === handleDom) { - showToolTip = true; - } - this._end('mouse', showToolTip); + onMouseUp() { + this._end('mouse'); }, onTouchUp() { @@ -197,201 +187,70 @@ const Slider = React.createClass({ return 0; } - return slider.getDOMNode().clientWidth; + return slider.clientWidth; }, getSliderStart() { - const slider = this.refs.slider.getDOMNode(); + const slider = this.refs.slider; const rect = slider.getBoundingClientRect(); return rect.left; }, - renderSteps() { - const props = this.props; - const marksLen = props.marks.length; - const withDots = props.withDots; - - if (marksLen || withDots) { - const stepNum = marksLen ? marksLen : Math.floor((props.max - props.min) / props.step) + 1; - const unit = 100 / (stepNum - 1); - - const prefixCls = props.prefixCls; - const stepClassName = prefixClsFn(prefixCls, 'step'); - - const elements = []; - for (let i = 0; i < stepNum; i++) { - const offset = unit * i + '%'; - const style = { - left: offset, - }; - let className = prefixClsFn(prefixCls, 'dot'); - if (props.isIncluded) { - if (i <= this.getIndex()) { - className = prefixClsFn(prefixCls, 'dot', 'dot-active'); - } - } else { - className = (i === this.getIndex()) ? prefixClsFn(prefixCls, 'dot', 'dot-active') : className; - } - - elements[i] = ( - - ); - } - - return ( -
- {elements} -
- ); - } - - return null; - }, - - renderMark(i) { - const marks = this.props.marks; - const marksLen = marks.length; - const unit = 100 / (marksLen - 1); - const offset = unit * i; - - const style = { - width: unit / 2 + '%', - }; - - if (i === marksLen - 1) { - style.right = -unit / 4 + '%'; - } else { - style.left = i > 0 ? offset - unit / 4 + '%' : -unit / 4 + '%'; - } - - const prefixCls = this.props.prefixCls; - let className = prefixClsFn(prefixCls, 'mark-text'); - - if (this.props.isIncluded) { - if (i <= this.getIndex()) { - className = prefixClsFn(prefixCls, 'mark-text', 'mark-text-active'); - } - } else { - className = (i === this.getIndex()) ? prefixClsFn(prefixCls, 'mark-text', 'mark-text-active') : className; - } - - return ( - {this.props.marks[i]} - ); - }, - - renderMarks() { - const marks = this.props.marks; - const marksLen = marks.length; - const elements = []; - for (let i = 0; i < marksLen; i++) { - elements[i] = this.renderMark(i); - } - - const prefixCls = this.props.prefixCls; - const className = prefixClsFn(prefixCls, 'mark'); - - return ( -
- {elements} -
- ); - }, - - renderHandler(offset) { - const onStyle = { - left: offset, - }; - - const prefixCls = this.props.prefixCls; - const className = prefixClsFn(prefixCls, 'handle'); - - let events = {}; - - let tooltipVisible; - - if (this.state.dragging) { - tooltipVisible = true; - } else { - events = { - onClick: this.showTooltip.bind(this, true), - onMouseEnter: this.showTooltip.bind(this, true), - onMouseLeave: this.showTooltip.bind(this, false), - }; - tooltipVisible = this.state.showTooltip; - } - - const handle = (
); - - if (this.props.marks.length > 0) { - return handle; - } - return ( - {this.state.value}} - delay={0} - transitionName={this.props.tipTransitionName} - prefixCls={prefixClsFn(prefixCls, 'tooltip')}> - {handle} - - ); - }, - - renderTrack(offset) { - const style = { - width: offset, - }; - - const prefixCls = this.props.prefixCls; - const trackClassName = prefixClsFn(prefixCls, 'track'); - - return ( -
- ); - }, - render() { const state = this.state; + const {value, dragging} = state; const props = this.props; - const value = state.value; + const {className, prefixCls, disabled, isIncluded, withDots} = props; + const {marks, step, max, min, tipTransitionName, children} = props; + const marksLen = marks.length; + + const sliderClassName = rcUtil.classSet({ + [prefixCls]: true, + [prefixCls + '-disabled']: disabled, + [className]: !!className, + }); + const offset = this._calcOffset(value); - const track = this.props.isIncluded ? this.renderTrack(offset) : null; - const ons = this.renderHandler(offset); - const steps = (props.step > 1 || props.marks.length > 0) ? this.renderSteps() : null; - const sliderMarks = (props.marks.length > 0) ? this.renderMarks() : null; - const prefixCls = props.prefixCls; - const disabled = props.disabled; - const sliderClassName = { - [prefixCls]: 1, - [props.className]: !!props.className, - [`${prefixCls}-disabled`]: disabled, - }; + + let track = null; + if (isIncluded) { + const trackClassName = prefixCls + '-track'; + track = ; + } + + const handleClassName = prefixCls + '-handle'; + + let steps = null; + if (marksLen > 0 || (step > 1 && withDots)) { + 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 = (); + } return ( -
{track} - {ons} + 0} /> {steps} - {sliderMarks} - {this.props.children} + {mark} + {children}
); }, - showTooltip(show) { - this.setState({ - showTooltip: show, - }); - }, - _trimAlignValue(v, propsArg) { let val = v; const props = propsArg || this.props; @@ -416,7 +275,7 @@ const Slider = React.createClass({ _calcOffset(value) { const ratio = (value - this.props.min) / (this.props.max - this.props.min); - return ratio * 100 + '%'; + return ratio * 100; }, _calcValue(offset) { @@ -485,12 +344,11 @@ const Slider = React.createClass({ }); }, - _end(type, showToolTip) { + _end(type) { this._removeEventons(type); this._triggerEvents('onAfterChange'); this.setState({ dragging: false, - showTooltip: !!showToolTip, }); }, }); diff --git a/src/Steps.jsx b/src/Steps.jsx new file mode 100644 index 0000000..dc49d2d --- /dev/null +++ b/src/Steps.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import rcUtil from 'rc-util'; + +const Steps = ({className, stepNum, isIncluded, index}) => { + 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 style = { left: offset }; + + const isActived = (isIncluded && i <= index) || (!isIncluded && i === index); + const stepClassName = rcUtil.classSet({ + [dotClassName]: true, + [dotClassName + '-active']: isActived, + }); + + elements.push(); + } + + return (
+ {elements} +
); +}; + +export default Steps; diff --git a/src/Track.jsx b/src/Track.jsx new file mode 100644 index 0000000..fb1cdf2 --- /dev/null +++ b/src/Track.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const Track = ({className, offset, length}) => { + const style = { + left: offset + '%', + width: length + '%', + }; + return
; +}; + +export default Track; diff --git a/tests/index.spec.js b/tests/index.spec.js index 1ea2b4a..8c18335 100644 --- a/tests/index.spec.js +++ b/tests/index.spec.js @@ -1,8 +1,9 @@ var expect = require('expect.js'); var Slider = require('../index.js'); -var React = require('react/addons'); -var TestUtils = React.addons.TestUtils; +var React = require('react'); +var ReactDOM = require('react-dom'); +var TestUtils = require('react-addons-test-utils'); var Simulate = TestUtils.Simulate; var $ = require('jquery'); require('../assets/index.less'); @@ -17,7 +18,7 @@ describe('rc-slider', function () { }); it('should render a simple slider with value correctly!', function () { - var slider = React.render( + var slider = ReactDOM.render( , div ); @@ -31,7 +32,7 @@ describe('rc-slider', function () { }); it('should render a slider with correct numbers of step!', function () { - var slider = React.render( + var slider = ReactDOM.render( , div ); @@ -50,7 +51,7 @@ describe('rc-slider', function () { }); it('should render a slider with marks correctly!', function () { - var slider = React.render( + var slider = ReactDOM.render( , div ); @@ -65,7 +66,7 @@ describe('rc-slider', function () { }); // it('should mouseDown works!', function (done) { - // var slider = React.render( + // var slider = ReactDOM.render( // , // div // );