You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

585 line
18 KiB

  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
  6. var _defineProperty3 = _interopRequireDefault(_defineProperty2);
  7. var _extends2 = require('babel-runtime/helpers/extends');
  8. var _extends3 = _interopRequireDefault(_extends2);
  9. var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
  10. var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
  11. var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
  12. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  13. var _createClass2 = require('babel-runtime/helpers/createClass');
  14. var _createClass3 = _interopRequireDefault(_createClass2);
  15. var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
  16. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  17. var _inherits2 = require('babel-runtime/helpers/inherits');
  18. var _inherits3 = _interopRequireDefault(_inherits2);
  19. var _react = require('react');
  20. var _react2 = _interopRequireDefault(_react);
  21. var _propTypes = require('prop-types');
  22. var _propTypes2 = _interopRequireDefault(_propTypes);
  23. var _classnames = require('classnames');
  24. var _classnames2 = _interopRequireDefault(_classnames);
  25. var _reactLifecyclesCompat = require('react-lifecycles-compat');
  26. var _shallowequal = require('shallowequal');
  27. var _shallowequal2 = _interopRequireDefault(_shallowequal);
  28. var _Track = require('./common/Track');
  29. var _Track2 = _interopRequireDefault(_Track);
  30. var _createSlider = require('./common/createSlider');
  31. var _createSlider2 = _interopRequireDefault(_createSlider);
  32. var _utils = require('./utils');
  33. var utils = _interopRequireWildcard(_utils);
  34. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
  35. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  36. /* eslint-disable react/prop-types */
  37. var _trimAlignValue = function _trimAlignValue(_ref) {
  38. var value = _ref.value,
  39. handle = _ref.handle,
  40. bounds = _ref.bounds,
  41. props = _ref.props;
  42. var allowCross = props.allowCross,
  43. pushable = props.pushable;
  44. var thershold = Number(pushable);
  45. var valInRange = utils.ensureValueInRange(value, props);
  46. var valNotConflict = valInRange;
  47. if (!allowCross && handle != null && bounds !== undefined) {
  48. if (handle > 0 && valInRange <= bounds[handle - 1] + thershold) {
  49. valNotConflict = bounds[handle - 1] + thershold;
  50. }
  51. if (handle < bounds.length - 1 && valInRange >= bounds[handle + 1] - thershold) {
  52. valNotConflict = bounds[handle + 1] - thershold;
  53. }
  54. }
  55. return utils.ensureValuePrecision(valNotConflict, props);
  56. };
  57. var Range = function (_React$Component) {
  58. (0, _inherits3['default'])(Range, _React$Component);
  59. function Range(props) {
  60. (0, _classCallCheck3['default'])(this, Range);
  61. var _this = (0, _possibleConstructorReturn3['default'])(this, (Range.__proto__ || Object.getPrototypeOf(Range)).call(this, props));
  62. _this.onEnd = function (force) {
  63. var handle = _this.state.handle;
  64. _this.removeDocumentEvents();
  65. if (handle !== null || force) {
  66. _this.props.onAfterChange(_this.getValue());
  67. }
  68. _this.setState({
  69. handle: null
  70. });
  71. };
  72. var count = props.count,
  73. min = props.min,
  74. max = props.max;
  75. var initialValue = Array.apply(undefined, (0, _toConsumableArray3['default'])(Array(count + 1))).map(function () {
  76. return min;
  77. });
  78. var defaultValue = 'defaultValue' in props ? props.defaultValue : initialValue;
  79. var value = props.value !== undefined ? props.value : defaultValue;
  80. var bounds = value.map(function (v, i) {
  81. return _trimAlignValue({
  82. value: v,
  83. handle: i,
  84. props: props
  85. });
  86. });
  87. var recent = bounds[0] === max ? 0 : bounds.length - 1;
  88. _this.state = {
  89. handle: null,
  90. recent: recent,
  91. bounds: bounds
  92. };
  93. return _this;
  94. }
  95. (0, _createClass3['default'])(Range, [{
  96. key: 'componentDidUpdate',
  97. value: function componentDidUpdate(prevProps, prevState) {
  98. var _this2 = this;
  99. if (!('value' in this.props || 'min' in this.props || 'max' in this.props)) {
  100. return;
  101. }
  102. if (this.props.min === prevProps.min && this.props.max === prevProps.max && (0, _shallowequal2['default'])(this.props.value, prevProps.value)) {
  103. return;
  104. }
  105. var _props = this.props,
  106. onChange = _props.onChange,
  107. value = _props.value;
  108. var currentValue = value || prevState.bounds;
  109. if (currentValue.some(function (v) {
  110. return utils.isValueOutOfRange(v, _this2.props);
  111. })) {
  112. var newValues = currentValue.map(function (v) {
  113. return utils.ensureValueInRange(v, _this2.props);
  114. });
  115. onChange(newValues);
  116. }
  117. }
  118. }, {
  119. key: 'onChange',
  120. value: function onChange(state) {
  121. var props = this.props;
  122. var isNotControlled = !('value' in props);
  123. if (isNotControlled) {
  124. this.setState(state);
  125. } else {
  126. var controlledState = {};
  127. ['handle', 'recent'].forEach(function (item) {
  128. if (state[item] !== undefined) {
  129. controlledState[item] = state[item];
  130. }
  131. });
  132. if (Object.keys(controlledState).length) {
  133. this.setState(controlledState);
  134. }
  135. }
  136. var data = (0, _extends3['default'])({}, this.state, state);
  137. var changedValue = data.bounds;
  138. props.onChange(changedValue);
  139. }
  140. }, {
  141. key: 'onStart',
  142. value: function onStart(position) {
  143. var props = this.props;
  144. var state = this.state;
  145. var bounds = this.getValue();
  146. props.onBeforeChange(bounds);
  147. var value = this.calcValueByPos(position);
  148. this.startValue = value;
  149. this.startPosition = position;
  150. var closestBound = this.getClosestBound(value);
  151. this.prevMovedHandleIndex = this.getBoundNeedMoving(value, closestBound);
  152. this.setState({
  153. handle: this.prevMovedHandleIndex,
  154. recent: this.prevMovedHandleIndex
  155. });
  156. var prevValue = bounds[this.prevMovedHandleIndex];
  157. if (value === prevValue) return;
  158. var nextBounds = [].concat((0, _toConsumableArray3['default'])(state.bounds));
  159. nextBounds[this.prevMovedHandleIndex] = value;
  160. this.onChange({ bounds: nextBounds });
  161. }
  162. }, {
  163. key: 'onMove',
  164. value: function onMove(e, position) {
  165. utils.pauseEvent(e);
  166. var state = this.state;
  167. var value = this.calcValueByPos(position);
  168. var oldValue = state.bounds[state.handle];
  169. if (value === oldValue) return;
  170. this.moveTo(value);
  171. }
  172. }, {
  173. key: 'onKeyboard',
  174. value: function onKeyboard(e) {
  175. var _props2 = this.props,
  176. reverse = _props2.reverse,
  177. vertical = _props2.vertical;
  178. var valueMutator = utils.getKeyboardValueMutator(e, vertical, reverse);
  179. if (valueMutator) {
  180. utils.pauseEvent(e);
  181. var state = this.state,
  182. props = this.props;
  183. var bounds = state.bounds,
  184. handle = state.handle;
  185. var oldValue = bounds[handle === null ? state.recent : handle];
  186. var mutatedValue = valueMutator(oldValue, props);
  187. var value = _trimAlignValue({
  188. value: mutatedValue,
  189. handle: handle,
  190. bounds: state.bounds,
  191. props: props
  192. });
  193. if (value === oldValue) return;
  194. var isFromKeyboardEvent = true;
  195. this.moveTo(value, isFromKeyboardEvent);
  196. }
  197. }
  198. }, {
  199. key: 'getValue',
  200. value: function getValue() {
  201. return this.state.bounds;
  202. }
  203. }, {
  204. key: 'getClosestBound',
  205. value: function getClosestBound(value) {
  206. var bounds = this.state.bounds;
  207. var closestBound = 0;
  208. for (var i = 1; i < bounds.length - 1; ++i) {
  209. if (value >= bounds[i]) {
  210. closestBound = i;
  211. }
  212. }
  213. if (Math.abs(bounds[closestBound + 1] - value) < Math.abs(bounds[closestBound] - value)) {
  214. closestBound += 1;
  215. }
  216. return closestBound;
  217. }
  218. }, {
  219. key: 'getBoundNeedMoving',
  220. value: function getBoundNeedMoving(value, closestBound) {
  221. var _state = this.state,
  222. bounds = _state.bounds,
  223. recent = _state.recent;
  224. var boundNeedMoving = closestBound;
  225. var isAtTheSamePoint = bounds[closestBound + 1] === bounds[closestBound];
  226. if (isAtTheSamePoint && bounds[recent] === bounds[closestBound]) {
  227. boundNeedMoving = recent;
  228. }
  229. if (isAtTheSamePoint && value !== bounds[closestBound + 1]) {
  230. boundNeedMoving = value < bounds[closestBound + 1] ? closestBound : closestBound + 1;
  231. }
  232. return boundNeedMoving;
  233. }
  234. }, {
  235. key: 'getLowerBound',
  236. value: function getLowerBound() {
  237. return this.state.bounds[0];
  238. }
  239. }, {
  240. key: 'getUpperBound',
  241. value: function getUpperBound() {
  242. var bounds = this.state.bounds;
  243. return bounds[bounds.length - 1];
  244. }
  245. /**
  246. * Returns an array of possible slider points, taking into account both
  247. * `marks` and `step`. The result is cached.
  248. */
  249. }, {
  250. key: 'getPoints',
  251. value: function getPoints() {
  252. var _props3 = this.props,
  253. marks = _props3.marks,
  254. step = _props3.step,
  255. min = _props3.min,
  256. max = _props3.max;
  257. var cache = this._getPointsCache;
  258. if (!cache || cache.marks !== marks || cache.step !== step) {
  259. var pointsObject = (0, _extends3['default'])({}, marks);
  260. if (step !== null) {
  261. for (var point = min; point <= max; point += step) {
  262. pointsObject[point] = point;
  263. }
  264. }
  265. var points = Object.keys(pointsObject).map(parseFloat);
  266. points.sort(function (a, b) {
  267. return a - b;
  268. });
  269. this._getPointsCache = { marks: marks, step: step, points: points };
  270. }
  271. return this._getPointsCache.points;
  272. }
  273. }, {
  274. key: 'moveTo',
  275. value: function moveTo(value, isFromKeyboardEvent) {
  276. var _this3 = this;
  277. var state = this.state,
  278. props = this.props;
  279. var nextBounds = [].concat((0, _toConsumableArray3['default'])(state.bounds));
  280. var handle = state.handle === null ? state.recent : state.handle;
  281. nextBounds[handle] = value;
  282. var nextHandle = handle;
  283. if (props.pushable !== false) {
  284. this.pushSurroundingHandles(nextBounds, nextHandle);
  285. } else if (props.allowCross) {
  286. nextBounds.sort(function (a, b) {
  287. return a - b;
  288. });
  289. nextHandle = nextBounds.indexOf(value);
  290. }
  291. this.onChange({
  292. recent: nextHandle,
  293. handle: nextHandle,
  294. bounds: nextBounds
  295. });
  296. if (isFromKeyboardEvent) {
  297. // known problem: because setState is async,
  298. // so trigger focus will invoke handler's onEnd and another handler's onStart too early,
  299. // cause onBeforeChange and onAfterChange receive wrong value.
  300. // here use setState callback to hack,but not elegant
  301. this.props.onAfterChange(nextBounds);
  302. this.setState({}, function () {
  303. _this3.handlesRefs[nextHandle].focus();
  304. });
  305. this.onEnd();
  306. }
  307. }
  308. }, {
  309. key: 'pushSurroundingHandles',
  310. value: function pushSurroundingHandles(bounds, handle) {
  311. var value = bounds[handle];
  312. var threshold = this.props.pushable;
  313. threshold = Number(threshold);
  314. var direction = 0;
  315. if (bounds[handle + 1] - value < threshold) {
  316. direction = +1; // push to right
  317. }
  318. if (value - bounds[handle - 1] < threshold) {
  319. direction = -1; // push to left
  320. }
  321. if (direction === 0) {
  322. return;
  323. }
  324. var nextHandle = handle + direction;
  325. var diffToNext = direction * (bounds[nextHandle] - value);
  326. if (!this.pushHandle(bounds, nextHandle, direction, threshold - diffToNext)) {
  327. // revert to original value if pushing is impossible
  328. bounds[handle] = bounds[nextHandle] - direction * threshold;
  329. }
  330. }
  331. }, {
  332. key: 'pushHandle',
  333. value: function pushHandle(bounds, handle, direction, amount) {
  334. var originalValue = bounds[handle];
  335. var currentValue = bounds[handle];
  336. while (direction * (currentValue - originalValue) < amount) {
  337. if (!this.pushHandleOnePoint(bounds, handle, direction)) {
  338. // can't push handle enough to create the needed `amount` gap, so we
  339. // revert its position to the original value
  340. bounds[handle] = originalValue;
  341. return false;
  342. }
  343. currentValue = bounds[handle];
  344. }
  345. // the handle was pushed enough to create the needed `amount` gap
  346. return true;
  347. }
  348. }, {
  349. key: 'pushHandleOnePoint',
  350. value: function pushHandleOnePoint(bounds, handle, direction) {
  351. var points = this.getPoints();
  352. var pointIndex = points.indexOf(bounds[handle]);
  353. var nextPointIndex = pointIndex + direction;
  354. if (nextPointIndex >= points.length || nextPointIndex < 0) {
  355. // reached the minimum or maximum available point, can't push anymore
  356. return false;
  357. }
  358. var nextHandle = handle + direction;
  359. var nextValue = points[nextPointIndex];
  360. var threshold = this.props.pushable;
  361. var diffToNext = direction * (bounds[nextHandle] - nextValue);
  362. if (!this.pushHandle(bounds, nextHandle, direction, threshold - diffToNext)) {
  363. // couldn't push next handle, so we won't push this one either
  364. return false;
  365. }
  366. // push the handle
  367. bounds[handle] = nextValue;
  368. return true;
  369. }
  370. }, {
  371. key: 'trimAlignValue',
  372. value: function trimAlignValue(value) {
  373. var _state2 = this.state,
  374. handle = _state2.handle,
  375. bounds = _state2.bounds;
  376. return _trimAlignValue({
  377. value: value,
  378. handle: handle,
  379. bounds: bounds,
  380. props: this.props
  381. });
  382. }
  383. }, {
  384. key: 'render',
  385. value: function render() {
  386. var _this4 = this;
  387. var _state3 = this.state,
  388. handle = _state3.handle,
  389. bounds = _state3.bounds;
  390. var _props4 = this.props,
  391. prefixCls = _props4.prefixCls,
  392. vertical = _props4.vertical,
  393. included = _props4.included,
  394. disabled = _props4.disabled,
  395. min = _props4.min,
  396. max = _props4.max,
  397. reverse = _props4.reverse,
  398. handleGenerator = _props4.handle,
  399. trackStyle = _props4.trackStyle,
  400. handleStyle = _props4.handleStyle,
  401. tabIndex = _props4.tabIndex;
  402. var offsets = bounds.map(function (v) {
  403. return _this4.calcOffset(v);
  404. });
  405. var handleClassName = prefixCls + '-handle';
  406. var handles = bounds.map(function (v, i) {
  407. var _classNames;
  408. var _tabIndex = tabIndex[i] || 0;
  409. if (disabled || tabIndex[i] === null) {
  410. _tabIndex = null;
  411. }
  412. return handleGenerator({
  413. className: (0, _classnames2['default'])((_classNames = {}, (0, _defineProperty3['default'])(_classNames, handleClassName, true), (0, _defineProperty3['default'])(_classNames, handleClassName + '-' + (i + 1), true), _classNames)),
  414. prefixCls: prefixCls,
  415. vertical: vertical,
  416. offset: offsets[i],
  417. value: v,
  418. dragging: handle === i,
  419. index: i,
  420. tabIndex: _tabIndex,
  421. min: min,
  422. max: max,
  423. reverse: reverse,
  424. disabled: disabled,
  425. style: handleStyle[i],
  426. ref: function ref(h) {
  427. return _this4.saveHandle(i, h);
  428. }
  429. });
  430. });
  431. var tracks = bounds.slice(0, -1).map(function (_, index) {
  432. var _classNames2;
  433. var i = index + 1;
  434. var trackClassName = (0, _classnames2['default'])((_classNames2 = {}, (0, _defineProperty3['default'])(_classNames2, prefixCls + '-track', true), (0, _defineProperty3['default'])(_classNames2, prefixCls + '-track-' + i, true), _classNames2));
  435. return _react2['default'].createElement(_Track2['default'], {
  436. className: trackClassName,
  437. vertical: vertical,
  438. reverse: reverse,
  439. included: included,
  440. offset: offsets[i - 1],
  441. length: offsets[i] - offsets[i - 1],
  442. style: trackStyle[index],
  443. key: i
  444. });
  445. });
  446. return { tracks: tracks, handles: handles };
  447. }
  448. }], [{
  449. key: 'getDerivedStateFromProps',
  450. value: function getDerivedStateFromProps(props, state) {
  451. if ('value' in props || 'min' in props || 'max' in props) {
  452. var value = props.value || state.bounds;
  453. var nextBounds = value.map(function (v, i) {
  454. return _trimAlignValue({
  455. value: v,
  456. handle: i,
  457. bounds: state.bounds,
  458. props: props
  459. });
  460. });
  461. if (nextBounds.length === state.bounds.length && nextBounds.every(function (v, i) {
  462. return v === state.bounds[i];
  463. })) {
  464. return null;
  465. }
  466. return (0, _extends3['default'])({}, state, {
  467. bounds: nextBounds
  468. });
  469. }
  470. return null;
  471. }
  472. }]);
  473. return Range;
  474. }(_react2['default'].Component);
  475. Range.displayName = 'Range';
  476. Range.propTypes = {
  477. autoFocus: _propTypes2['default'].bool,
  478. defaultValue: _propTypes2['default'].arrayOf(_propTypes2['default'].number),
  479. value: _propTypes2['default'].arrayOf(_propTypes2['default'].number),
  480. count: _propTypes2['default'].number,
  481. pushable: _propTypes2['default'].oneOfType([_propTypes2['default'].bool, _propTypes2['default'].number]),
  482. allowCross: _propTypes2['default'].bool,
  483. disabled: _propTypes2['default'].bool,
  484. reverse: _propTypes2['default'].bool,
  485. tabIndex: _propTypes2['default'].arrayOf(_propTypes2['default'].number),
  486. min: _propTypes2['default'].number,
  487. max: _propTypes2['default'].number
  488. };
  489. Range.defaultProps = {
  490. count: 1,
  491. allowCross: true,
  492. pushable: false,
  493. tabIndex: []
  494. };
  495. (0, _reactLifecyclesCompat.polyfill)(Range);
  496. exports['default'] = (0, _createSlider2['default'])(Range);
  497. module.exports = exports['default'];