Compare commits

...
186 Commits
Author SHA1 Message Date
Benjy Cui a4cf02cf75 bump 3.8.1 2016-07-25 14:09:49 +08:00
Benjy Cui d05761f396 fix: should pass prefixCls to Tooltip correctly, close: #123 2016-07-25 14:09:05 +08:00
Benjy Cui 926d5aeb91 bump 3.8.0 2016-07-20 09:40:04 +08:00
miskreant b2ae1bc0fc feat: identify upper/lower range handles (#118)
Extend the handle classNames, and provide props so that
upper/lower handles are easily distinguishable in CSS & React.

* Use classNames() instead of string concatenation
2016-07-20 09:34:49 +08:00
Benjy Cui 80d4ee4794 bump 3.7.4 2016-07-11 09:55:12 +08:00
Benjy Cui e2504d99fe fix: should calc cloest point correctly, close: #116 2016-07-11 09:53:38 +08:00
Benjy Cui d4ae5a5298 deps: update 2016-07-11 09:48:44 +08:00
Benjy Cui ce755ecb4b bump 3.7.3 to publish website 2016-06-29 16:23:00 +08:00
Benjy Cui 9bc56e993d chore: update demo 2016-06-29 16:22:01 +08:00
Benjy Cui 1e34b94d86 bump 3.7.2 2016-06-22 09:25:13 +08:00
Aaron Lampros a678437462 fix: import dom util directly, close: #108. (#110) 2016-06-22 09:20:57 +08:00
Benjy Cui a4c06c2509 bump 3.7.1 2016-06-12 09:17:48 +08:00
Jordan Stephens ff9e68cd36 ignore right button on mousedown (#107)
fix: should ignore right button on mousedown
2016-06-12 09:16:24 +08:00
Benjy Cui 1adc68504a bump 3.7.0 2016-05-31 14:27:23 +08:00
Benjy Cui 01174f3cb0 Merge pull request #102 from elboman/custom-handle
Allow to pass custom handle components
2016-05-31 14:24:13 +08:00
Marco Botto 1ae39dd995 added custom handle API to docs 2016-05-30 12:16:53 +02:00
Marco Botto 0b4b546e03 changed API to from to 2016-05-30 12:08:52 +02:00
Marco Botto bc3883304d allow to pass custom handle components 2016-05-16 17:38:56 +02:00
Benjy Cui e2f9c508f3 Merge pull request #101 from nathandurand/master
Add license file
2016-05-06 12:05:19 +08:00
Nathan Durand ef5d136b14 Update license file 2016-05-06 06:53:38 +03:00
Nathan Durand f1637da046 Add license file 2016-05-05 16:41:49 +03:00
Benjy Cui ddcf32b094 bump 3.6.2 2016-04-28 09:35:21 +08:00
Boris Serdiuk 025a9e7ea6 Merge pull request #99 from react-component/fix-bugs
Fix #96 and #97
2016-04-27 15:08:48 +04:00
Benjy Cui e4396ae4bd refactor: simplify code 2016-04-27 17:48:17 +08:00
Benjy Cui 37b7f508da fix: use the latest step, close: #96 2016-04-27 14:29:45 +08:00
Benjy Cui ecbb253986 fix: set recent default value correctly, close: #97 2016-04-27 14:17:32 +08:00
Benjy Cui f4a82e3fd1 bump 3.6.1 2016-04-27 12:09:04 +08:00
Benjy Cui 0b1a421a71 chore: add warning for invalid usage, close: #91 2016-04-27 12:07:20 +08:00
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
Benjy Cui f850dab6c4 bump 3.3.1 2015-12-21 09:59:02 +08:00
Benjy Cui f3c1d4bd3d fix: the key of dots should be unique #64 2015-12-21 09:57:30 +08:00
Benjy Cui 4d795b01cc chore: update unit test 2015-12-18 17:30:34 +08:00
Benjy Cui 959007ed30 bump 3.3.0 2015-12-18 10:11:50 +08:00
Benjy Cui 079469b765 refactor: the default value of tipFormatter 2015-12-18 10:10:52 +08:00
Benjy Cui ddb2bf670b Merge pull request #61 from frank-weindel/hide-the-tip
If tipFormatter is null, don't show the tip
2015-12-18 09:18:41 +08:00
Frank Weindel 4c57f3ecca Refactor isNoTip expression 2015-12-17 10:49:29 -05:00
Frank Weindel 24f3b755b2 Add example for hiding the tooltip 2015-12-17 10:48:54 -05:00
Frank Weindel 867e252631 Add documentation on how to hide the tip 2015-12-16 16:42:13 -05:00
Frank Weindel 39de81dfa9 If tipFormatter is null, don't show the tip 2015-12-16 16:38:15 -05:00
Benjy Cui 978d877323 bump 3.2.0 2015-12-16 09:30:46 +08:00
Boris Serdiuk a1ae3a8374 Merge pull request #60 from react-component/fix-rerender
fix: crash when rerender #57
2015-12-15 13:53:31 +03:00
Benjy Cui 15f568283c fix: crash when rerender #57 2015-12-15 11:32:41 +08:00
Benjy Cui e85d325542 Merge pull request #59 from react-component/feat-allowCross
feat: add `allowCross` property #56
2015-12-15 09:06:09 +08:00
Benjy Cui 395fa6c201 feat: add allowCross property #56 2015-12-12 08:45:28 +08:00
Benjy Cui 0329df0c5a bump 3.1.4 2015-12-07 14:40:57 +08:00
Boris Serdiuk 7fa8dfdd03 Merge pull request #55 from react-component/fix-align
fix: value should be aligned if `min` `max` changed
2015-12-07 09:23:51 +03:00
Benjy Cui 555f5a0660 fix: value should be aligned if min max changed 2015-12-06 09:21:17 +08:00
Benjy Cui c232d62c86 bump 3.1.3 2015-12-02 11:41:32 +08:00
Benjy Cui 1262a78638 deps: replace rcUtil.classSet with classNames 2015-12-02 11:30:34 +08:00
Benjy Cui e7d98e0ee4 chore: update unit test 2015-12-01 17:57:05 +08:00
Benjy Cui 5f9a65137a style: update code style to please lint 2015-12-01 16:26:09 +08:00
Benjy Cui 64296d4957 docs: add docs for onChange onAfterChange 2015-11-24 11:44:44 +08:00
Benjy Cui ee0dd09a4f fix: support decimal step 2015-11-23 16:00:21 +08:00
Benjy Cui a5de9b0dbc Merge pull request #48 from react-component/improve-performance
refactor: improve performance
2015-11-23 15:37:13 +08:00
Benjy Cui 37d32ae71c Merge pull request #49 from just-boris/master
style: reduce gaps between marks
2015-11-23 09:57:24 +08:00
just-boris f339db494b reduce gaps between marks 2015-11-23 00:17:29 +03:00
Benjy Cui c097b8f761 bump 3.1.1 2015-11-22 10:31:08 +08:00
Benjy Cui 10244cf01b refactor: improve the performance of Slider 2015-11-22 10:29:41 +08:00
Benjy Cui e8a86b91e2 Merge pull request #45 from react-component/feat-mark-as-step
Feat mark as step
2015-11-19 11:55:10 +08:00
Benjy Cui 05dafc0f10 bump 3.1.0 2015-11-19 11:43:25 +08:00
Benjy Cui 5dbde43da8 docs: update README.md 2015-11-19 11:43:07 +08:00
Benjy Cui 0a23a67f31 feat: allow user set step to null to make marks as steps 2015-11-19 11:42:04 +08:00
Benjy Cui 6f39212df5 Merge pull request #43 from react-component/fix-marks
fix: the key of marks could be negative
2015-11-18 18:37:46 +08:00
Benjy Cui a7c2319949 fix: the key of marks could be negative 2015-11-18 18:27:37 +08:00
Benjy Cui ee71955e14 Merge pull request #42 from react-component/3.0.0-beta
bump 3.0.0
2015-11-18 14:48:52 +08:00
Benjy Cui 8448e80212 bump 3.0.0 2015-11-18 14:38:52 +08:00
Benjy Cui 99e61001fc chore: update unit test 2015-11-18 14:32:56 +08:00
Benjy Cui 1546546040 refactor: remove useless code 2015-11-18 14:32:56 +08:00
Benjy Cui d4e2aad482 chore: update examples 2015-11-18 14:32:56 +08:00
Benjy Cui 7680347dfe feat: remove index/defaultIndex 2015-11-18 14:32:56 +08:00
Benjy Cui e2530ad2bf feat: Slider with marks should pass value(not index) to event handles 2015-11-18 14:32:56 +08:00
Benjy Cui 0566e7f098 fix: should trigger event after the value is changed 2015-11-18 14:32:56 +08:00
Benjy Cui 1e430ba694 fix: if there is no marks, step=1 should work 2015-11-18 14:32:56 +08:00
Benjy Cui f29894e690 chore: update tooltip className 2015-11-18 14:32:56 +08:00
Benjy Cui fd6c393f66 feat: Steps should not depend on marks 2015-11-18 14:32:56 +08:00
Benjy Cui e3ba1eee5b feat: marks should be an object 2015-11-18 14:32:56 +08:00
Benjy Cui 8dc66dd2a4 chore: remove isIncluded 2015-11-18 14:32:56 +08:00
afc163 b9501ef414 Merge pull request #40 from react-component/fix-controlled-slider
Fix controlled slider
2015-11-18 14:20:27 +08:00
Benjy Cui a329b00347 chore: update examples 2015-11-17 16:42:19 +08:00
Benjy Cui ccf3803d20 chore: remove initMochaPhantomJS 2015-11-17 11:41:55 +08:00
Benjy Cui b585f2fa1a bump 2.4.0 2015-11-17 10:35:02 +08:00
Benjy Cui 6f0e618a30 fix: Slider should be a controlled component 2015-11-17 10:31:10 +08:00
Benjy Cui ae4be7392d feat: unify onBeforeChange onChange onAfterChange 2015-11-17 09:54:09 +08:00
Benjy Cui d5891c79df chore: update examples 2015-11-17 09:48:35 +08:00
simaQ 87442eac35 Merge pull request #38 from react-component/chore
Chore
2015-11-16 18:24:47 +08:00
Benjy Cui 5e559a1555 chore: update test case 2015-11-16 16:35:17 +08:00
Benjy Cui 315849a0f3 refactor: rename variables 2015-11-16 16:33:45 +08:00
Benjy Cui 5f91e9a648 chore: update examples 2015-11-16 16:33:45 +08:00
yiminghe 610531be12 2.3.2 2015-11-16 14:05:16 +08:00
Benjy Cui a06b43dcd7 bump 2.3.1 2015-11-16 10:34:13 +08:00
Benjy Cui 3e11978bfc Merge pull request #37 from just-boris/master
feat: make range and marks props to work together
2015-11-16 10:02:06 +08:00
just-boris 48dab67950 make range and marks props to work together 2015-11-15 03:42:36 +03:00
simaQ ab494c9ca8 update. Add tipFormat property. See pull #33. 2015-11-14 12:52:59 +08:00
simaQ 68bb3bcadb update demo. 2015-11-14 12:46:13 +08:00
simaQ 0f97361257 update tooltip style. 2015-11-14 12:45:50 +08:00
simaQ 599771dc1a Merge branch 'thorbenziemek-master' 2015-11-14 12:38:39 +08:00
simaQ a109298acd Merge branch 'master' of https://github.com/thorbenziemek/slider into thorbenziemek-master 2015-11-14 12:37:27 +08:00
Benjy Cui 6db366a0c5 bump 2.2.0 2015-11-14 10:02:14 +08:00
Benjy Cui 2a5f28c60e chore: remove deprecated withDots 2015-11-14 10:00:28 +08:00
Benjy Cui c4f3f5d20d chore: add example for onAfterChange 2015-11-14 09:56:54 +08:00
Benjy Cui 5e84fa0e1e fix: setState doesn't promise to run synchronously 2015-11-14 09:52:38 +08:00
Benjy Cui 8873210873 Merge pull request #35 from just-boris/master
feat: provide value for `onAfterChange` trigger
2015-11-14 09:38:10 +08:00
just-boris b96e4757ea provide slider value onAfterChange trigger 2015-11-14 02:37:37 +03:00
yiminghe df97e41d48 update deps 2015-11-10 23:25:43 +08:00
Thorben Ziemek 3519ba24c0 react-component/slider#32 implemented tipFormatter prop 2015-11-05 12:43:05 +01:00
Benjy Cui 9d62c64784 bump 2.0.1 2015-11-01 11:24:57 +08:00
Benjy Cui 305844e73c bump 2.0.0 2015-11-01 10:54:47 +08:00
Benjy Cui 99b583aee9 Merge pull request #30 from benjycui/upgrade-api
Upgrade api
2015-11-01 10:52:04 +08:00
Benjy Cui 256a7b3eb9 deps: upgrade deps 2015-10-31 12:01:35 +08:00
Benjy Cui 217701543b fix: to be compatible with old version 2015-10-31 11:45:29 +08:00
Benjy Cui a3bd4db2f8 fix: IE8/9 does not support Object.assign 2015-10-31 11:34:47 +08:00
Benjy Cui 53df129611 chore: update examples 2015-10-31 10:43:23 +08:00
Benjy Cui afc3b57e23 fix: typo 2015-10-30 18:02:33 +08:00
Benjy Cui 9dccdb6c90 fix: lowerBound should be smaller than upperBound 2015-10-30 17:53:24 +08:00
Benjy Cui e909890b7a docs: update README.md 2015-10-30 17:27:18 +08:00
Benjy Cui 0b0271053a feat: rename defaultValues values 2015-10-30 17:21:28 +08:00
Benjy Cui 7991918a96 feat: rename APIs 2015-10-30 16:52:25 +08:00
SimaQ 724245eb2a update version. 2015-10-30 12:14:09 +08:00
SimaQ 4b854b04e5 doc: update demo. 2015-10-30 12:13:12 +08:00
simaQ 66eee7a2ef Merge pull request #28 from benjycui/docs-range
docs: add docs for feature range
2015-10-28 23:27:50 +08:00
Benjy Cui eb18232523 docs: add docs for feature range 2015-10-28 11:31:24 +08:00
simaQ 1326e1e565 Merge pull request #25 from benjycui/feature-range
Feature range
2015-10-27 18:46:36 +08:00
Benjy Cui 3c86db909c feat: add support for range 2015-10-27 10:15:01 +08:00
Benjy Cui 040e0fef41 refactor: extract helper function from Slider 2015-10-20 19:31:05 +08:00
Benjy Cui ffbc799455 refactor: remove prefixCls for Handle 2015-10-20 19:31:05 +08:00
Benjy Cui 33e2ee6e9a refactor Slider with ES6 2015-10-20 19:31:05 +08:00
SimaQ 17d3f8ae54 update version. 2015-10-20 19:16:24 +08:00
SimaQ a1dd641e70 update demo. 2015-10-20 19:08:08 +08:00
simaQ 5a7f9df3d5 Merge pull request #22 from benjycui/master
refactor: extract sub components from Slider
2015-10-20 18:59:50 +08:00
Benjy Cui 2033c6ea32 refactor: extract sub components from Slider 2015-10-20 18:53:41 +08:00
yiminghe 4b4eb52147 update readme 2015-10-15 15:03:13 +08:00
yiminghe d2e678b1e3 update example 2015-10-15 15:01:51 +08:00
Benjy Cui ebf27cc9ba Merge pull request #24 from react-component/step-marks-fix
Step marks fix
2015-10-15 11:26:49 +08:00
SimaQ 314fc59d15 updata version. 2015-10-15 11:01:21 +08:00
SimaQ 7bd951072f fix: fix disabled style. 2015-10-15 11:01:21 +08:00
SimaQ d6779510f9 test: update test case. 2015-10-15 11:01:15 +08:00
SimaQ 2588a2b919 fix: fix#23. 2015-10-15 10:44:58 +08:00
yiminghe dd0a63dee3 change anim name 2015-10-14 23:08:51 +08:00
yiminghe 8b414d510b update travis 2015-10-14 23:06:24 +08:00
yiminghe 2c41239d90 fix style. fixes #19 2015-10-14 23:03:46 +08:00
simaQ 19f1183634 update version 2015-08-29 10:58:26 +08:00
simaQ 200d0810ce Merge pull request #21 from danioso/master
Sending new value to _start while dragging
2015-08-29 10:57:19 +08:00
Daniel Osorio e7007fbe8e Sending new value to _start while dragging 2015-08-27 19:23:57 -05:00
yiminghe 8f490c80be up 2015-08-25 21:45:26 +08:00
simaQ a68a839515 update README.md 2015-08-24 14:07:38 +08:00
Emma e615ffb7b0 Merge pull request #20 from jljsj33/addAnimation
add slider animation
2015-08-24 13:59:45 +08:00
jljsj c643ae235e tipTransitionName is tag 2015-08-24 13:21:08 +08:00
jljsj 93c92f5f37 改名字 2015-08-24 13:12:46 +08:00
jljsj 35ba80d884 add slider animation 2015-08-24 11:56:37 +08:00
simaQ c28f14272d update version 2015-08-19 17:37:45 +08:00
simaQ b70a4e8c94 fix: fix ie8 can not support e.pageX bug. 2015-08-19 17:18:36 +08:00
simaQ 41f5ddb9bd fix: Slider 点击圆点后气泡提示会消失以及分段式滑块无法拖动问题。 2015-08-19 16:51:28 +08:00
yiminghe 38edc4db93 update travis 2015-08-10 19:27:48 +08:00
yiminghe 93ddaef0c3 update demo 2015-08-07 12:50:38 +08:00
yiminghe dbc64888bc update docs 2015-08-07 12:47:07 +08:00
yiminghe 2112385ccc remove npmignore 2015-08-07 12:44:49 +08:00
yiminghe 11ef100472 upgrade rc-tooltip 2015-08-07 12:44:12 +08:00
yiminghe 6965bbcefe support value/index 2015-07-21 00:03:08 +08:00
yiminghe cf806616b1 Merge pull request #17 from react-component/defaultValUE
change value to defaultValue
2015-07-20 23:51:53 +08:00
yiminghe 9ebe2de0cb change value to defaultValue 2015-07-20 23:49:55 +08:00
simaQ ccdaa08a9a bug fix 2015-07-15 16:21:40 +08:00
simaQ 58b18484fe update version 2015-07-15 15:19:19 +08:00
simaQ 3a61ef37c6 bugfix: active step fix 2015-07-15 15:19:00 +08:00
Emma fc76a93949 Merge pull request #14 from benjycui/master
修复 Slider 滑块越界与 step 偏移的 Bug。
2015-07-15 14:51:17 +08:00
Benjy Cui 2cd34c0e40 Merge branch 'master' of github.com:react-component/slider 2015-07-15 14:21:11 +08:00
Benjy Cui 0dc20afce7 修复 Slider 滑块越界与 step 偏移的 Bug。 2015-07-15 10:48:35 +08:00
Benjy Cui b69a4af14f Merge pull request #13 from react-component/revert-10-master
Revert "修复 Slider 初始 `upperBound` 与 `sliderLength` 错误的 Bug。"
2015-07-15 09:19:45 +08:00
Benjy Cui 84e999697f Revert "修复 Slider 初始 upperBoundsliderLength 错误的 Bug。" 2015-07-15 17:11:25 +08:00
simaQ 8290cb0337 update online example url 2015-07-14 21:34:17 +08:00
simaQ be15e1c8db update version 2015-07-14 21:16:26 +08:00
30 changed files with 1632 additions and 611 deletions
-29
View File
@@ -1,29 +0,0 @@
build/
*.cfg
nohup.out
*.iml
.idea/
.ipr
.iws
*~
~*
*.diff
*.log
*.patch
*.bak
.DS_Store
Thumbs.db
.project
.*proj
.svn/
*.swp
out/
.build
node_modules
.cache
examples
tests
src
/index.js
.*
assets/**/*.less
+8 -2
View File
@@ -1,11 +1,13 @@
language: node_js
sudo: false
notifications:
email:
- yiminghe@gmail.com
node_js:
- 0.12
- 4.0.0
before_install:
- |
@@ -14,7 +16,6 @@ before_install:
echo "Only docs were updated, stopping build process."
exit
fi
npm install mocha-phantomjs -g
phantomjs --version
script:
@@ -34,3 +35,8 @@ env:
global:
- secure: S1VwbaPzLnSH/IUT/wlJulxAX5VHRIDmSt53h/ycHcZsszUpWcLCJRQAe0fTVB2dAx5MdBbSZ+o+tr3tRwVB5TRAYm0oTCsYAkOZaWOB28RuUQtdGt3wf9xxTG1UiPiaLLUW3waX9zAaf3yqKBcJGf1op0RD8dksxbCFw/7xVbU=
- secure: EBEDg8k///IlEsnx0AE8X3mbFl0QE5+xGKbG4AxXlGZda12uTIPUSMKJzdZQ2hVbZXduTzf1cQl9rcu9nGoSnkL/DWnIax9cvHi+1orx5+YPlxPHNWAwWByTnHosBn2MJhfy1s5paJfHC9cUzmmEL6x4fYthWxjsPUo+irEZH6E=
matrix:
allow_failures:
- env: "TEST_TYPE=saucelabs"
+5
View File
@@ -1,6 +1,11 @@
# 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
+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+84 -30
View File
@@ -4,7 +4,6 @@
slider ui component for react
[![NPM version][npm-image]][npm-url]
[![SPM version](http://spmjs.io/badge/rc-slider)](http://spmjs.io/package/rc-slider)
[![build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![gemnasium deps][gemnasium-image]][gemnasium-url]
@@ -51,9 +50,10 @@ slider ui component for react
## Usage
```js
var Rcslider = require('rc-slider');
var React = require('react');
React.render(<Rcslider />, container);
var ReactDOM = require('react-dom');
var Rcslider = require('rc-slider');
ReactDOM.render(<Rcslider />, container);
```
## API
@@ -74,7 +74,7 @@ React.render(<Rcslider />, container);
<td>className</td>
<td>String</td>
<td>rc-slider</td>
<td>additional css class of root dom node</td>
<td>Additional css class for the root dom node</td>
</tr>
<tr>
<td>min</td>
@@ -88,41 +88,95 @@ React.render(<Rcslider />, container);
<td>100</td>
<td>The maximum value of the slider</td>
</tr>
<tr>
<td>step</td>
<td>number</td>
<td>1</td>
<td>Value to be added or subtracted on each step the slider makes. Must be greater than zero. max - min should be evenly divisible by the step value.</td>
</tr>
<tr>
<td>value</td>
<td>number</td>
<td>0</td>
<td>Determines the initial positions of the handles.</td>
</tr>
<tr>
<td>marks</td>
<td>array</td>
<td>[]</td>
<td>mark every step for the slider, it will ignore the `step` parameter if it has been defined</td>
<td>object{number: string} or object{number: object{ style, label }}</td>
<td>{}</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>
<td>isIncluded</td>
<td>step</td>
<td>number or `null`</td>
<td>1</td>
<td>Value to be added or subtracted on each step the slider makes. Must be greater than zero. max - min should be evenly divisible by the step value. When `marks` is not an empty object, `step` can be set to `null`, to make marks as steps.</td>
</tr>
<tr>
<td>range</td>
<td>boolean</td>
<td>false</td>
<td>Determines the type of slider. If range is `true`, two handles will be rendered in order to select a range.</td>
</tr>
<tr>
<td>allowCross</td>
<td>boolean</td>
<td>true</td>
<td>if the value is true, it means a continuous value interval, otherwise, it is a independent value.</td>
<td>When `range` is `true`, `allowCross` could be set as `true` to allow those two handles cross.</td>
</tr>
<tr>
<td>index</td>
<td>number</td>
<td>0</td>
<td>For step or marks slider, determine the initial positions of the handles.</td>
<td>vertical</td>
<td>boolean</td>
<td>false</td>
<td>If vertical is `true`, the slider will be vertical.</td>
</tr>
<tr>
<td>defaultValue</td>
<td>number or [number, number]</td>
<td>0 or [0, 0]</td>
<td>Set initial positions of handles. If range is `false`, the type of `defaultValue` should be `number`. Otherwise, `[number, number]`</td>
</tr>
<tr>
<td>value</td>
<td>number or [number, number]</td>
<td></td>
<td>Set current positions of handles. If range is `false`, the type of `defaultValue` should be `number`. Otherwise, `[number, number]`</td>
</tr>
<tr>
<td>handle</td>
<td>Component</td>
<td></td>
<td>Provide a custom Handle to use in the slider by passing a component. This component will have a `value` and `offset` props used to define custom styling/content.</td>
</tr>
<tr>
<td>included</td>
<td>boolean</td>
<td>true</td>
<td>If the value is `true`, it means a continuous value interval, otherwise, it is a independent value.</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>false</td>
<td>If true the handles can't be moved.</td>
<td>If `true`, handles can't be moved.</td>
</tr>
<tr>
<td>tipTransitionName</td>
<td>string</td>
<td>''</td>
<td>Set the animation for tooltip if it shows.</td>
</tr>
<tr>
<td>tipFormatter</td>
<td>function or `null`</td>
<td></td>
<td>Format the value of the tooltip if it shows. If `null` the tooltip will always be hidden.</td>
</tr>
<tr>
<td>dots</td>
<td>bool</td>
<td>false</td>
<td>When the `step` value is greater than 1, you can set the `dots` to `true` if you want to render the slider with dots.</td>
</tr>
<tr>
<td>onChange</td>
<td>function</td>
<td>NOOP</td>
<td>`onChange` will be triggered while the value of Slider changing.</td>
</tr>
<tr>
<td>onAfterChange</td>
<td>function</td>
<td>NOOP</td>
<td>`onAfterChange` will be triggered when `ontouchend` or `onmouseup` is triggered.</td>
</tr>
</tbody>
</table>
@@ -136,17 +190,17 @@ npm start
## Example
http://localhost:8000/examples/
http://localhost:8005/examples/
online example: http://react-component.github.io/slider/build/examples/
online example: http://react-component.github.io/slider/
## Test Case
http://localhost:8000/tests/runner.html?coverage
http://localhost:8005/tests/runner.html?coverage
## Coverage
http://localhost:8000/node_modules/rc-server/node_modules/node-jscover/lib/front-end/jscoverage.html?w=http://localhost:8088/tests/runner.html?coverage
http://localhost:8005/node_modules/rc-server/node_modules/node-jscover/lib/front-end/jscoverage.html?w=http://localhost:8088/tests/runner.html?coverage
## License
+151 -47
View File
@@ -8,15 +8,17 @@
@tooltip-arrow-width: 4px;
@tooltip-distance: @tooltip-arrow-width+4;
@tooltip-arrow-color: @tooltip-bg;
@ease-out-quint : cubic-bezier(0.23, 1, 0.32, 1);
@ease-in-quint : cubic-bezier(0.755, 0.05, 0.855, 0.06);
* {
.borderBox() {
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); // remove tap highlight color for mobile safari
}
*:before,
*:after {
box-sizing: border-box;
* {
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); // remove tap highlight color for mobile safari
}
}
.@{prefixClass} {
@@ -26,6 +28,8 @@
border-radius: @border-radius-base;
background-color: #e9e9e9;
.borderBox();
&-track {
position: absolute;
left: 0;
@@ -90,7 +94,7 @@
&-dot {
position: absolute;
top: -2px;
bottom: -2px;
margin-left: -4px;
width: 8px;
height: 8px;
@@ -117,61 +121,161 @@
background-color: @disabledColor;
}
.@{prefixClass}-handle {
.@{prefixClass}-handle, .@{prefixClass}-dot {
border-color: @disabledColor;
background-color: #fff;
cursor: not-allowed;
}
.@{prefixClass}-mark-text, .dot {
.@{prefixClass}-mark-text, .@{prefixClass}-dot {
cursor: not-allowed!important;
}
}
}
// slider tooltip style
&-tooltip {
position: absolute;
left: -9999px;
top: -9999px;
z-index: 4;
visibility: visible;
&-hidden {
display: none;
.@{prefixClass}-vertical {
width: 4px;
height: 100%;
.@{prefixClass} {
&-track {
bottom: 0;
width: 4px;
}
&-placement-top {
padding: @tooltip-arrow-width 0 @tooltip-distance 0;
}
&-inner {
padding: 6px 0;
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 {
&-handle {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
margin-left: -5px;
margin-bottom: -7px;
}
&-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;
&-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() {
animation-duration: .3s;
animation-fill-mode: both;
display: block !important;
}
.make-motion(@className, @keyframeName) {
.@{className}-enter, .@{className}-appear {
.motion-common();
animation-play-state: paused;
}
.@{className}-leave {
.motion-common();
animation-play-state: paused;
}
.@{className}-enter.@{className}-enter-active, .@{className}-appear.@{className}-appear-active {
animation-name: ~"@{keyframeName}In";
animation-play-state: running;
}
.@{className}-leave.@{className}-leave-active {
animation-name: ~"@{keyframeName}Out";
animation-play-state: running;
}
}
.zoom-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName);
.@{className}-enter, .@{className}-appear {
transform: scale(0, 0); // need this by yiminghe
animation-timing-function: @ease-out-quint;
}
.@{className}-leave {
animation-timing-function: @ease-in-quint;
}
}
.zoom-motion(rc-slider-tooltip-zoom-down, rcSliderTooltipZoomDown);
@keyframes rcSliderTooltipZoomDownIn {
0% {
opacity: 0;
transform-origin: 50% 100%;
transform: scale(0, 0);
}
100% {
transform-origin: 50% 100%;
transform: scale(1, 1);
}
}
@keyframes rcSliderTooltipZoomDownOut {
0% {
transform-origin: 50% 100%;
transform: scale(1, 1);
}
100% {
opacity: 0;
transform-origin: 50% 100%;
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;
}
}
+44
View File
@@ -0,0 +1,44 @@
require('rc-slider/assets/index.less');
const React = require('react');
const ReactDOM = require('react-dom');
const Slider = require('rc-slider');
const wrapperStyle = {width: 400, margin: 50};
const handleStyle = {
position: 'absolute',
transform: 'translate(-50%, -50%)',
cursor: 'pointer',
padding: '2px',
border: '2px solid #abe2fb',
borderRadius: '3px',
background: '#fff',
fontSize: '14px',
textAlign: 'center',
zIndex: 3,
};
const CustomHandle = props => {
const style = Object.assign({left: props.offset + '%'}, handleStyle);
return (
<div style={style}>val: {props.value}</div>
);
};
CustomHandle.propTypes = {
value: React.PropTypes.any,
offset: React.PropTypes.number,
};
ReactDOM.render(
<div>
<div style={wrapperStyle}>
<p>Default slider</p>
<Slider min={0} max={20} defaultValue={3} />
</div>
<div style={wrapperStyle}>
<p>Slider with custom handle</p>
<Slider min={0} max={20} defaultValue={3} handle={<CustomHandle />} />
</div>
</div>
, document.getElementById('__react-content'));
+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 = {width: 400, margin: 50};
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>
<div style={style}>
<p>Slider with marks, `step=null`</p>
<Slider min={-10} marks={marks} step={null} onChange={log} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks and steps</p>
<Slider dots min={-10} marks={marks} step={10} onChange={log} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks, `included=false`</p>
<Slider min={-10} marks={marks} included={false} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks and steps, `included=false`</p>
<Slider min={-10} marks={marks} step={10} included={false} defaultValue={20} />
</div>
<div style={style}>
<p>Range with marks</p>
<Slider min={-10} range marks={marks} onChange={log} defaultValue={[20, 40]} />
</div>
<div style={style}>
<p>Range with marks and steps</p>
<Slider min={-10} range marks={marks} step={10} onChange={log} defaultValue={[20, 40]} />
</div>
</div>
, document.getElementById('__react-content'));
+1
View File
@@ -0,0 +1 @@
placeholder
+117
View File
@@ -0,0 +1,117 @@
/* 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 = {width: 400, margin: 50};
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>
<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>
);
},
});
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>
<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} />
<br /><br />
<Slider range defaultValue={[20, 50]} min={this.state.min} max={this.state.max} onChange={this.onSliderChange} />
</div>
);
},
});
ReactDOM.render(
<div>
<div style={style}>
<p>Basic Range`allowCross=false`</p>
<Slider range allowCross={false} defaultValue={[0, 20]} onChange={log} />
</div>
<div style={style}>
<p>Basic Range`step=20` </p>
<Slider range step={20} defaultValue={[20, 20]} onBeforeChange={log} />
</div>
<div style={style}>
<p>Basic Range`step=20, dots` </p>
<Slider range dots step={20} defaultValue={[20, 40]} onAfterChange={log} />
</div>
<div style={style}>
<p>Controlled Range</p>
<Slider range 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'));
-9
View File
@@ -1,9 +0,0 @@
'use strict';
require('rc-slider/assets/index.css');
var Slider = require('rc-slider');
var React = require('react');
// React.render(<Slider marks={["一","二","三","四","五"]} index={3}/>, document.getElementById('__react-content'));
// React.render(<Slider className='rc-slider' step={20}/>, document.getElementById('__react-content'));
React.render(<Slider />, document.getElementById('__react-content'));
+1
View File
@@ -0,0 +1 @@
placeholder
+109
View File
@@ -0,0 +1,109 @@
/* 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 = {width: 400, margin: 50};
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,
});
},
onAfterChange: function(value) {
console.log(value);
},
render: function() {
return <Slider value={this.state.value} onChange={this.onSliderChange} onAfterChange={this.onAfterChange} />;
},
});
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>
<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} />
<br /><br />
<Slider defaultValue={50} min={this.state.min} max={this.state.max} onChange={this.onSliderChange} />
</div>
);
},
});
ReactDOM.render(
<div>
<div style={style}>
<p>Basic Slider</p>
<Slider tipTransitionName="rc-slider-tooltip-zoom-down" onChange={log} />
</div>
<div style={style}>
<p>Basic Slider`step=20`</p>
<Slider step={20} defaultValue={50} onBeforeChange={log} />
</div>
<div style={style}>
<p>Basic Slider`step=20, dots`</p>
<Slider dots step={20} defaultValue={100} onAfterChange={log} />
</div>
<div style={style}>
<p>Basic Slider with `tipFormatter`</p>
<Slider tipFormatter={percentFormatter} tipTransitionName="rc-slider-tooltip-zoom-down" onChange={log} />
</div>
<div style={style}>
<p>Basic Slider without tooltip</p>
<Slider tipFormatter={null} onChange={log} />
</div>
<div style={style}>
<p>Controlled Slider</p>
<Slider value={50} />
</div>
<div style={style}>
<p>Customized Slider</p>
<CustomizedSlider />
</div>
<div style={style}>
<p>Slider with dynamic `min` `max`</p>
<DynamicBounds />
</div>
</div>
, document.getElementById('__react-content'));
+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
View File
@@ -1,3 +1,2 @@
'use strict';
module.exports = require('./src/');
+23 -19
View File
@@ -1,6 +1,6 @@
{
"name": "rc-slider",
"version": "1.2.7",
"version": "3.8.1",
"description": "slider ui component for react",
"keywords": [
"react",
@@ -17,38 +17,42 @@
"bugs": {
"url": "http://github.com/react-component/slider/issues"
},
"files": [
"assets/*.css",
"lib"
],
"licenses": "MIT",
"main": "./lib/index.js",
"config": {
"port": 8000
"port": 8005
},
"scripts": {
"build": "rc-tools run build",
"precommit": "rc-tools run precommit",
"less": "rc-tools run less",
"gh-pages": "rc-tools run gh-pages",
"history": "rc-tools run history",
"start": "node --harmony node_modules/.bin/rc-server",
"publish": "rc-tools run tag",
"start": "rc-server",
"pub": "rc-tools run pub",
"lint": "rc-tools run lint",
"saucelabs": "node --harmony node_modules/.bin/rc-tools run saucelabs",
"browser-test": "node --harmony node_modules/.bin/rc-tools run browser-test",
"browser-test-cover": "node --harmony node_modules/.bin/rc-tools run browser-test-cover"
"karma": "rc-tools run karma",
"saucelabs": "rc-tools run saucelabs",
"browser-test": "rc-tools run browser-test",
"browser-test-cover": "rc-tools run browser-test-cover"
},
"devDependencies": {
"expect.js": "0.3.x",
"precommit-hook": "^1.0.7",
"pre-commit": "1.x",
"rc-server": "3.x",
"rc-tools": "3.x",
"react": "^0.13.x",
"node-dev": "2.x",
"jquery": "^1.11.2"
"rc-tools": "4.x",
"react": "^15.2.1",
"react-addons-test-utils": "^15.2.1",
"react-dom": "^15.2.1"
},
"precommit": [
"precommit"
"pre-commit": [
"lint"
],
"dependencies": {
"rc-tooltip": "^2.4.0",
"rc-util": "^2.0.2"
"classnames": "^2.2.5",
"rc-tooltip": "^3.4.2",
"rc-util": "^3.2.1",
"warning": "^3.0.0"
}
}
+77
View File
@@ -0,0 +1,77 @@
import React from 'react';
import Tooltip from 'rc-tooltip';
export default class Handle extends React.Component {
constructor(props) {
super(props);
this.state = {
isTooltipVisible: false,
};
}
showTooltip() {
this.setState({
isTooltipVisible: true,
});
}
hideTooltip() {
this.setState({
isTooltipVisible: false,
});
}
render() {
const {
prefixCls,
className,
tipTransitionName,
tipFormatter,
vertical,
offset,
value,
dragging,
noTip,
} = this.props;
const style = vertical ? { bottom: offset + '%' } : { left: offset + '%' };
const handle = (
<div className={className} style={style}
onMouseUp={this.showTooltip.bind(this)}
onMouseEnter={this.showTooltip.bind(this)}
onMouseLeave={this.hideTooltip.bind(this)}
/>
);
if (noTip) {
return handle;
}
const isTooltipVisible = dragging || this.state.isTooltipVisible;
return (
<Tooltip
prefixCls={prefixCls.replace('slider', 'tooltip')}
placement="top"
visible={isTooltipVisible}
overlay={<span>{tipFormatter(value)}</span>}
delay={0}
transitionName={tipTransitionName}
>
{handle}
</Tooltip>
);
}
}
Handle.propTypes = {
prefixCls: React.PropTypes.string,
className: React.PropTypes.string,
vertical: React.PropTypes.bool,
offset: React.PropTypes.number,
tipTransitionName: React.PropTypes.string,
tipFormatter: React.PropTypes.func,
value: React.PropTypes.number,
dragging: React.PropTypes.bool,
noTip: React.PropTypes.bool,
};
+47
View File
@@ -0,0 +1,47 @@
import React from 'react';
import classNames from 'classnames';
const Marks = ({className, vertical, marks, included, upperBound, lowerBound, max, min}) => {
const marksKeys = Object.keys(marks);
const marksCount = marksKeys.length;
const unit = 100 / (marksCount - 1);
const markWidth = unit * 0.9;
const range = max - min;
const elements = marksKeys.map(parseFloat).sort((a, b) => a - b).map((point) => {
const isActived = (!included && point === upperBound) ||
(included && point <= upperBound && point >= lowerBound);
const markClassName = classNames({
[className + '-text']: true,
[className + '-text-active']: isActived,
});
const bottomStyle = {
// height: markWidth + '%',
marginBottom: '-200' + '%',
bottom: (point - min) / range * 100 + '%',
};
const leftStyle = {
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>);
});
return <div className={className}>{elements}</div>;
};
export default Marks;
+424 -413
View File
@@ -1,465 +1,476 @@
'use strict';
import React, { cloneElement } from 'react';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
import Track from './Track';
import DefaultHandle from './Handle';
import Steps from './Steps';
import Marks from './Marks';
var React = require('react');
var Tooltip = require('rc-tooltip');
var DomUtils = require('rc-util').Dom;
function noop() {
}
function isNotTouchEvent(e) {
return e.touches.length > 1 || (e.type.toLowerCase() === 'touchend' && e.touches.length > 0);
}
function getTouchPosition(vertical, e) {
return vertical ? e.touches[0].clientY : e.touches[0].pageX;
}
function getMousePosition(vertical, e) {
return vertical ? e.clientY : e.pageX;
}
function pauseEvent(e) {
if (e.stopPropagation) {
e.stopPropagation();
}
if (e.preventDefault) {
e.preventDefault();
}
e.stopPropagation();
e.preventDefault();
}
function prefixClsFn(prefixCls) {
var args = Array.prototype.slice.call(arguments, 1);
return args.map((s)=> {
return prefixCls + '-' + s;
}).join(' ');
}
class Slider extends React.Component {
constructor(props) {
super(props);
var Slider = React.createClass({
propTypes: {
min: React.PropTypes.number,
max: React.PropTypes.number,
step: React.PropTypes.number,
value: React.PropTypes.number,
index: React.PropTypes.number,
marks: React.PropTypes.array,
isIncluded: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
onBeforeChange: React.PropTypes.func,
onChange: React.PropTypes.func,
onAfterChange: React.PropTypes.func
},
const {range, min, max} = props;
const initialValue = range ? [min, min] : min;
const defaultValue = ('defaultValue' in props ? props.defaultValue : initialValue);
const value = (props.value !== undefined ? props.value : defaultValue);
getDefaultProps: function() {
return {
min: 0,
max: 100,
step: 1,
value: 0,
marks: [],
isIncluded: true,
className: 'rc-slider',
disabled: false,
index: 0
};
},
getInitialState: function() {
var props = this.props;
var value = this._trimAlignValue(props.value);
var marksLen = props.marks.length;
if (marksLen > 0) {
value = ((props.max - props.min) / (marksLen - 1)) * (props.index);
value = value.toFixed(5);
let upperBound;
let lowerBound;
if (props.range) {
lowerBound = this.trimAlignValue(value[0]);
upperBound = this.trimAlignValue(value[1]);
} else {
upperBound = this.trimAlignValue(value);
}
return {
upperBound: 0,
sliderLength: 0,
value: value,
active: props.disabled ? '' : ((value > props.min || props.index > 0) ? 'active' : '')
};
},
componentWillReceiveProps: function(newProps) {
var value = newProps.value;
this.state.value = this._trimAlignValue(value, newProps);
},
componentDidMount: function() {
this._onHandleResizeListener = DomUtils.addEventListener(window, 'resize', this.handleResize);
setTimeout(this.handleResize, 0);
},
componentWillUnmount: function() {
if (this._onHandleResizeListener) {
this._onHandleResizeListener.remove();
let recent;
if (props.range && upperBound === lowerBound) {
recent = lowerBound === max ? 'lowerBound' : 'upperBound';
} else {
recent = 'upperBound';
}
},
getValue: function() {
return this.state.value;
},
this.state = {
handle: null,
recent: recent,
upperBound: upperBound,
// If Slider is not range, set `lowerBound` equal to `min`.
lowerBound: (lowerBound || min),
};
}
getIndex: function() {
var props = this.props;
if (props.marks.length === 0) {
componentWillReceiveProps(nextProps) {
if (!('value' in nextProps || 'min' in nextProps || 'max' in nextProps)) return;
const {lowerBound, upperBound} = this.state;
if (nextProps.range) {
const value = nextProps.value || [lowerBound, upperBound];
const nextUpperBound = this.trimAlignValue(value[1], nextProps);
const nextLowerBound = this.trimAlignValue(value[0], nextProps);
if (nextLowerBound === lowerBound && nextUpperBound === upperBound) return;
this.setState({
upperBound: nextUpperBound,
lowerBound: nextLowerBound,
});
if (this.isValueOutOfBounds(upperBound, nextProps) ||
this.isValueOutOfBounds(lowerBound, nextProps)) {
this.props.onChange([nextLowerBound, nextUpperBound]);
}
} else {
const value = nextProps.value !== undefined ? nextProps.value : upperBound;
const nextValue = this.trimAlignValue(value, nextProps);
if (nextValue === upperBound && lowerBound === nextProps.min) return;
this.setState({
upperBound: nextValue,
lowerBound: nextProps.min,
});
if (this.isValueOutOfBounds(upperBound, nextProps)) {
this.props.onChange(nextValue);
}
}
}
onChange(state) {
const props = this.props;
const isNotControlled = !('value' in props);
if (isNotControlled) {
this.setState(state);
} else if (state.handle) {
this.setState({handle: state.handle});
}
const data = {...this.state, ...state};
const changedValue = props.range ? [data.lowerBound, data.upperBound] : data.upperBound;
props.onChange(changedValue);
}
onMouseMove(e) {
const position = getMousePosition(this.props.vertical, e);
this.onMove(e, position);
}
onTouchMove(e) {
if (isNotTouchEvent(e)) {
this.end('touch');
return;
}
const position = getTouchPosition(this.props.vertical, e);
this.onMove(e, position);
}
onMove(e, position) {
pauseEvent(e);
const props = this.props;
const state = this.state;
let diffPosition = position - this.startPosition;
diffPosition = this.props.vertical ? -diffPosition : diffPosition;
const diffValue = diffPosition / this.getSliderLength() * (props.max - props.min);
const value = this.trimAlignValue(this.startValue + diffValue);
const oldValue = state[state.handle];
if (value === oldValue) return;
if (props.allowCross && value < state.lowerBound && state.handle === 'upperBound') {
this.onChange({
handle: 'lowerBound',
lowerBound: value,
upperBound: this.state.lowerBound,
});
return;
}
if (props.allowCross && value > state.upperBound && state.handle === 'lowerBound') {
this.onChange({
handle: 'upperBound',
upperBound: value,
lowerBound: this.state.upperBound,
});
return;
}
this.onChange({
[state.handle]: value,
});
}
onTouchStart(e) {
if (isNotTouchEvent(e)) return;
const position = getTouchPosition(this.props.vertical, e);
this.onStart(position);
this.addDocumentEvents('touch');
pauseEvent(e);
}
onMouseDown(e) {
if (e.button !== 0) { return; }
const position = getMousePosition(this.props.vertical, e);
this.onStart(position);
this.addDocumentEvents('mouse');
pauseEvent(e);
}
onStart(position) {
const props = this.props;
props.onBeforeChange(this.getValue());
const value = this.calcValueByPos(position);
this.startValue = value;
this.startPosition = position;
const state = this.state;
const {upperBound, lowerBound} = state;
let valueNeedChanging = 'upperBound';
if (this.props.range) {
const isLowerBoundCloser = Math.abs(upperBound - value) > Math.abs(lowerBound - value);
if (isLowerBoundCloser) {
valueNeedChanging = 'lowerBound';
}
const isAtTheSamePoint = (upperBound === lowerBound);
if (isAtTheSamePoint) {
valueNeedChanging = state.recent;
}
if (isAtTheSamePoint && (value !== upperBound)) {
valueNeedChanging = value < upperBound ? 'lowerBound' : 'upperBound';
}
}
this.setState({
handle: valueNeedChanging,
recent: valueNeedChanging,
});
const oldValue = state[valueNeedChanging];
if (value === oldValue) return;
this.onChange({
[valueNeedChanging]: value,
});
}
getValue() {
const {lowerBound, upperBound} = this.state;
return this.props.range ? [lowerBound, upperBound] : upperBound;
}
getSliderLength() {
const slider = this.refs.slider;
if (!slider) {
return 0;
}
var value = this.state.value;
var unit = ((props.max - props.min) / (props.marks.length - 1)).toFixed(5);
return Math.floor(value / unit);
},
_trimAlignValue: function(val, props) {
props = props || this.props;
return this.props.vertical ? slider.clientHeight : slider.clientWidth;
}
var step = props.marks.length > 0 ? (props.max - props.min) / (props.marks.length - 1) : props.step;
getSliderStart() {
const slider = this.refs.slider;
const rect = slider.getBoundingClientRect();
if (val <= props.min) {
val = props.min;
return this.props.vertical ? rect.top : rect.left;
}
getPrecision(step) {
const stepString = step.toString();
let precision = 0;
if (stepString.indexOf('.') >= 0) {
precision = stepString.length - stepString.indexOf('.') - 1;
}
if (val >= props.max) {
val = props.max;
return precision;
}
isValueOutOfBounds(value, props) {
return value < props.min || value > props.max;
}
trimAlignValue(v, nextProps) {
const state = this.state || {};
const {handle, lowerBound, upperBound} = state;
const {marks, step, min, max, allowCross} = {...this.props, ...(nextProps || {})};
let val = v;
if (val <= min) {
val = min;
}
if (val >= max) {
val = max;
}
if (!allowCross && handle === 'upperBound' && val <= lowerBound) {
val = lowerBound;
}
if (!allowCross && handle === 'lowerBound' && val >= upperBound) {
val = upperBound;
}
var valModStep = (val - props.min) % step;
var alignValue = val - valModStep;
if (Math.abs(valModStep) * 2 >= step) {
alignValue += (valModStep > 0) ? step : (-step);
const points = Object.keys(marks).map(parseFloat);
if (step !== null) {
const closestStep = (Math.round((val - min) / step) * step) + min;
points.push(closestStep);
}
return parseFloat(alignValue.toFixed(5));
},
const diffs = points.map((point) => Math.abs(val - point));
const closestPoint = points[diffs.indexOf(Math.min.apply(Math, diffs))];
_calcOffset: function(value) {
var ratio = (value - this.props.min) / (this.props.max - this.props.min);
return ratio * this.state.upperBound;
},
return step !== null ? parseFloat(closestPoint.toFixed(this.getPrecision(step))) : closestPoint;
}
_calcValue: function(offset) {
var ratio = offset / this.state.upperBound;
return ratio * (this.props.max - this.props.min) + this.props.min;
},
calcOffset(value) {
const {min, max} = this.props;
const ratio = (value - min) / (max - min);
return ratio * 100;
}
_calValueByPos: function (position, callback) {
var pixelOffset = position - this.getSliderStart();
// pixelOffset -= (this.state.handleSize / 2);
calcValue(offset) {
const {vertical, min, max} = this.props;
const ratio = Math.abs(offset / this.getSliderLength());
const value = vertical ? (1 - ratio) * (max - min) + min : ratio * (max - min) + min;
return value;
}
var nextValue = this._trimAlignValue(this._calcValue(pixelOffset));
calcValueByPos(position) {
const pixelOffset = position - this.getSliderStart();
const nextValue = this.trimAlignValue(this.calcValue(pixelOffset));
return nextValue;
}
this.setState({value: nextValue, active: 'active'}, callback);
},
_getMousePosition: function(e) {
return e.pageX || (e.clientX + document.documentElement.scrollLeft);
},
_getTouchPosition: function (e) {
var touch = e.touches[0];
return touch.pageX;
},
_triggerEvents: function(event) {
var props = this.props;
var hasMarks = props.marks && props.marks.length > 0;
if (props[event]) {
props[event](hasMarks ? this.getIndex() : this.state.value);
}
},
_addEventHandles: function(type) {
addDocumentEvents(type) {
if (type === 'touch') {
// just work for chrome iOS Safari and Android Browser
this._onTouchMoveListener = DomUtils.addEventListener(document, 'touchmove', this._onTouchMove);
this._onTouchUpListener = DomUtils.addEventListener(document, 'touchend', this._onTouchUp);
this.onTouchMoveListener = addEventListener(document, 'touchmove', this.onTouchMove.bind(this));
this.onTouchUpListener = addEventListener(document, 'touchend', this.end.bind(this, 'touch'));
} else if (type === 'mouse') {
this.onMouseMoveListener = addEventListener(document, 'mousemove', this.onMouseMove.bind(this));
this.onMouseUpListener = addEventListener(document, 'mouseup', this.end.bind(this, 'mouse'));
}
}
if (type === 'mouse') {
this._onMouseMoveListener = DomUtils.addEventListener(document, 'mousemove', this._onMouseMove);
this._onMouseUpListener = DomUtils.addEventListener(document, 'mouseup', this._onMouseUp);
}
},
_removeEventHandles: function (type) {
removeEvents(type) {
if (type === 'touch') {
this._onTouchMoveListener.remove();
this._onTouchUpListener.remove();
this.onTouchMoveListener.remove();
this.onTouchUpListener.remove();
} else if (type === 'mouse') {
this.onMouseMoveListener.remove();
this.onMouseUpListener.remove();
}
}
if (type === 'mouse') {
this._onMouseMoveListener.remove();
this._onMouseUpListener.remove();
}
},
end(type) {
this.removeEvents(type);
this.props.onAfterChange(this.getValue());
this.setState({handle: null});
}
_start: function(position) {
if (document.activeElement) {
document.activeElement.blur();
}
render() {
const {
handle,
upperBound,
lowerBound,
} = this.state;
const {
className,
prefixCls,
disabled,
vertical,
dots,
included,
range,
step,
marks,
max, min,
tipTransitionName,
tipFormatter,
children,
} = this.props;
this._triggerEvents('onBeforeChange');
const customHandle = this.props.handle;
this.setState({
startValue: this.state.value,
startPosition: position
const upperOffset = this.calcOffset(upperBound);
const lowerOffset = this.calcOffset(lowerBound);
const handleClassName = prefixCls + '-handle';
const upperClassName = classNames({
[handleClassName]: true,
[handleClassName + '-upper']: true,
});
},
_end: function(type) {
this._removeEventHandles(type);
this.setState(this._triggerEvents.bind(this, 'onAfterChange'));
},
_onMouseUp: function() {
this._end('mouse');
},
_onTouchUp: function() {
this._end('touch');
},
_onMouseMove: function(e) {
var position = this._getMousePosition(e);
this._handleMove(e, position);
},
_onTouchMove: function(e) {
if (e.touches.length > 1 || (e.type === 'touchend' && e.touches.length > 0)) {
return;
}
var position = this._getTouchPosition(e);
this._handleMove(e, position);
},
_handleMove: function(e, position) {
pauseEvent(e);
// var position = this._getMousePosition(e);
var props = this.props;
var state = this.state;
var value = state.value;
var oldValue = value;
var diffPosition = position - state.startPosition;
var diffValue = diffPosition / (state.sliderLength) * (props.max - props.min);
var newValue = this._trimAlignValue(state.startValue + diffValue);
value = newValue;
if (newValue !== oldValue) {
this.setState({value: value, active: 'active'}, this._triggerEvents.bind(this, 'onChange'));
}
},
handleResize: function() {
var slider = this.refs.slider.getDOMNode();
var rect = slider.getBoundingClientRect();
var sliderMin = rect.left;
var sliderMax = rect.right;
this.setState({
upperBound: slider.clientWidth,
sliderLength: Math.abs(sliderMax - sliderMin)
const lowerClassName = classNames({
[handleClassName]: true,
[handleClassName + '-lower']: true,
});
},
getSliderStart: function() {
var slider = this.refs.slider.getDOMNode();
var rect = slider.getBoundingClientRect();
const isNoTip = (step === null) || (tipFormatter === null);
return rect.left;
},
handleTouchStart: function(e) {
if (this.props.disabled || e.touches.length > 1 || (e.type === 'touchend' && e.touches.length > 0)) {
return;
}
var position = this._getTouchPosition(e);
this.startPosition = position;
this._start(position);
this._addEventHandles('touch');
pauseEvent(e);
},
handleMouseDown: function() {
return (e) => {
if (this.props.disabled) {
return;
}
var position = this._getMousePosition(e);
this._start(position);
this._addEventHandles('mouse');
pauseEvent(e);
};
},
handleSliderMouseDown: function(e) {
if (this.props.disabled) {
return;
}
var position = this._getMousePosition(e);
this._calValueByPos(position,
() => {
this._triggerEvents('onChange');
this._start(position);
this._addEventHandles('mouse');
}
);
pauseEvent(e);
},
renderSteps: function() {
var props = this.props;
var marksLen = props.marks.length;
var stepNum = marksLen > 0 ? marksLen : Math.floor((props.max - props.min) / props.step) + 1;
var unit = this.state.sliderLength / (stepNum - 1);
var prefixCls = props.className;
var stepClassName = prefixClsFn(prefixCls, 'step');
var elements = [];
for (var i = 0; i < stepNum; i++) {
var offset = unit * i;
var style = {
left: offset.toFixed(5)
};
var className = prefixClsFn(prefixCls, 'dot');
if (props.isIncluded) {
if (i <= this.getIndex() || (this._calcValue(offset) <= this.getValue())) {
className = prefixClsFn(prefixCls, 'dot', 'dot-active');
}
} else {
className = (i === this.getIndex()) ? prefixClsFn(prefixCls, 'dot', 'dot-active') : className;
}
elements[i] = (
<span className={className} style={style} ref={'step' + i}></span>
);
}
return (
<div className={stepClassName}>
{elements}
</div>
);
},
renderMark: function(i) {
var marks = this.props.marks;
var marksLen = marks.length;
var unit = this.state.sliderLength / (marksLen - 1);
var offset = unit * i;
var style = {
width: (unit / 2).toFixed(5)
const commonHandleProps = {
prefixCls,
noTip: isNoTip,
tipTransitionName,
tipFormatter,
vertical,
};
if (i === marksLen - 1) {
style.right = -(style.width / 2).toFixed(5);
} else {
style.left = i > 0 ? (offset - unit / 4).toFixed(5) : -(style.width / 2).toFixed(5);
}
const upper = cloneElement(customHandle, {
...commonHandleProps,
className: upperClassName,
value: upperBound,
offset: upperOffset,
dragging: handle === 'upperBound',
});
var prefixCls = this.props.className;
var 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;
let lower = null;
if (range) {
lower = cloneElement(customHandle, {
...commonHandleProps,
className: lowerClassName,
value: lowerBound,
offset: lowerOffset,
dragging: handle === 'lowerBound',
});
}
const sliderClassName = classNames({
[prefixCls]: true,
[prefixCls + '-disabled']: disabled,
[className]: !!className,
[prefixCls + '-vertical']: this.props.vertical,
});
const isIncluded = included || range;
return (
<span className={className} style={style}>{this.props.marks[i]}</span>
);
},
renderMarks: function() {
var marks = this.props.marks;
var marksLen = marks.length;
var elements = [];
for (var i = 0; i < marksLen; i++) {
elements[i] = this.renderMark(i);
}
var prefixCls = this.props.className;
var className = prefixClsFn(prefixCls, 'mark');
return (
<div className={className}>
{elements}
</div>
);
},
renderHandle: function(offset) {
var handleStyle = {
left: offset
};
var prefixCls = this.props.className;
var className = prefixClsFn(prefixCls, 'handle');
if (this.state.active) {
className = prefixClsFn(prefixCls, 'handle', 'handle-active');
}
var handle = <div className={className}
ref = "handle"
style = {handleStyle}
href = "#"
onMouseDown = {this.handleMouseDown}
onTouchStart = {this.handleTouchStart}></div>;
if (this.props.marks.length > 0) {
return handle;
} else {
return (
<Tooltip
placement="top"
overlay={<span>{this.state.value}</span>}
delay={0}
prefixCls={prefixClsFn(prefixCls, 'tooltip')}>
{handle}
</Tooltip>
);
}
},
renderTrack: function(offset) {
var style = {
width: offset
};
var prefixCls = this.props.className;
var trackClassName = prefixClsFn(prefixCls, 'track');
return (
<div className={trackClassName} ref="track" style={style}></div>
);
},
render: function() {
var state = this.state;
var props = this.props;
var value = state.value;
var offset = this._calcOffset(value);
var track = this.props.isIncluded ? this.renderTrack(offset) : null;
var handles = this.renderHandle(offset);
var steps = (props.step > 1 || props.marks.length > 0) ? this.renderSteps() : null;
var sliderMarks = (props.marks.length > 0) ? this.renderMarks() : null;
var prefixCls = props.className;
var sliderClassName = props.disabled ? prefixCls + ' ' + prefixClsFn(prefixCls, 'disabled') : prefixCls;
return (
<div className={sliderClassName} ref="slider" onMouseDown={this.handleSliderMouseDown}>
{track}
{handles}
{steps}
{sliderMarks}
{this.props.children}
<div ref="slider" className={sliderClassName}
onTouchStart={disabled ? noop : this.onTouchStart.bind(this)}
onMouseDown={disabled ? noop : this.onMouseDown.bind(this)}
>
{upper}
{lower}
<Track className={prefixCls + '-track'} vertical = {vertical} included={isIncluded}
offset={lowerOffset} length={upperOffset - lowerOffset} />
<Steps prefixCls={prefixCls} vertical = {vertical} marks={marks} dots={dots} step={step}
included={isIncluded} lowerBound={lowerBound}
upperBound={upperBound} max={max} min={min} />
<Marks className={prefixCls + '-mark'} vertical = {vertical} marks={marks}
included={isIncluded} lowerBound={lowerBound}
upperBound={upperBound} max={max} min={min} />
{children}
</div>
);
}
});
}
module.exports = Slider;
Slider.propTypes = {
min: React.PropTypes.number,
max: React.PropTypes.number,
step: React.PropTypes.number,
defaultValue: 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),
]),
marks: React.PropTypes.object,
included: React.PropTypes.bool,
className: React.PropTypes.string,
prefixCls: React.PropTypes.string,
disabled: React.PropTypes.bool,
children: React.PropTypes.any,
onBeforeChange: React.PropTypes.func,
onChange: React.PropTypes.func,
onAfterChange: React.PropTypes.func,
handle: React.PropTypes.element,
tipTransitionName: React.PropTypes.string,
tipFormatter: React.PropTypes.func,
dots: React.PropTypes.bool,
range: React.PropTypes.bool,
vertical: React.PropTypes.bool,
allowCross: React.PropTypes.bool,
};
Slider.defaultProps = {
prefixCls: 'rc-slider',
className: '',
tipTransitionName: '',
min: 0,
max: 100,
step: 1,
marks: {},
handle: <DefaultHandle />,
onBeforeChange: noop,
onChange: noop,
onAfterChange: noop,
tipFormatter: value => value,
included: true,
disabled: false,
dots: false,
range: false,
vertical: false,
allowCross: true,
};
export default Slider;
+37
View File
@@ -0,0 +1,37 @@
import React from 'react';
import classNames from 'classnames';
import warning from 'warning';
function calcPoints(vertical, marks, dots, step, min, max) {
warning(dots ? step > 0 : true, '`Slider[step]` should be a positive number in order to make Slider[dots] work.');
const points = Object.keys(marks).map(parseFloat);
if (dots) {
for (let i = min; i <= max; i = i + step) {
if (points.indexOf(i) >= 0) continue;
points.push(i);
}
}
return points;
}
const Steps = ({prefixCls, vertical, marks, dots, step, included,
lowerBound, upperBound, max, min}) => {
const range = max - min;
const elements = calcPoints(vertical, marks, dots, step, min, max).map((point) => {
const offset = Math.abs(point - min) / range * 100 + '%';
const style = vertical ? { bottom: offset } : { left: offset };
const isActived = (!included && point === upperBound) ||
(included && point <= upperBound && point >= lowerBound);
const pointClassName = classNames({
[prefixCls + '-dot']: true,
[prefixCls + '-dot-active']: isActived,
});
return <span className={pointClassName} style={style} key={point} />;
});
return <div className={prefixCls + '-step'}>{elements}</div>;
};
export default Steps;
+17
View File
@@ -0,0 +1,17 @@
import React from 'react';
const Track = ({className, included, vertical, offset, length}) => {
const style = {
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} />;
};
export default Track;
-1
View File
@@ -1,3 +1,2 @@
'use strict';
module.exports = require('./Slider');
+132 -60
View File
@@ -1,76 +1,148 @@
'use strict';
const expect = require('expect.js');
const React = require('react');
const ReactDOM = require('react-dom');
const ReactTestUtils = require('react-addons-test-utils');
const Slider = require('..');
var expect = require('expect.js');
var Slider = require('../index.js');
var React = require('react');
var TestUtils = React.addons.TestUtils;
var Simulate = TestUtils.Simulate;
var $ = require('jquery');
require('../assets/index.less');
describe('rc-slider', function () {
describe('rc-slider', function test() {
this.timeout(5000);
var div = document.createElement('div');
const div = document.createElement('div');
document.body.appendChild(div);
afterEach(function () {
React.unmountComponentAtNode(div);
afterEach(() => {
ReactDOM.unmountComponentAtNode(div);
});
it('should render a simple slider with value correctly!', function () {
var slider = React.render(
<Slider className='rc-slider' value={40}/>,
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(slider.getValue()).to.be(40);
var trackWidth = node.find('.rc-slider-track')[0].style.width;
expect(trackWidth).to.eql(node.find('.rc-slider-handle')[0].style.left);
it('should render a Slider with correct DOM structure', () => {
const slider = ReactDOM.render(<Slider />, div);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider').length).to.be(1);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-handle').length).to.be(1);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-track').length).to.be(1);
});
it('should render a slider with correct numbers of step!', function () {
var slider = React.render(
<Slider className='rc-slider' step={20}/>,
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(6);
expect(slider.getValue()).to.be(0);
it('should render a Slider with default value correctly', () => {
const sliderWithDefaultValue = ReactDOM.render(<Slider defaultValue={50} />, div);
expect(sliderWithDefaultValue.state.upperBound).to.be(50);
expect(ReactTestUtils
.scryRenderedDOMComponentsWithClass(sliderWithDefaultValue, 'rc-slider-handle')[0]
.style.cssText)
.to.match(/left: 50%;/);
const trackStyle = ReactTestUtils
.scryRenderedDOMComponentsWithClass(sliderWithDefaultValue, 'rc-slider-track')[0]
.style.cssText;
expect(trackStyle).to.match(/left: 0%;/);
expect(trackStyle).to.match(/width: 50%;/);
expect(trackStyle).to.match(/visibility: visible;/);
});
it('should render a slider with marks correctly!', function () {
var slider = React.render(
<Slider marks={["一","二","三","四","五"]} index={3} />,
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-mark').length).to.be(1);
expect(node.find('.rc-slider-mark-text').length).to.be(slider.props.marks.length);
expect(slider.getIndex()).to.be(3);
it('should render a Slider with value corrently', () => {
const sliderWithValue = ReactDOM.render(<Slider value={50} />, div);
expect(sliderWithValue.state.upperBound).to.be(50);
expect(ReactTestUtils
.scryRenderedDOMComponentsWithClass(sliderWithValue, 'rc-slider-handle')[0]
.style.cssText)
.to.match(/left: 50%;/);
const trackStyle = ReactTestUtils
.scryRenderedDOMComponentsWithClass(sliderWithValue, 'rc-slider-track')[0]
.style.cssText;
expect(trackStyle).to.match(/left: 0%;/);
expect(trackStyle).to.match(/width: 50%;/);
expect(trackStyle).to.match(/visibility: visible;/);
});
// it('should mouseDown works!', function (done) {
// var slider = React.render(
// <Slider marks={["一","二","三","四","五"]} />,
// div
// );
// var selectedStep = slider.refs.step3.getDOMNode();
// Simulate.mouseDown(selectedStep);
it('should render a Range with correct DOM structure', () => {
const range = ReactDOM.render(<Slider range />, div);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(range, 'rc-slider').length).to.be(1);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(range, 'rc-slider-handle').length).to.be(2);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(range, 'rc-slider-track').length).to.be(1);
});
// setTimeout( function() {
// expect(slider.state.active).to.be('active');
// done();
// }, 200);
// });
it('should render a Range with default value correctly', () => {
const rangeWithDefaultValue = ReactDOM.render(<Slider range defaultValue={[0, 50]} />, div);
expect(rangeWithDefaultValue.state.lowerBound).to.be(0);
expect(rangeWithDefaultValue.state.upperBound).to.be(50);
expect(ReactTestUtils
.scryRenderedDOMComponentsWithClass(rangeWithDefaultValue, 'rc-slider-handle')[0]
.style.cssText)
.to.match(/left: 50%;/);
expect(ReactTestUtils
.scryRenderedDOMComponentsWithClass(rangeWithDefaultValue, 'rc-slider-handle')[1]
.style.cssText)
.to.match(/left: 0%;/);
const trackStyle = ReactTestUtils
.scryRenderedDOMComponentsWithClass(rangeWithDefaultValue, 'rc-slider-track')[0]
.style.cssText;
expect(trackStyle).to.match(/left: 0%;/);
expect(trackStyle).to.match(/width: 50%;/);
expect(trackStyle).to.match(/visibility: visible;/);
});
it('should render a Range with value correctly', () => {
const rangeWithValue = ReactDOM.render(<Slider range value={[50, 100]} />, div);
expect(rangeWithValue.state.lowerBound).to.be(50);
expect(rangeWithValue.state.upperBound).to.be(100);
expect(ReactTestUtils
.scryRenderedDOMComponentsWithClass(rangeWithValue, 'rc-slider-handle')[0]
.style.cssText)
.to.match(/left: 100%;/);
expect(ReactTestUtils
.scryRenderedDOMComponentsWithClass(rangeWithValue, 'rc-slider-handle')[1]
.style.cssText)
.to.match(/left: 50%;/);
const trackStyle = ReactTestUtils
.scryRenderedDOMComponentsWithClass(rangeWithValue, 'rc-slider-track')[0]
.style.cssText;
expect(trackStyle).to.match(/left: 50%;/);
expect(trackStyle).to.match(/width: 50%;/);
expect(trackStyle).to.match(/visibility: visible;/);
});
it('should render dots correctly when `dots=true`', () => {
const slider = ReactDOM.render(<Slider value={50} step={10} dots />, div);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-dot').length).to.be(11);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-dot-active').length).to.be(6);
const range = ReactDOM.render(<Slider range value={[20, 50]} step={10} dots />, div);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(range, 'rc-slider-dot').length).to.be(11);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(range, 'rc-slider-dot-active').length).to.be(4);
});
it('should render marks correctly when `marks` is not an empty object', () => {
const marks = {0: '0', 30: '30', 100: '100'};
const slider = ReactDOM.render(<Slider value={30} marks={marks} />, div);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-mark-text').length).to.be(3);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-mark-text')[0].innerHTML).to.be('0');
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-mark-text')[1].innerHTML).to.be('30');
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(slider, 'rc-slider-mark-text')[2].innerHTML).to.be('100');
const range = ReactDOM.render(<Slider range value={[0, 30]} marks={marks} />, div);
expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(range, 'rc-slider-mark-text').length).to.be(3);
});
it('should not set value greater than `max` or smaller `min`', () => {
const sliderWithMin = ReactDOM.render(<Slider value={0} min={10} />, div);
expect(sliderWithMin.state.upperBound).to.be(10);
ReactDOM.unmountComponentAtNode(div);
const sliderWithMax = ReactDOM.render(<Slider value={100} max={90} />, div);
expect(sliderWithMax.state.upperBound).to.be(90);
ReactDOM.unmountComponentAtNode(div);
const range = ReactDOM.render(<Slider range value={[0, 100]} min={10} max={90} />, div);
expect(range.state.lowerBound).to.be(10);
expect(range.state.upperBound).to.be(90);
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);
});
});